examples/Base/SmpExample/src/SmpExample.cpp

00001 /*
00002 Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
00003 
00004 Redistribution and use in source and binary forms, with or without
00005 modification, are permitted provided that the following conditions are met:
00006 
00007 * Redistributions of source code must retain the above copyright notice, this
00008   list of conditions and the following disclaimer.
00009 * Redistributions in binary form must reproduce the above copyright notice,
00010   this list of conditions and the following disclaimer in the documentation
00011   and/or other materials provided with the distribution.
00012 * Neither the name of Nokia Corporation nor the names of its contributors
00013   may be used to endorse or promote products derived from this software
00014   without specific prior written permission.
00015 
00016 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00017 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00018 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
00020 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00021 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00022 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00023 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00024 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00025 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026 
00027 Description: 
00028 */
00029 
00030 #include <d32dbms.h>  //Used for RDbDatabase class. 
00031 #include "SmpExample.h"
00032 _LIT(KDatabase1, "C:\\DBforSMP1.db");
00033 _LIT(KDatabase2, "C:\\DBforSMP2.db");
00034 
00038 CSmpExample::~CSmpExample()
00039     {
00040     iReadThread.Close(); //Reader thread closed. 
00041     iWriteThread1.Close(); //Writer thread closed. 
00042     iWriteThread2.Close(); //Writer thread closed.
00043     delete iConsole;
00044     }
00045 
00049 CSmpExample* CSmpExample::NewL()
00050     {
00051     CSmpExample* self = new(ELeave)CSmpExample();
00052     CleanupStack::PushL(self);
00053     self->ConstructL();
00054     CleanupStack::Pop(self);
00055     return self;
00056     }
00057 
00061 void CSmpExample::ConstructL()
00062     { 
00063     CreateDatabaseL(KDatabase1);
00064     CreateDatabaseL(KDatabase2);
00065     
00066     _LIT(KTextConsoleTitle, "SmpExample");
00067     iConsole = Console::NewL(KTextConsoleTitle, TSize(KConsFullScreen, KConsFullScreen));  
00068 
00069     //Creates a reader thread to read the databases.
00070     _LIT(KReader, "ReaderThread");
00071     User::LeaveIfError(iReadThread.Create(KReader, ReadThreadFuncL, KDefaultStackSize, KMinHeapSize, 256*KMinHeapSize, this, EOwnerProcess));   
00072 
00073     //Creates a writer thread to write to the DBforSMP1.db database. 
00074     _LIT(KWriter1, "WriterThread1");
00075     User::LeaveIfError(iWriteThread1.Create(KWriter1, WriteThread1FuncL, KDefaultStackSize, KMinHeapSize, 256*KMinHeapSize, this, EOwnerProcess));    
00076     
00077     //Creates a writer thread to write to the DBforSMP2.db database. 
00078     _LIT(KWriter2, "WriterThread2");
00079     User::LeaveIfError(iWriteThread2.Create(KWriter2, WriteThread2FuncL, KDefaultStackSize, KMinHeapSize, 256*KMinHeapSize, this, EOwnerProcess));           
00080 
00081 
00082     //Sets priority to the threads. 
00083     iWriteThread1.SetPriority(EPriorityMuchLess);
00084     iWriteThread2.SetPriority(EPriorityMore);
00085     iReadThread.SetPriority(EPriorityNormal);
00086     }
00087 
00091 void CSmpExample::StartThreads()
00092     {   
00093     TRequestStatus writerThread1Status; 
00094     TRequestStatus readerThreadStatus; 
00095     TRequestStatus writerThread2Status; 
00096     
00097     _LIT(KTextPressKey, "\nPress any key to start writing to and reading from the database\n");
00098     iConsole->Printf(KTextPressKey);
00099     iConsole->Getch();
00100   
00101     //Requests a notification for the ReaderThread to terminate. 
00102     iReadThread.Logon(readerThreadStatus);
00103     iReadThread.Resume();
00104     
00105     //Requests a notification for the WriterThread1 to terminate. 
00106     iWriteThread1.Logon(writerThread1Status);   
00107     iWriteThread1.Resume();
00108     
00109     //Requests a notification for the WriterThread2 to terminate. 
00110     iWriteThread2.Logon(writerThread2Status);   
00111     iWriteThread2.Resume();
00112     
00113     //Control returns to the main thread when the all the threads terminate. 
00114     User::WaitForRequest(writerThread1Status);
00115     User::WaitForRequest(readerThreadStatus);
00116     User::WaitForRequest(writerThread2Status);
00117     }
00118 
00122 void CSmpExample::PrintMessage()
00123     {
00124     _LIT(KTextWelcome, "Welcome to the SmpExample.\n");
00125     _LIT(KTextPurposel1, "There are three threads running in the example: WriterThread1 has the lowest priority,\n");
00126     _LIT(KTextPurposel2, "ReaderThread has normal priority and WriterThread2 has maximum priority.\n");  
00127     _LIT(KTextPurposel3, "The two WriterThreads open two different databases and write some integers to them.\n");
00128     _LIT(KTextPurposel4, "ReaderThread reads the two databases and prints the output to the console.\n");
00129     
00130     _LIT(KTextPurposel5, "In a unicore environment, WriterThread1 will be scheduled to run last and would not have\n");
00131     _LIT(KTextPurposel6, "written to the database when ReaderThread starts reading the databases.\n");
00132     _LIT(KTextPurposel7, "But in an SMP environment, both the WriterThreads write to their respective databases simultaneously.\n");
00133     
00134     iConsole->Printf(KTextWelcome);
00135     iConsole->Printf(KTextPurposel1);
00136     iConsole->Printf(KTextPurposel2);
00137     iConsole->Printf(KTextPurposel3);
00138     iConsole->Printf(KTextPurposel4);
00139     iConsole->Printf(KTextPurposel5);
00140     iConsole->Printf(KTextPurposel6);
00141     iConsole->Printf(KTextPurposel7);
00142     }
00143 
00147 void CSmpExample::ReadDatabaseL(const TDesC& aDbName, CConsoleBase& console)
00148     { 
00149     //Creates a file server session object before any file system manipulation. 
00150     RFs fsSession;
00151     CleanupClosePushL(fsSession);
00152     fsSession.Connect();
00153     
00154     //Creates Rdbs object
00155     RDbs dbs;
00156     CleanupClosePushL(dbs); 
00157     dbs.Connect();
00158     
00159     //Opens the named database using the RDbs object
00160     RDbNamedDatabase database;
00161     CleanupClosePushL(database);
00162     User::LeaveIfError(database.Open(dbs, aDbName)); 
00163     
00164     //Locks the database.
00165     database.Begin();
00166     //Prepare an SQL query to read one row of numbers from the database. 
00167     _LIT(KSQLStatement, "Select Number1, Number2, Number3  from Numbers order by Number1, Number2, Number3");
00168     
00169     //Creates a view on the database to read it.
00170     RDbView view; 
00171     CleanupClosePushL(view);
00172     
00173     User::LeaveIfError(view.Prepare(database, TDbQuery(KSQLStatement, EDbCompareNormal)));
00174     User::LeaveIfError(view.EvaluateAll());
00175     
00176     _LIT(KTextReading, "Reading the database\t %S.\n");
00177     console.Printf(KTextReading, &aDbName);
00178     
00179     //Boolean variable to check whether the database is empty.
00180     TBool isDbEmpty= EFalse;
00181     //Iterates through the database till the last row is read. 
00182     for (view.FirstL(); view.AtRow(); view.NextL())
00183         {       
00184         view.GetL();
00185         TInt number1 = view.ColInt(1);
00186         TInt number2 = view.ColInt(2);
00187         TInt number3 = view.ColInt(3);
00188         //Prepare a row formatter to print numbers in the console. 
00189         _LIT(KRowFormatter, "Reading  %d \t%d\t%d\n");  
00190         //Reads the integers from the view and display them in the console.
00191         console.Printf(KRowFormatter, number1, number2, number3);
00192         isDbEmpty= ETrue;
00193         }
00194     
00195     if(isDbEmpty== EFalse)
00196         {
00197         _LIT(KTextDbEmpty, "Database is empty.\n\n");
00198         console.Printf(KTextDbEmpty);
00199         }
00200     else
00201         {
00202         _LIT(KTextAllRead, "All the numbers in the database have been read.\n\n");
00203         console.Printf(KTextAllRead);
00204         }            
00205     
00206     CleanupStack::PopAndDestroy(&view); 
00207     CleanupStack::PopAndDestroy(&database);  
00208     CleanupStack::PopAndDestroy(&dbs);    
00209     CleanupStack::PopAndDestroy(&fsSession);
00210     }
00211 
00215 void CSmpExample::ReadBothDatabasesL()
00216     {
00217     _LIT(KTextConsoleTitle, "ReaderThread");
00218     CConsoleBase* console= Console::NewL(KTextConsoleTitle, TSize(KConsFullScreen, KConsFullScreen)); 
00219     CleanupStack::PushL(console);
00220 
00221     //Reads DBforSMP1.db and prints the output to the console. 
00222     ReadDatabaseL(KDatabase1, *console);
00223     //Reads DBforSMP2.db and prints the output to the console.
00224     ReadDatabaseL(KDatabase2, *console);
00225     
00226     _LIT(KExit, "Press any key to exit\n");
00227     console->Printf(KExit);
00228     console->Getch();
00229     CleanupStack::PopAndDestroy(console);    
00230     }
00231 
00236 TInt CSmpExample::ReadThreadFuncL(TAny* /*aPtr*/)
00237     {
00238     __UHEAP_MARK;
00239     //Creates cleanup stack.
00240     CTrapCleanup* cleanup = CTrapCleanup::New();
00241     if(!cleanup)
00242         {
00243         return KErrNoMemory;
00244         }
00245      
00246     TRAPD(error, ReadBothDatabasesL()); 
00247     if(error != KErrNone)
00248         {
00249         _LIT(KUserPanic, "DB Read Failed");  
00250         User::Panic(KUserPanic, error);
00251         }
00252     delete cleanup;
00253     __UHEAP_MARKEND;
00254     return KErrNone;
00255     }
00256 
00261 void CSmpExample::WriteDbFuncL(const TDesC& aDbName, TInt aNum)
00262     {
00263     //Creates a file server session object before any file system manipulation. 
00264     RFs fsSession;
00265     CleanupClosePushL(fsSession);
00266     fsSession.Connect();
00267 
00268 
00269     //Creates Rdbs object   
00270     RDbs dbs;
00271     CleanupClosePushL(dbs);
00272     dbs.Connect();
00273     
00274     //Opens the database using the RDbs object
00275     RDbNamedDatabase database;
00276     CleanupClosePushL(database);
00277     User::LeaveIfError(database.Open(dbs, aDbName)); 
00278     
00279     //Locks the database.
00280     database.Begin();
00281     
00282     //Creates a view on the database. 
00283     RDbView view;
00284     CleanupClosePushL(view);
00285     _LIT(KSQLStatement, "Select Number1, Number2, Number3 from Numbers order by Number1, Number2, Number3");
00286     User::LeaveIfError(view.Prepare(database, TDbQuery(KSQLStatement, EDbCompareNormal)));
00287     User::LeaveIfError(view.EvaluateAll());
00288 
00289     for(int i=0; i<5; i++)
00290         {
00291         //Inserts a new row at the end of the database. 
00292         view.InsertL();
00293         //Fills three columns with numbers.
00294         view.SetColL(1, aNum++);
00295         view.SetColL(2, aNum++);
00296         view.SetColL(3, aNum++);
00297         view.PutL();
00298         }
00299 
00300     CleanupStack::PopAndDestroy(&view);       
00301     //Commits the database and unlocks it. 
00302     database.Commit();
00303     CleanupStack::PopAndDestroy(&database);  
00304     CleanupStack::PopAndDestroy(&dbs);   
00305     CleanupStack::PopAndDestroy(&fsSession);
00306     }
00307 
00308 
00313 TInt CSmpExample::WriteThread2FuncL(TAny* /*aPtr*/)
00314     {
00315     __UHEAP_MARK;
00316     //Creates cleanup stack.
00317     CTrapCleanup* cleanup = CTrapCleanup::New();
00318     if(!cleanup)
00319         {
00320         return KErrNoMemory;
00321         }
00322     
00323     //First number to be written to the database. 
00324     const int KFirstNumforDb2 = 500; 
00325     TRAPD(err, WriteDbFuncL(KDatabase2, KFirstNumforDb2));
00326     if(err != KErrNone)
00327         {
00328         _LIT(KUserPanic, "DB Write Failed");  
00329         User::Panic(KUserPanic, err);
00330         }
00331     delete cleanup;
00332     __UHEAP_MARKEND;
00333     return KErrNone;
00334     }
00335 
00340 TInt CSmpExample::WriteThread1FuncL(TAny* /*aPtr*/)
00341     {
00342     __UHEAP_MARK;
00343     //Creates cleanup stack.
00344     CTrapCleanup* cleanup = CTrapCleanup::New();
00345     if(!cleanup)
00346         {
00347         return KErrNoMemory;
00348         }
00349 
00350     //First number to be written to the database. 
00351     const int KFirstNumforDb1 = 0; 
00352     TRAPD(err, WriteDbFuncL(KDatabase1, KFirstNumforDb1));
00353     if(err != KErrNone)
00354         {
00355         _LIT(KUserPanic, "DB Write Failed");  
00356         User::Panic(KUserPanic, err);
00357         }
00358     delete cleanup;
00359     __UHEAP_MARKEND;
00360     return KErrNone;
00361     }
00362 
00367 void CSmpExample::CreateDatabaseL(const TDesC& aDbName)
00368     {
00369     //Creates a file server session object before any file system manipulation. 
00370     RFs fsSession;
00371     CleanupClosePushL(fsSession);
00372     fsSession.Connect();
00373 
00374     //Creates Rdbs object
00375     RDbs dbs;
00376     CleanupClosePushL(dbs); 
00377     dbs.Connect();
00378     
00379     //Creates a new database with the name specified in the parameter aDbName, 
00380     //if database with same name is present, it will be replaced.    
00381     RDbNamedDatabase database;
00382     CleanupClosePushL(database);  
00383     User::LeaveIfError(database.Replace(fsSession, aDbName)); 
00384     database.Close(); 
00385     
00386     //Opens the database using the RDbs object
00387     User::LeaveIfError(database.Open(dbs, aDbName));       
00388     //Creates a table definition.
00389     CDbColSet* columns=CDbColSet::NewLC();
00390 
00391     //Adds three columns each containing Int32 values. 
00392     _LIT(KCol1, "Number1");
00393     _LIT(KCol2, "Number2");
00394     _LIT(KCol3, "Number3");   
00395     columns->AddL(TDbCol(KCol1, EDbColInt32));
00396     columns->AddL(TDbCol(KCol2, EDbColInt32));
00397     columns->AddL(TDbCol(KCol3, EDbColInt32));
00398  
00399 
00400      //Creates the table, table name is "Numbers" and add the columns to it.
00401     _LIT(KTable, "Numbers");
00402     User::LeaveIfError(database.CreateTable(KTable, *columns));
00403     
00404     CDbKey* key=CDbKey::NewLC();
00405 
00406      //Add the key columns.
00407      TDbKeyCol number1(KCol1);
00408      key->AddL(number1);
00409      TDbKeyCol number2(KCol2);
00410      key->AddL(number2);
00411      TDbKeyCol number3(KCol3);
00412      key->AddL(number3);
00413     User::LeaveIfError(database.CreateIndex(KTable, KTable, *key));
00414     
00415     //Cleans up the column set.  
00416     CleanupStack::PopAndDestroy(key);
00417     CleanupStack::PopAndDestroy(columns);  
00418     CleanupStack::PopAndDestroy(&database);  
00419     CleanupStack::PopAndDestroy(&dbs);   
00420     CleanupStack::PopAndDestroy(&fsSession);
00421     }
00422 
00427 static void MainL()
00428     {
00429     CSmpExample* smpExample = CSmpExample::NewL();
00430     CleanupStack::PushL(smpExample);    
00431     smpExample->PrintMessage();
00432     smpExample->StartThreads();
00433     CleanupStack::PopAndDestroy(smpExample);
00434     }
00435 
00439 extern TInt E32Main()
00440     {
00441     //Creates cleanup stack.
00442     __UHEAP_MARK;
00443     CTrapCleanup* cleanup = CTrapCleanup::New();
00444     if(!cleanup)
00445         {
00446         return KErrNoMemory;
00447         }
00448     //Run application code inside a TRAP harness.
00449     TRAPD(mainError, MainL());
00450     if(mainError != KErrNone)
00451         {
00452         _LIT(KUserPanic, "Main Failed");  
00453         User::Panic(KUserPanic, mainError);
00454         }
00455     delete cleanup;
00456     __UHEAP_MARKEND;
00457     return KErrNone;
00458     }
00459 

Generated by  doxygen 1.6.2