|
1 // Copyright (c) 2007-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 "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 // |
|
15 |
|
16 #include <kernel/kern_priv.h> |
|
17 #include "d_sharedchunk.h" |
|
18 |
|
19 static TInt ChunkDestroyedCount=1; // Test counter |
|
20 |
|
21 // |
|
22 // Class definitions |
|
23 // |
|
24 |
|
25 class DSharedChunkFactory : public DLogicalDevice |
|
26 { |
|
27 public: |
|
28 ~DSharedChunkFactory(); |
|
29 virtual TInt Install(); |
|
30 virtual void GetCaps(TDes8& aDes) const; |
|
31 virtual TInt Create(DLogicalChannelBase*& aChannel); |
|
32 void LockWait(); |
|
33 void LockSignal(); |
|
34 private: |
|
35 NFastMutex iLock; |
|
36 }; |
|
37 |
|
38 class DSharedChunkChannel : public DLogicalChannelBase |
|
39 { |
|
40 public: |
|
41 DSharedChunkChannel(); |
|
42 ~DSharedChunkChannel(); |
|
43 virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); |
|
44 virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2); |
|
45 DChunk* OpenChunk(TLinAddr* aKernelAddr=0, TInt* aMaxSize=0); |
|
46 inline void LockWait() |
|
47 { iFactory->LockWait(); } |
|
48 inline void LockSignal() |
|
49 { iFactory->LockSignal(); } |
|
50 public: |
|
51 DSharedChunkFactory* iFactory; |
|
52 DChunk* iChunk; |
|
53 TLinAddr iKernelAddress; |
|
54 TInt iMaxSize; |
|
55 |
|
56 public: |
|
57 /** Require physically contiguous memory */ |
|
58 TInt iContiguous; |
|
59 /** Caching attribute to create chunks memory */ |
|
60 TInt iCacheAttrib; |
|
61 }; |
|
62 |
|
63 class TChunkCleanup : public TDfc |
|
64 { |
|
65 public: |
|
66 TChunkCleanup(DSharedChunkFactory* aFactory); |
|
67 ~TChunkCleanup(); |
|
68 static void ChunkDestroyed(TChunkCleanup* aSelf); |
|
69 void Cancel(); |
|
70 public: |
|
71 DSharedChunkFactory* iFactory; |
|
72 }; |
|
73 |
|
74 // |
|
75 // TChunkCleanup |
|
76 // |
|
77 |
|
78 TChunkCleanup::TChunkCleanup(DSharedChunkFactory* aFactory) |
|
79 : TDfc((TDfcFn)TChunkCleanup::ChunkDestroyed,this,Kern::SvMsgQue(),0) |
|
80 , iFactory(0) |
|
81 { |
|
82 aFactory->Open(); |
|
83 iFactory = aFactory; |
|
84 } |
|
85 |
|
86 TChunkCleanup::~TChunkCleanup() |
|
87 { |
|
88 if(iFactory) |
|
89 iFactory->Close(0); |
|
90 } |
|
91 |
|
92 void TChunkCleanup::ChunkDestroyed(TChunkCleanup* aSelf) |
|
93 { |
|
94 DSharedChunkFactory* factory = aSelf->iFactory; |
|
95 if(factory) |
|
96 { |
|
97 factory->LockWait(); |
|
98 ++ChunkDestroyedCount; |
|
99 factory->LockSignal(); |
|
100 } |
|
101 delete aSelf; |
|
102 } |
|
103 |
|
104 void TChunkCleanup::Cancel() |
|
105 { |
|
106 if(iFactory) |
|
107 { |
|
108 iFactory->Close(0); |
|
109 iFactory = 0; |
|
110 } |
|
111 }; |
|
112 |
|
113 // |
|
114 // DSharedChunkFactory |
|
115 // |
|
116 |
|
117 TInt DSharedChunkFactory::Install() |
|
118 { |
|
119 return SetName(&KSharedChunkLddName); |
|
120 } |
|
121 |
|
122 DSharedChunkFactory::~DSharedChunkFactory() |
|
123 { |
|
124 |
|
125 } |
|
126 |
|
127 void DSharedChunkFactory::GetCaps(TDes8& /*aDes*/) const |
|
128 { |
|
129 // Not used but required as DLogicalDevice::GetCaps is pure virtual |
|
130 } |
|
131 |
|
132 TInt DSharedChunkFactory::Create(DLogicalChannelBase*& aChannel) |
|
133 { |
|
134 aChannel = NULL; |
|
135 DSharedChunkChannel* channel=new DSharedChunkChannel; |
|
136 if(!channel) |
|
137 return KErrNoMemory; |
|
138 channel->iFactory = this; |
|
139 aChannel = channel; |
|
140 return KErrNone; |
|
141 } |
|
142 |
|
143 void DSharedChunkFactory::LockWait() |
|
144 { |
|
145 NKern::FMWait(&iLock); |
|
146 } |
|
147 |
|
148 void DSharedChunkFactory::LockSignal() |
|
149 { |
|
150 NKern::FMSignal(&iLock); |
|
151 } |
|
152 |
|
153 DECLARE_STANDARD_LDD() |
|
154 { |
|
155 return new DSharedChunkFactory; |
|
156 } |
|
157 |
|
158 // |
|
159 // DSharedChunkChannel |
|
160 // |
|
161 |
|
162 TInt DSharedChunkChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/) |
|
163 { |
|
164 return KErrNone; |
|
165 } |
|
166 |
|
167 DSharedChunkChannel::DSharedChunkChannel() |
|
168 :iFactory(0),iChunk(0),iKernelAddress(0),iMaxSize(0), iContiguous(0),iCacheAttrib(0) |
|
169 { |
|
170 } |
|
171 |
|
172 DSharedChunkChannel::~DSharedChunkChannel() |
|
173 { |
|
174 if(iChunk) |
|
175 iChunk->Close(0); |
|
176 } |
|
177 |
|
178 DChunk* DSharedChunkChannel::OpenChunk(TLinAddr* aKernelAddr,TInt* aMaxSize) |
|
179 { |
|
180 __ASSERT_CRITICAL // Thread must be in critical section (to avoid leaking access count on chunk) |
|
181 LockWait(); |
|
182 DChunk* chunk=iChunk; |
|
183 if(chunk) |
|
184 if(chunk->Open()!=KErrNone) |
|
185 chunk = NULL; |
|
186 if(aKernelAddr) |
|
187 *aKernelAddr = chunk ? iKernelAddress : NULL; |
|
188 if(aMaxSize) |
|
189 *aMaxSize = chunk ? iMaxSize : 0; |
|
190 LockSignal(); |
|
191 return chunk; |
|
192 } |
|
193 |
|
194 TInt DSharedChunkChannel::Request(TInt aFunction, TAny* a1, TAny* a2) |
|
195 { |
|
196 TInt i1 = (TInt)a1; |
|
197 TInt i2 = (TInt)a2; |
|
198 |
|
199 TInt r=KErrNotSupported; |
|
200 |
|
201 switch(aFunction) |
|
202 { |
|
203 |
|
204 case RSharedChunkLdd::ECreateChunk: |
|
205 { |
|
206 if(ChunkDestroyedCount==0) |
|
207 NKern::Sleep(NKern::TimerTicks(100)); // Go idle for a while to let chunk cleanup DFCs to be called |
|
208 |
|
209 NKern::ThreadEnterCS(); |
|
210 |
|
211 TChunkCleanup* cleanup = new TChunkCleanup(this->iFactory); |
|
212 if(!cleanup) |
|
213 { |
|
214 NKern::ThreadLeaveCS(); |
|
215 return KErrNoMemory; |
|
216 } |
|
217 |
|
218 // Try and create chunk... |
|
219 DChunk* chunk; |
|
220 TChunkCreateInfo info; |
|
221 |
|
222 info.iType = (i1&EMultiple) |
|
223 ? TChunkCreateInfo::ESharedKernelMultiple |
|
224 : TChunkCreateInfo::ESharedKernelSingle; |
|
225 |
|
226 info.iMaxSize = i1&~ECreateFlagsMask; |
|
227 #ifndef __WINS__ |
|
228 info.iMapAttr = (i1&ECached) ? EMapAttrCachedMax |
|
229 : EMapAttrFullyBlocking; |
|
230 #else |
|
231 info.iMapAttr = 0; |
|
232 #endif |
|
233 |
|
234 info.iOwnsMemory = (i1&EOwnsMemory)!=0; |
|
235 |
|
236 info.iDestroyedDfc = cleanup; |
|
237 |
|
238 if(i1&EBadType) *(TUint8*)&info.iType = 0xff; |
|
239 |
|
240 TUint32 mapAttr; |
|
241 TUint32 kernAddr; |
|
242 r = Kern::ChunkCreate(info, chunk, kernAddr, mapAttr); |
|
243 if(r!=KErrNone) |
|
244 { |
|
245 Kern::Printf("Chunk create failed with reason: %d",r); |
|
246 delete cleanup; |
|
247 NKern::ThreadLeaveCS(); |
|
248 return r; |
|
249 } |
|
250 |
|
251 // Setup data members |
|
252 LockWait(); |
|
253 |
|
254 if(iChunk) |
|
255 r = KErrAlreadyExists; |
|
256 else |
|
257 { |
|
258 iChunk = chunk; |
|
259 iKernelAddress = kernAddr; |
|
260 iMaxSize = info.iMaxSize; |
|
261 #ifndef __WINS__ |
|
262 TUint32 level1Info = mapAttr & EMapAttrL1CacheMask; |
|
263 TUint32 level2Info = mapAttr & EMapAttrL2CacheMask; |
|
264 TBool chunkIsNotcached = ((level2Info == EMapAttrL2Uncached) && |
|
265 ((level1Info == EMapAttrFullyBlocking) || (level1Info == EMapAttrBufferedNC) || |
|
266 (level1Info == EMapAttrBufferedC) || (level1Info == EMapAttrL1Uncached))); |
|
267 iCacheAttrib = (chunkIsNotcached) ? ENotCached : ECached; |
|
268 |
|
269 #else |
|
270 iCacheAttrib = 0; |
|
271 #endif |
|
272 ChunkDestroyedCount = 0; |
|
273 } |
|
274 LockSignal(); |
|
275 |
|
276 if(r!=KErrNone) |
|
277 { |
|
278 // There was an error, so discard created chunk |
|
279 cleanup->Cancel(); |
|
280 Kern::ChunkClose(chunk); |
|
281 NKern::ThreadLeaveCS(); |
|
282 return r; |
|
283 } |
|
284 |
|
285 NKern::ThreadLeaveCS(); |
|
286 |
|
287 // Write back kernel address of chunk |
|
288 if(a2) |
|
289 kumemput32(a2,(TAny*)&kernAddr,4); |
|
290 |
|
291 return KErrNone; |
|
292 } |
|
293 |
|
294 |
|
295 case RSharedChunkLdd::EGetChunkHandle: |
|
296 { |
|
297 NKern::ThreadEnterCS(); |
|
298 DChunk* chunk=OpenChunk(); |
|
299 if(chunk) |
|
300 { |
|
301 Kern::Printf("We can open a chunk here."); |
|
302 r = Kern::MakeHandleAndOpen(0,chunk); |
|
303 Kern::Printf("The chunk handle we get is: %d", r); |
|
304 chunk->Close(0); |
|
305 } |
|
306 else |
|
307 r = KErrNotFound; |
|
308 NKern::ThreadLeaveCS(); |
|
309 return r; |
|
310 } |
|
311 |
|
312 |
|
313 case RSharedChunkLdd::ECloseChunkHandle: |
|
314 { |
|
315 NKern::ThreadEnterCS(); |
|
316 r = Kern::CloseHandle(0,i1); |
|
317 NKern::ThreadLeaveCS(); |
|
318 return r; |
|
319 } |
|
320 |
|
321 |
|
322 case RSharedChunkLdd::ECommitMemory: |
|
323 { |
|
324 NKern::ThreadEnterCS(); |
|
325 TUint32 chunkKernelAddress; |
|
326 DChunk* chunk=OpenChunk(&chunkKernelAddress); |
|
327 if(chunk) |
|
328 { |
|
329 TInt type = i1&ECommitTypeMask; |
|
330 i1 &= ~ECommitTypeMask; |
|
331 iContiguous = type; |
|
332 switch(type) |
|
333 { |
|
334 case ENonContiguous: |
|
335 r = Kern::ChunkCommit(chunk,i1,i2); |
|
336 break; |
|
337 |
|
338 case EContiguous: |
|
339 { |
|
340 TUint32 physAddr=~0u; |
|
341 r = Kern::ChunkCommitContiguous(chunk,i1,i2,physAddr); |
|
342 if(r!=KErrNone || i2==0) |
|
343 break; |
|
344 if(physAddr==~0u) |
|
345 { r=KErrGeneral; break; } |
|
346 |
|
347 // Check that ChunkPhysicalAddress returns addresses consistant with the commit |
|
348 TUint32 kernAddr; |
|
349 TUint32 mapAttr; |
|
350 TUint32 physAddr2; |
|
351 r = Kern::ChunkPhysicalAddress(chunk, i1, i2, kernAddr, mapAttr, physAddr2); |
|
352 if(r==KErrNone) |
|
353 if(kernAddr!=chunkKernelAddress+i1 || physAddr2!=physAddr) |
|
354 r=KErrGeneral; |
|
355 } |
|
356 break; |
|
357 |
|
358 default: |
|
359 r = KErrNotSupported; |
|
360 break; |
|
361 } |
|
362 chunk->Close(0); |
|
363 } |
|
364 else |
|
365 r = KErrNotFound; |
|
366 NKern::ThreadLeaveCS(); |
|
367 return r; |
|
368 } |
|
369 |
|
370 case RSharedChunkLdd::ECloseChunk: |
|
371 { |
|
372 NKern::ThreadEnterCS(); |
|
373 |
|
374 // Claim ownership of the chunk |
|
375 LockWait(); |
|
376 DChunk* chunk=iChunk; |
|
377 iChunk = 0; |
|
378 LockSignal(); |
|
379 |
|
380 // Close the chunk |
|
381 if(chunk) |
|
382 r = Kern::ChunkClose(chunk); |
|
383 else |
|
384 r = KErrNotFound; |
|
385 |
|
386 NKern::ThreadLeaveCS(); |
|
387 return r; |
|
388 } |
|
389 |
|
390 case RSharedChunkLdd::ECacheAttribute: |
|
391 { |
|
392 Kern::Printf("In my shared chunk, the iCacheAttrib is: %d", iCacheAttrib); |
|
393 return iCacheAttrib; |
|
394 } |
|
395 |
|
396 case RSharedChunkLdd::EContiguousAttribute: |
|
397 { |
|
398 Kern::Printf("In my shared chunk, the iContiguous is: %d", iContiguous); |
|
399 return iContiguous; |
|
400 } |
|
401 |
|
402 default: |
|
403 return KErrNotSupported; |
|
404 } |
|
405 } |
|
406 |