summaryrefslogtreecommitdiffstats
path: root/plugins/contacts/symbian/contactsmodel/tsrc/t_concurrent.cpp
blob: 5b8de7c4452b2c611c3ffa1a0a4732c69b307a8a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
/*
* Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
* Contact: http://www.qt-project.org/legal
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/

#include "t_concurrent.h"
#include <e32base.h>
#include <e32std.h>
#include <e32cons.h>            
#include <cntdb.h>
#include <cntdbobs.h>
#include <cntitem.h>
#include <cntfield.h>
#include <cntfldst.h>


//  Constants
_LIT(KThreadTitle, "Thread2");
_LIT(KTextFailed, " failed, leave code = %d");

// Global Variables
RTest MainTest(_L("Concurrent test"));	// Main RTest
CContactDatabase * database = NULL;		// Shared database.
RSemaphore sem;							// Synchronising Semaphore
TInt t1MachineId = 0;					// Thread1 machineId from db.
TInt currentStep = 0;					// Current test step.

///////////////////////////////////////////////////////////
//                  CHILD THREAD FUNCTIONS.
///////////////////////////////////////////////////////////

/**
* The main function called when the child thread is invoked.
*/
TInt RunChildThread(TAny * /* ptr */)
	{
    // Create cleanup stack
    __UHEAP_MARK;
    CTrapCleanup* cleanup = CTrapCleanup::New();
    
    // Create active scheduler (to run active objects)
    CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
    CActiveScheduler::Install(scheduler);
    CChildThread* childThread = NULL;
    
    TInt err;
    TRAP(err, childThread = CChildThread::NewL());
	if (err == KErrNone)
		{
		TRAP(err, childThread->AccessDBTestL() );
		}
    
	if (err != KErrNone)
    	MainTest.Printf( _L(" Child thread test returned with error = %d"),  err);

	delete childThread;
    delete cleanup;
    delete scheduler;
	__UHEAP_MARKEND;
    return KErrNone;	
	}

/**
* The child thread accesses the shared db session.
* A basic operation like getting the count of contacts is performed.
*/
CChildThread * CChildThread::NewL()
	{
	CChildThread * self = new(ELeave) CChildThread;
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

void CChildThread::ConstructL()
	{
	TBuf<100> threadName;
	threadName.Format(_L("Child Thread"));
	iTest = new(ELeave) RTest(threadName);
	}

CChildThread::~CChildThread()
	{
	iTest->Close();
	delete iTest;
	iTest = NULL;
	}
	

/**
* This function tries to access the db and check the count, or perform some other action
* on the db. The session object is shared with the main thread .
*/
void CChildThread::AccessDBTestL()
	{
    
    while(currentStep != ETestsEnd)
    	{
	    TInt t2MachineId = database->MachineId();
	    TInt count = database->CountL();
	    iTest->Printf( _L("Thread2: Contact Count = %d"), count  );
	    
	    // Check that the child thread is accessing the shared db session correctly.
	    MainTest(count==1);
	    MainTest( t2MachineId == t1MachineId );
	    
	    sem.Signal();
	    RThread().Suspend();
	    }
	   
	// Child thread is now over.  
	sem.Signal();  
	    
	}


///////////////////////////////////////////////////////////
//                  MAIN THREAD FUNCTIONS.
///////////////////////////////////////////////////////////
/**
* The main thread object which owns the session with the database in thread shared mode.
*/
CMainThread * CMainThread::NewL()
	{
	CMainThread * self = new (ELeave) CMainThread;
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop();
	return self;
	}
	
void CMainThread::ConstructL()
	{
	TBuf<100> threadName;
	threadName.Format(_L("Main Thread"));
	iTest = new(ELeave) RTest(threadName);
	}
	
CMainThread::~CMainThread()
	{
	TRAP_IGNORE(CloseDatabaseSessionL() );
	iTest->Close();
	delete iTest;
	iTest = NULL;
	iChildThread.Close();
	}
	
/** 
* The function to empty the database and close the database session.
*/
void CMainThread::CloseDatabaseSessionL()
	{
		TestDeleteContactL();
		delete database;
		database = NULL;
	}

/**
* Create the database in shared mode.
*/
void CMainThread::TestCreateDatabaseL()
	{
	// Creat the database in the first thread.
    iTest->Next( _L("CreateDatabaseL :Test creating the db in multi - thread mode.") );
    TRAP_IGNORE(CContactDatabase::DeleteDefaultFileL());
    database = CContactDatabase::CreateL( CContactDatabase::EMultiThread );
    t1MachineId = database->MachineId();
	}

/**
* Open the database in shared mode.
*/
void CMainThread::TestOpenDatabaseL()
	{
	// Open the database in the first thread.
    iTest->Next( _L("OpenDatabaseL :Test Opening the db in multi - thread mode.") );
    database = CContactDatabase::OpenL( CContactDatabase::EMultiThread );
    t1MachineId = database->MachineId();
	}

/**
* Replace the database in shared mode.
*/
void CMainThread::TestReplaceDatabaseL()
	{
    // Replace the database in the first thread, in mutithread mode.
    iTest->Next( _L("ReplaceDatabaseL :Test Replacing the db in multi - thread mode.") );
    database = CContactDatabase::ReplaceL( CContactDatabase::EMultiThread );
    t1MachineId = database->MachineId();
	}

/**
* Add one contact to the database.
*/
void CMainThread::TestAddContactL()
	{
    
    // Add a contact 
	_LIT(KForename,"Jo"); 
	_LIT(KSurname,"Stichbury"); 

	// Create a  contact card to contain the data
	CContactCard* newCard = CContactCard::NewLC();
    
	// Create the firstName field and add the data to it
	CContactItemField* firstName = CContactItemField::NewLC(KStorageTypeText, KUidContactFieldGivenName);
	firstName->TextStorage()->SetTextL(KForename);
	newCard->AddFieldL(*firstName);
  	CleanupStack::Pop(firstName);
  	
	// Create the lastName field and add the data to it
   	CContactItemField* lastName= CContactItemField::NewLC(KStorageTypeText, KUidContactFieldFamilyName);
  	lastName ->TextStorage()->SetTextL(KSurname);
  	newCard->AddFieldL(*lastName);
   	CleanupStack::Pop(lastName);
   		    
	// Add newCard to the database
	iContactId = database->AddNewContactL(*newCard);
	CleanupStack::PopAndDestroy(newCard);
	
	iTest->Printf( _L("Thread1: Added 1 contact to the database."));
	}

/**
* Delete the contact from the database.
*/
void CMainThread::TestDeleteContactL()
	{
	// Check if a contact has been stored in the db and delete it.
	if (iContactId)
		{
		database->DeleteContactL(iContactId);
		iContactId = 0;
		}
	}

/**
* The main thread controls the child thread
*/
void CMainThread::LaunchChildThreadL()
	{
	
    TRAPD(err,iChildThread.Create(KThreadTitle, RunChildThread, KDefaultStackSize, NULL, NULL, EOwnerProcess));
    
    if(err != KErrNone)
		{
		iTest->Printf(_L("Failed to create the child thread, error code=%d"), err);
		User::Leave(err);
		}
	}

/**
* Resume the child thread.
*/	

void CMainThread::ResumeChildThreadL()
	{
    iChildThread.Resume();
	}


///////////////////////////////////////////////////////////
//                  MAIN FUNCTIONS.
///////////////////////////////////////////////////////////

/**
* The main function which creates the main thread controller object 
* and invokes all the tests.
*/

/**

@SYMTestCaseID     PIM-T-CONCURRENT-0001

*/

LOCAL_C void DoTestsL()
    {
    
    // Initialisation
    MainTest.Start(_L("@SYMTESTCaseID:PIM-T-CONCURRENT-0001 T_Concurrent"));

    
    // Create active scheduler (to run active objects)
    CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
    CleanupStack::PushL(scheduler);
    CActiveScheduler::Install(scheduler);

    // Create main thread object, child thread and synchnising semaphore.
    sem.CreateLocal(0);
    CMainThread * ptr = CMainThread::NewL();
    CleanupStack::PushL(ptr);
    ptr->LaunchChildThreadL();
	
	// Run all the tests
	while (currentStep <= ETestsEnd)
		{
		switch(currentStep)
			{
			case ETestCreate:
				// create the db in shared mode and add a contact. 
			    ptr->TestCreateDatabaseL();
			    ptr->TestAddContactL();
				break;
			case ETestOpen:
			 	// create the db in shared mode 
			    ptr->TestOpenDatabaseL();
			    ptr->TestAddContactL();
				break;
			case ETestReplace:
				// create the db in shared mode 
			    ptr->TestReplaceDatabaseL();
				ptr->TestAddContactL();
				break;
			case ETestsEnd:
				break;
			default:
				break;
			} // end of switch
			
			// Run the child thread and let it access the shared session.
		    ptr->ResumeChildThreadL();
		    sem.Wait();
		    ptr->CloseDatabaseSessionL();
		    currentStep++ ;
		} // end of while

    // Cleanup and close.
    sem.Close();
    CleanupStack::PopAndDestroy(ptr);
    CleanupStack::PopAndDestroy(scheduler);
    }


/**
*  Entry point function.
*/
GLDEF_C TInt E32Main()
    {
    // Create cleanup stack
    __UHEAP_MARK;
    CTrapCleanup* cleanup = CTrapCleanup::New();
	
    TRAPD(mainError, DoTestsL());
    if (mainError)
        MainTest.Printf(KTextFailed, mainError);
    
    MainTest.End();
    MainTest.Close();
    delete cleanup;
    
    __UHEAP_MARKEND;
    return KErrNone;
    }