|
1 // Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32test\mmu\t_alias_remove.cpp |
|
15 // Overview: |
|
16 // Test interactions when free memory being aliases. |
|
17 // Details: |
|
18 // Create 3 mappings to one chunk one that owns the chunk, one to map it again another process |
|
19 // and another alias mapping. |
|
20 // Then while the alias mapping is accessing the chunk close the second mapping. |
|
21 // Platforms/Drives/Compatibility: |
|
22 // All. |
|
23 // Assumptions/Requirement/Pre-requisites: |
|
24 // Failures and causes: |
|
25 // Base Port information: |
|
26 // |
|
27 // |
|
28 |
|
29 #define __E32TEST_EXTENSION__ |
|
30 #include <e32test.h> |
|
31 #include <e32hal.h> |
|
32 #include <e32svr.h> |
|
33 #include "..\defrag\d_pagemove.h" |
|
34 |
|
35 const TPtrC KAliasProcessName = _L("T_ALIAS_REMOVE"); |
|
36 const TPtrC KAliasChunkName = _L("AliasChunk"); |
|
37 const TPtrC KAliasServerName = _L("AliasServer"); |
|
38 const TPtrC KMasterServerName = _L("MasterServer"); |
|
39 |
|
40 RBuf ChunkName; |
|
41 RBuf MasterServerName; |
|
42 RBuf AliasServerName; |
|
43 |
|
44 RTest test(KAliasProcessName); |
|
45 |
|
46 //#define ENABLE_PRINTFS |
|
47 #ifndef __MSVC6__ // VC6 can't cope with variable arguments in macros. |
|
48 |
|
49 #define T_PRINTF(x...) test.Printf(x) |
|
50 #define D_PRINTF(x...) RDebug::Printf(x) |
|
51 #ifdef ENABLE_PRINTFS |
|
52 #define PRINTF(x) x |
|
53 #else |
|
54 #define PRINTF(x) |
|
55 #endif // ENABLE_PRINTFS |
|
56 |
|
57 #else |
|
58 #define PRINTF(x) |
|
59 #endif // __MSCV6__ |
|
60 |
|
61 enum TSlaveMsgType |
|
62 { |
|
63 ESlaveConnect = -1, |
|
64 ESlaveDisconnect = -2, |
|
65 ESlaveReadChunk = 0, |
|
66 ESlaveClosedChunk = 1, |
|
67 }; |
|
68 |
|
69 |
|
70 struct SThreadData |
|
71 { |
|
72 TUint8 iFillValue; |
|
73 TUint iChunkSize; |
|
74 RThread* iMasterThread; |
|
75 TUint iProcessId; |
|
76 }; |
|
77 |
|
78 |
|
79 class RAliasSession : public RSessionBase |
|
80 { |
|
81 public: |
|
82 TInt CreateSession(const TDesC& aServerName, TInt aMsgSlots) |
|
83 { |
|
84 return RSessionBase::CreateSession(aServerName,User::Version(),aMsgSlots); |
|
85 } |
|
86 TInt PublicSendReceive(TInt aFunction, const TIpcArgs &aPtr) |
|
87 { |
|
88 return (SendReceive(aFunction, aPtr)); |
|
89 } |
|
90 TInt PublicSend(TInt aFunction, const TIpcArgs &aPtr) |
|
91 { |
|
92 return (Send(aFunction, aPtr)); |
|
93 } |
|
94 }; |
|
95 |
|
96 |
|
97 TInt SlaveProcess(TUint aProcessId, TUint aFillValue) |
|
98 { |
|
99 // Connect to the master server to indicate that we're ready to receive ipc messages. |
|
100 RAliasSession masterSession; |
|
101 test_KErrNone(masterSession.CreateSession(MasterServerName, 1)); |
|
102 |
|
103 PRINTF(T_PRINTF(_L("Process ID %d Slave open chunk\n"), aProcessId)); |
|
104 // Open the global chunk. |
|
105 RChunk chunk; |
|
106 TInt r = chunk.OpenGlobal(ChunkName, ETrue); |
|
107 test_KErrNone(r); |
|
108 |
|
109 // Connect to alias server. |
|
110 PRINTF(T_PRINTF(_L("Process ID %d Slave connect to alias server\n"), aProcessId)); |
|
111 RAliasSession aliasSession; |
|
112 test_KErrNone(aliasSession.CreateSession(AliasServerName, 1)); |
|
113 |
|
114 PRINTF(T_PRINTF(_L("Process ID %d Slave send data to alias server\n"), aProcessId)); |
|
115 TPtr8 arg0(chunk.Base(), chunk.Size(), chunk.Size()); |
|
116 r = aliasSession.PublicSend(ESlaveReadChunk, TIpcArgs(&arg0)); |
|
117 test_KErrNone(r); |
|
118 |
|
119 // Close the chunk removing its mapping before the server has read it. |
|
120 chunk.Close(); |
|
121 PRINTF(T_PRINTF(_L("Process ID %d Slave closed chunk\n"), aProcessId)); |
|
122 |
|
123 r = masterSession.PublicSendReceive(ESlaveClosedChunk, TIpcArgs()); |
|
124 test_KErrNone(r); |
|
125 aliasSession.Close(); |
|
126 masterSession.Close(); |
|
127 return KErrNone; |
|
128 } |
|
129 |
|
130 |
|
131 TInt ChunkReadThread(TAny* aThreadData) |
|
132 { |
|
133 SThreadData* threadData = (SThreadData*)aThreadData; |
|
134 RServer2 aliasServer; |
|
135 TInt r = aliasServer.CreateGlobal(AliasServerName); |
|
136 if (r != KErrNone) |
|
137 { |
|
138 RDebug::Printf("Process ID %d Error creating alias server r=%d", threadData->iProcessId, r); |
|
139 return r; |
|
140 } |
|
141 // Connect to the master server to indicate that we're ready to receive ipc messages. |
|
142 RAliasSession masterSession; |
|
143 test_KErrNone(masterSession.CreateSession(MasterServerName, 1)); |
|
144 |
|
145 PRINTF(D_PRINTF("Process ID %d Alias wait for slave connection", threadData->iProcessId)); |
|
146 RMessage2 aliasMessage; |
|
147 // Read and complete the connect message from the slave. |
|
148 aliasServer.Receive(aliasMessage); |
|
149 test_Equal(ESlaveConnect, aliasMessage.Function()); |
|
150 aliasMessage.Complete(KErrNone); |
|
151 |
|
152 // Read the data of the remote chunk. |
|
153 PRINTF(D_PRINTF("Process ID %d Alias read chunk data", threadData->iProcessId)); |
|
154 HBufC8* argTmp = HBufC8::New(threadData->iChunkSize); |
|
155 test_NotNull(argTmp); |
|
156 RBuf8 argBuf(argTmp); |
|
157 aliasServer.Receive(aliasMessage); |
|
158 test_Equal(ESlaveReadChunk, aliasMessage.Function()); |
|
159 r = aliasMessage.Read(0, argBuf); |
|
160 if (r == KErrNone) |
|
161 {// Successfully read the chunk so verify it. |
|
162 aliasMessage.Complete(KErrNone); |
|
163 |
|
164 PRINTF(D_PRINTF("Process ID %d Alias verify chunk data", threadData->iProcessId)); |
|
165 const TUint8* bufPtr = argBuf.Ptr(); |
|
166 const TUint8* bufEnd = bufPtr + threadData->iChunkSize; |
|
167 for (; bufPtr < bufEnd; bufPtr++) |
|
168 { |
|
169 if (*bufPtr != threadData->iFillValue) |
|
170 { |
|
171 RDebug::Printf("Process ID %d Read incorrect data exp 0x%x got 0x%x", |
|
172 threadData->iProcessId, threadData->iFillValue, *bufPtr); |
|
173 r = *bufPtr; |
|
174 break; |
|
175 } |
|
176 } |
|
177 } |
|
178 else |
|
179 { |
|
180 PRINTF(D_PRINTF("Process ID %d Error reading chunk remotely %d", threadData->iProcessId, r)); |
|
181 } |
|
182 argBuf.Close(); |
|
183 masterSession.Close(); |
|
184 return r; |
|
185 } |
|
186 |
|
187 |
|
188 TInt MasterProcess(TInt aProcessId) |
|
189 { |
|
190 TInt pageSize; |
|
191 UserHal::PageSizeInBytes(pageSize); |
|
192 // Need a large chunk so that alias that reads it is held for a long |
|
193 // enough period for there to be conflicts with the chunk closure in |
|
194 // the slave process. |
|
195 const TUint KChunkSize = pageSize * 1024; |
|
196 |
|
197 PRINTF(T_PRINTF(_L("Process ID %d Create chunk\n"), aProcessId)); |
|
198 RChunk chunk; |
|
199 TInt r = chunk.CreateGlobal(ChunkName, KChunkSize, KChunkSize); |
|
200 test_KErrNone(r); |
|
201 |
|
202 |
|
203 for (TUint8 fillValue = 1; fillValue < 255; fillValue++) |
|
204 { |
|
205 // Output a character every 16 iterations so test machines |
|
206 // don't time out. |
|
207 if ((fillValue & 0xf) == 1) |
|
208 test.Printf(_L(".")); |
|
209 |
|
210 PRINTF(T_PRINTF(_L("Process ID %d start slave fill value %d\n"), aProcessId, fillValue)); |
|
211 RServer2 masterServer; |
|
212 r = masterServer.CreateGlobal(MasterServerName); |
|
213 test_KErrNone(r); |
|
214 RMessage2 masterMessage; |
|
215 |
|
216 // Update the chunk to new fill value. |
|
217 memset(chunk.Base(), fillValue, KChunkSize); |
|
218 |
|
219 PRINTF(T_PRINTF(_L("Process ID %d Start the slave process\n"), aProcessId)); |
|
220 RProcess slaveProcess; |
|
221 test_KErrNone(slaveProcess.Create(KAliasProcessName, KNullDesC)); |
|
222 test_KErrNone(slaveProcess.SetParameter(1, aProcessId)); |
|
223 test_KErrNone(slaveProcess.SetParameter(2, fillValue)); |
|
224 TRequestStatus slaveStatus; |
|
225 slaveProcess.Logon(slaveStatus); |
|
226 test_Equal(KRequestPending, slaveStatus.Int()); |
|
227 slaveProcess.Resume(); |
|
228 |
|
229 // Wait for the connect message from the slave process. |
|
230 masterServer.Receive(masterMessage); |
|
231 test_Equal(ESlaveConnect, masterMessage.Function()); |
|
232 |
|
233 SThreadData threadData; |
|
234 threadData.iFillValue = fillValue; |
|
235 threadData.iChunkSize = KChunkSize; |
|
236 threadData.iProcessId = aProcessId; |
|
237 RThread readThread; |
|
238 r = readThread.Create(KNullDesC, ChunkReadThread, 10 * pageSize, KChunkSize, KChunkSize * 2, &threadData); |
|
239 test_KErrNone(r); |
|
240 TRequestStatus threadStatus; |
|
241 readThread.Logon(threadStatus); |
|
242 test_Equal(KRequestPending, threadStatus.Int()); |
|
243 readThread.Resume(); |
|
244 |
|
245 PRINTF(T_PRINTF(_L("Process ID %d Wait for alias thread to start server\n"), aProcessId)); |
|
246 RMessage2 aliasMessage; |
|
247 masterServer.Receive(aliasMessage); |
|
248 test_Equal(ESlaveConnect, aliasMessage.Function()); |
|
249 aliasMessage.Complete(KErrNone); |
|
250 |
|
251 // Signal to the slave process to send chunk to alias thread. |
|
252 PRINTF(T_PRINTF(_L("Process ID %d Signal to slave to send chunk to alias\n"), aProcessId)); |
|
253 masterMessage.Complete(KErrNone); |
|
254 |
|
255 // Wait for slave to close the chunk and fill it with new value. |
|
256 for (;;) |
|
257 { |
|
258 masterServer.Receive(masterMessage); |
|
259 TInt func = masterMessage.Function(); |
|
260 PRINTF(T_PRINTF(_L("Process ID %d rxd %d\n"), aProcessId, func)); |
|
261 if (func == ESlaveClosedChunk) |
|
262 {// Slave closed the chunk. |
|
263 memset(chunk.Base(), ++fillValue, KChunkSize); |
|
264 break; |
|
265 } |
|
266 else |
|
267 {// Alias has read the chunk and completed. |
|
268 test_Equal(ESlaveDisconnect, func); |
|
269 } |
|
270 } |
|
271 |
|
272 PRINTF(T_PRINTF(_L("Process ID %d Wait for alias to complete\n"), aProcessId)); |
|
273 masterMessage.Complete(KErrNone); |
|
274 User::WaitForRequest(threadStatus); |
|
275 TInt statusInt = threadStatus.Int(); |
|
276 test_Value( statusInt, |
|
277 statusInt == KErrNone || |
|
278 statusInt == KErrBadDescriptor || |
|
279 statusInt == KErrDied); |
|
280 test_Equal(EExitKill, readThread.ExitType()); |
|
281 readThread.Close(); |
|
282 |
|
283 PRINTF(T_PRINTF(_L("Process ID %d Wait for slave to complete\n"), aProcessId)); |
|
284 User::WaitForRequest(slaveStatus); |
|
285 test_Equal(EExitKill, slaveProcess.ExitType()); |
|
286 test_Equal(KErrNone, slaveProcess.ExitReason()); |
|
287 slaveProcess.Close(); |
|
288 masterServer.Close(); |
|
289 } |
|
290 |
|
291 chunk.Close(); |
|
292 |
|
293 return 0; |
|
294 } |
|
295 |
|
296 |
|
297 GLDEF_C TInt E32Main() |
|
298 { |
|
299 TInt processId; |
|
300 if(User::GetTIntParameter(1, processId)==KErrNone) |
|
301 { |
|
302 test_KErrNone(ChunkName.Create(KAliasChunkName.Length() + 3)); |
|
303 ChunkName.Copy(KAliasChunkName); |
|
304 ChunkName.AppendNum(processId); |
|
305 |
|
306 test_KErrNone(MasterServerName.Create(KMasterServerName.Length() + 3)); |
|
307 MasterServerName.Copy(KMasterServerName); |
|
308 MasterServerName.AppendNum(processId); |
|
309 |
|
310 test_KErrNone(AliasServerName.Create(KAliasServerName.Length() + 3)); |
|
311 AliasServerName.Copy(KAliasServerName); |
|
312 AliasServerName.AppendNum(processId); |
|
313 |
|
314 TInt fillValue; |
|
315 if(User::GetTIntParameter(2, fillValue)==KErrNone) |
|
316 { |
|
317 return SlaveProcess(processId, fillValue); |
|
318 } |
|
319 return MasterProcess(processId); |
|
320 } |
|
321 |
|
322 // Get the number of cpus and use it to determine how many processes to execute. |
|
323 RPageMove pagemove; |
|
324 test_KErrNone(pagemove.Open()); |
|
325 TUint masterProcesses = pagemove.NumberOfCpus() + 1; |
|
326 pagemove.Close(); |
|
327 |
|
328 TInt cmdLineLen = User::CommandLineLength(); |
|
329 if(cmdLineLen) |
|
330 { |
|
331 RBuf cmdLine; |
|
332 test_KErrNone(cmdLine.Create(cmdLineLen)); |
|
333 User::CommandLine(cmdLine); |
|
334 test_KErrNone(TLex(cmdLine).Val(masterProcesses)); |
|
335 } |
|
336 |
|
337 test.Title(); |
|
338 test.Start(_L("")); |
|
339 test.Printf(_L("Create %d processes for accessing aliases being removed\n"), masterProcesses); |
|
340 |
|
341 TUint32 debugMask = UserSvr::DebugMask(); |
|
342 User::SetDebugMask(0); |
|
343 |
|
344 // Start master processes to alias memory between each other. |
|
345 RProcess* masters = new RProcess[masterProcesses]; |
|
346 TRequestStatus* masterStatus = new TRequestStatus[masterProcesses]; |
|
347 TUint i = 0; |
|
348 for (; i < masterProcesses; i++) |
|
349 { |
|
350 test_KErrNone(masters[i].Create(KAliasProcessName, KNullDesC)); |
|
351 test_KErrNone(masters[i].SetParameter(1, i)); |
|
352 masters[i].Logon(masterStatus[i]); |
|
353 test_Equal(KRequestPending, masterStatus[i].Int()); |
|
354 } |
|
355 test.Next(_L("Resume the processes")); |
|
356 for (i = 0; i < masterProcesses; i++) |
|
357 { |
|
358 masters[i].Resume(); |
|
359 } |
|
360 |
|
361 test.Next(_L("Wait for processes to exit")); |
|
362 for (i = 0; i < masterProcesses; i++) |
|
363 { |
|
364 User::WaitForRequest(masterStatus[i]); |
|
365 test_Equal(EExitKill, masters[i].ExitType()); |
|
366 test_Equal(KErrNone, masters[i].ExitReason()); |
|
367 } |
|
368 User::SetDebugMask(debugMask); |
|
369 delete masterStatus; |
|
370 delete masters; |
|
371 test.Printf(_L("\n")); |
|
372 test.End(); |
|
373 return KErrNone; |
|
374 } |