|
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 // e32/memmodel/epoc/flexible/mshbuf.cpp |
|
15 // Shareable Data Buffers |
|
16 |
|
17 #include <memmodel.h> |
|
18 #include "mmu/mm.h" |
|
19 #include "mmboot.h" |
|
20 #include <kernel/smap.h> |
|
21 |
|
22 _LIT(KLitDMemModelAlignedShPool,"DMMAlignedShPool"); // Must be no more than 16 characters! |
|
23 |
|
24 struct TWait |
|
25 { |
|
26 void Link(TWait*& aList) |
|
27 { |
|
28 iSem.SetOwner(NULL); |
|
29 iNext = aList; |
|
30 aList = this; |
|
31 }; |
|
32 void Wait() |
|
33 { |
|
34 NKern::FSWait(&iSem); |
|
35 } |
|
36 NFastSemaphore iSem; |
|
37 TWait* iNext; |
|
38 |
|
39 static void SignalAll(TWait* aList) |
|
40 { |
|
41 while (aList) |
|
42 { |
|
43 TWait* next = aList->iNext; |
|
44 NKern::FSSignal(&aList->iSem); |
|
45 aList = next; |
|
46 } |
|
47 } |
|
48 }; |
|
49 |
|
50 |
|
51 class DShBufMapping : public DBase |
|
52 { |
|
53 public: |
|
54 SDblQueLink iObjLink; |
|
55 DMemoryMapping* iMapping; |
|
56 TInt iOsAsid; |
|
57 TWait* iTransitions; // Mapping and Unmapping operations |
|
58 TBool iTransitioning; |
|
59 }; |
|
60 |
|
61 |
|
62 DMemModelShPool::DMemModelShPool() : DShPool() |
|
63 { |
|
64 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelShPool::DMemModelShPool")); |
|
65 } |
|
66 |
|
67 DMemModelShPool::~DMemModelShPool() |
|
68 { |
|
69 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelShPool::~DMemModelShPool")); |
|
70 } |
|
71 |
|
72 void DMemModelShPool::DestroyClientResources(DProcess* aProcess) |
|
73 { |
|
74 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelShPool::DestroyClientResources")); |
|
75 |
|
76 TInt r = DestroyAllMappingsAndReservedHandles(aProcess); |
|
77 __NK_ASSERT_DEBUG((r == KErrNone) || (r == KErrDied)); |
|
78 (void)r; // Silence warnings |
|
79 } |
|
80 |
|
81 DMemModelAlignedShBuf::DMemModelAlignedShBuf(DShPool* aPool) : DShBuf(aPool) |
|
82 { |
|
83 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShBuf::DMemModelAlignedShBuf()")); |
|
84 } |
|
85 |
|
86 TInt DMemModelAlignedShBuf::Construct() |
|
87 { |
|
88 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShBuf::Construct()")); |
|
89 |
|
90 TInt r = KErrNone; |
|
91 |
|
92 r = DShBuf::Construct(); |
|
93 |
|
94 if (r == KErrNone) |
|
95 r = Create(); |
|
96 |
|
97 return r; |
|
98 } |
|
99 |
|
100 TInt DMemModelAlignedShBuf::Close(TAny* aPtr) |
|
101 { |
|
102 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShBuf::Close(0x%08x)", aPtr)); |
|
103 |
|
104 if (aPtr) |
|
105 { |
|
106 DProcess* pP = reinterpret_cast<DProcess*>(aPtr); |
|
107 UnMap(pP); |
|
108 iPool->CloseClient(pP); |
|
109 } |
|
110 |
|
111 return DShBuf::Close(aPtr); |
|
112 } |
|
113 |
|
114 TInt DMemModelAlignedShBuf::AddToProcess(DProcess* aProcess, TUint aAttr) |
|
115 { |
|
116 __KTRACE_OPT(KMMU,Kern::Printf("Adding DMemModelShBuf %O to process %O",this,aProcess)); |
|
117 TInt r; |
|
118 TLinAddr base; |
|
119 TUint flags; |
|
120 |
|
121 r = iPool->OpenClient(aProcess, flags); |
|
122 |
|
123 if (r == KErrNone) |
|
124 { |
|
125 if ((flags & EShPoolAutoMapBuf) && ((aAttr & EShPoolNoMapBuf) == 0)) |
|
126 { |
|
127 // note we use the client's pool flags and not the buffer attributes |
|
128 r = Map(flags, aProcess, base); |
|
129 |
|
130 if (aProcess == K::TheKernelProcess) |
|
131 iRelAddress = static_cast<TLinAddr>(base); |
|
132 } |
|
133 } |
|
134 |
|
135 return r; |
|
136 } |
|
137 |
|
138 TInt DMemModelAlignedShBuf::Create() |
|
139 { |
|
140 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShBuf::Create()")); |
|
141 TInt r = KErrNone; |
|
142 |
|
143 // calculate memory type... |
|
144 TMemoryObjectType memoryType = EMemoryObjectUnpaged; |
|
145 |
|
146 TMemoryAttributes attr = EMemoryAttributeStandard; |
|
147 |
|
148 // calculate memory flags... |
|
149 TMemoryCreateFlags flags = static_cast<TMemoryCreateFlags>((EMemoryCreateDefault|EMemoryCreateUseCustomWipeByte|(0xAA<<EMemoryCreateWipeByteShift))); |
|
150 |
|
151 // note that any guard pages will be included in iBufGap, however the amount of memory committed |
|
152 // will be iBufSize rounded up to a page |
|
153 r = MM::MemoryNew(iMemoryObject, memoryType, MM::RoundToPageCount(iPool->iBufGap), flags, attr); |
|
154 |
|
155 if(r!=KErrNone) |
|
156 return r; |
|
157 |
|
158 if (iPool->iPoolFlags & EShPoolContiguous) |
|
159 { |
|
160 TPhysAddr paddr; |
|
161 r = MM::MemoryAllocContiguous(iMemoryObject, 0, MM::RoundToPageCount(iPool->iBufSize), 0, paddr); |
|
162 } |
|
163 else |
|
164 { |
|
165 r = MM::MemoryAlloc(iMemoryObject, 0, MM::RoundToPageCount(iPool->iBufSize)); |
|
166 } |
|
167 |
|
168 return r; |
|
169 } |
|
170 |
|
171 DMemModelAlignedShBuf::~DMemModelAlignedShBuf() |
|
172 { |
|
173 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShBuf::~DMemModelAlignedShBuf()")); |
|
174 |
|
175 __NK_ASSERT_DEBUG(iMappings.IsEmpty()); |
|
176 |
|
177 MM::MemoryDestroy(iMemoryObject); |
|
178 } |
|
179 |
|
180 TInt DMemModelAlignedShBuf::Map(TUint aMapAttr, DProcess* aProcess, TLinAddr& aBase) |
|
181 { |
|
182 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShBuf::Map()")); |
|
183 TInt r = KErrNone; |
|
184 |
|
185 DShBufMapping* m = NULL; |
|
186 DMemoryMapping* mapping = NULL; |
|
187 DMemModelProcess* pP = reinterpret_cast<DMemModelProcess*>(aProcess); |
|
188 |
|
189 TBool write = (TBool)EFalse; |
|
190 |
|
191 // User = ETrue, ReadOnlyWrite = ETrue, Execute = EFalse |
|
192 if (aMapAttr & EShPoolWriteable) |
|
193 write = (TBool)ETrue; |
|
194 |
|
195 TMappingPermissions perm = MM::MappingPermissions(pP!=K::TheKernelProcess, write, (TBool)EFalse); |
|
196 TWait wait; |
|
197 |
|
198 for(;;) |
|
199 { |
|
200 iPool->LockPool(); |
|
201 r = FindMapping(m, pP); |
|
202 |
|
203 if (r != KErrNone) |
|
204 break; |
|
205 |
|
206 if (m->iTransitioning) |
|
207 { |
|
208 wait.Link(m->iTransitions); |
|
209 iPool->UnlockPool(); |
|
210 wait.Wait(); |
|
211 } |
|
212 else |
|
213 { |
|
214 iPool->UnlockPool(); |
|
215 return KErrAlreadyExists; |
|
216 } |
|
217 } |
|
218 |
|
219 DMemModelAlignedShPoolClient* client = reinterpret_cast<DMemModelAlignedShPoolClient*>(iPool->iClientMap->Find(reinterpret_cast<TUint>(aProcess))); |
|
220 |
|
221 __NK_ASSERT_DEBUG(client); |
|
222 |
|
223 DMemModelAlignedShPool* pool = reinterpret_cast<DMemModelAlignedShPool*>(iPool); |
|
224 |
|
225 __NK_ASSERT_DEBUG(m == NULL); |
|
226 r = pool->GetFreeMapping(m, client); |
|
227 |
|
228 if (r == KErrNone) |
|
229 { |
|
230 iMappings.AddHead(&m->iObjLink); |
|
231 m->iTransitioning = ETrue; |
|
232 |
|
233 mapping = m->iMapping; |
|
234 iPool->UnlockPool(); // have to release fast lock for MappingMap |
|
235 |
|
236 r = MM::MappingMap(mapping, perm, iMemoryObject, 0, MM::RoundToPageCount(pool->iBufSize)); |
|
237 |
|
238 iPool->LockPool(); |
|
239 |
|
240 TWait* list = m->iTransitions; |
|
241 m->iTransitions = NULL; |
|
242 |
|
243 if (r != KErrNone) |
|
244 pool->ReleaseMapping(m, client); |
|
245 else |
|
246 aBase = MM::MappingBase(mapping); |
|
247 |
|
248 m->iTransitioning = EFalse; |
|
249 iPool->UnlockPool(); |
|
250 |
|
251 TWait::SignalAll(list); |
|
252 } |
|
253 else |
|
254 iPool->UnlockPool(); |
|
255 |
|
256 return r; |
|
257 } |
|
258 |
|
259 TInt DMemModelAlignedShBuf::FindMapping(DShBufMapping*& aMapping, DMemModelProcess* aProcess) |
|
260 { |
|
261 // Must be in critical section so we don't leak os asid references. |
|
262 __ASSERT_CRITICAL; |
|
263 __NK_ASSERT_DEBUG(iPool->iLock.HeldByCurrentThread()); |
|
264 |
|
265 TInt r = KErrNotFound; |
|
266 aMapping = NULL; |
|
267 |
|
268 // Open a reference on aProcess's os asid so that it can't be freed and |
|
269 // reused while searching. |
|
270 TInt osAsid = aProcess->TryOpenOsAsid(); |
|
271 if (osAsid < 0) |
|
272 {// aProcess has died and freed its os asid. |
|
273 return KErrDied; |
|
274 } |
|
275 |
|
276 SDblQueLink* pLink = iMappings.First(); |
|
277 SDblQueLink* end = reinterpret_cast<SDblQueLink*>(&iMappings); |
|
278 DShBufMapping* m = NULL; |
|
279 |
|
280 while (pLink != end) |
|
281 { |
|
282 m = _LOFF(pLink, DShBufMapping, iObjLink); |
|
283 |
|
284 if (m->iOsAsid == osAsid) |
|
285 { |
|
286 aMapping = m; |
|
287 r = KErrNone; |
|
288 break; |
|
289 } |
|
290 pLink = pLink->iNext; |
|
291 } |
|
292 |
|
293 // Close the reference on the os asid as if we have a mapping then its lifetime will |
|
294 // determine whether the process still owns an os asid. |
|
295 aProcess->CloseOsAsid(); |
|
296 return r; |
|
297 } |
|
298 |
|
299 TInt DMemModelAlignedShBuf::UnMap(DProcess* aProcess) |
|
300 { |
|
301 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShBuf::UnMap()")); |
|
302 |
|
303 TInt r = KErrNone; |
|
304 |
|
305 DMemModelProcess* pP = reinterpret_cast<DMemModelProcess*>(aProcess); |
|
306 |
|
307 DShBufMapping* m = NULL; |
|
308 TWait wait; |
|
309 |
|
310 for(;;) |
|
311 { |
|
312 iPool->LockPool(); |
|
313 r = FindMapping(m, pP); |
|
314 |
|
315 if (r != KErrNone) |
|
316 { |
|
317 iPool->UnlockPool(); |
|
318 return KErrNotFound; |
|
319 } |
|
320 |
|
321 if (m->iTransitioning) |
|
322 { |
|
323 wait.Link(m->iTransitions); |
|
324 iPool->UnlockPool(); |
|
325 wait.Wait(); |
|
326 } |
|
327 else |
|
328 { |
|
329 break; |
|
330 } |
|
331 } |
|
332 |
|
333 m->iTransitioning = ETrue; |
|
334 iPool->UnlockPool(); |
|
335 |
|
336 MM::MappingUnmap(m->iMapping); |
|
337 |
|
338 iPool->LockPool(); |
|
339 DMemModelAlignedShPoolClient* client = reinterpret_cast<DMemModelAlignedShPoolClient*>(iPool->iClientMap->Find(reinterpret_cast<TUint>(aProcess))); |
|
340 |
|
341 __NK_ASSERT_DEBUG(client); |
|
342 |
|
343 TWait* list = m->iTransitions; |
|
344 m->iTransitions = NULL; |
|
345 m->iObjLink.Deque(); |
|
346 m->iTransitioning = EFalse; |
|
347 |
|
348 DMemModelAlignedShPool* pool = reinterpret_cast<DMemModelAlignedShPool*>(iPool); |
|
349 pool->ReleaseMapping(m, client); |
|
350 |
|
351 if (aProcess == K::TheKernelProcess) |
|
352 iRelAddress = NULL; |
|
353 |
|
354 iPool->UnlockPool(); |
|
355 |
|
356 wait.SignalAll(list); |
|
357 return KErrNone; |
|
358 } |
|
359 |
|
360 TUint8* DMemModelAlignedShBuf::Base(DProcess* aProcess) |
|
361 { |
|
362 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShBuf::Base()")); |
|
363 DMemModelProcess* pP = reinterpret_cast<DMemModelProcess*>(aProcess); |
|
364 |
|
365 DShBufMapping* mapping = NULL; |
|
366 iPool->LockPool(); |
|
367 TInt r = FindMapping(mapping, pP); |
|
368 TUint8* base = NULL; |
|
369 |
|
370 if (r == KErrNone) |
|
371 base = reinterpret_cast<TUint8*>(MM::MappingBase(mapping->iMapping)); |
|
372 iPool->UnlockPool(); |
|
373 |
|
374 return base; |
|
375 } |
|
376 |
|
377 TUint8* DMemModelAlignedShBuf::Base() |
|
378 { |
|
379 return reinterpret_cast<TUint8*>(iRelAddress); |
|
380 } |
|
381 |
|
382 TInt DMemModelAlignedShBuf::Pin(TPhysicalPinObject* aPinObject, TBool aReadOnly, TPhysAddr& aAddress, TPhysAddr* aPages, TUint32& aMapAttr, TUint& aColour) |
|
383 { |
|
384 CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"DMemModelAlignedShBuf::Pin"); |
|
385 |
|
386 TInt r = MM::PinPhysicalMemory(iMemoryObject, (DPhysicalPinMapping*)aPinObject, 0, |
|
387 MM::RoundToPageCount(Size()), |
|
388 aReadOnly, aAddress, aPages, aMapAttr, aColour); |
|
389 |
|
390 return r; |
|
391 } |
|
392 |
|
393 TInt DMemModelAlignedShPool::GetFreeMapping(DShBufMapping*& aMapping, DMemModelAlignedShPoolClient* aClient) |
|
394 { |
|
395 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::GetFreeMapping()")); |
|
396 __NK_ASSERT_DEBUG(iLock.HeldByCurrentThread()); |
|
397 |
|
398 TInt r = KErrNotFound; |
|
399 aMapping = NULL; |
|
400 |
|
401 if (aClient) |
|
402 { |
|
403 if (!aClient->iMappingFreeList.IsEmpty()) |
|
404 { |
|
405 aMapping = _LOFF(aClient->iMappingFreeList.GetFirst(), DShBufMapping, iObjLink); |
|
406 r = KErrNone; |
|
407 } |
|
408 else |
|
409 { |
|
410 r = KErrNoMemory; |
|
411 } |
|
412 } |
|
413 |
|
414 __KTRACE_OPT(KMMU2, Kern::Printf("DMemModelAlignedShPool::GetFreeMapping(0x%08x, 0x%08x) returns %d", aMapping, aClient, r)); |
|
415 return r; |
|
416 } |
|
417 |
|
418 TInt DMemModelAlignedShPool::ReleaseMapping(DShBufMapping*& aMapping, DMemModelAlignedShPoolClient* aClient) |
|
419 { |
|
420 __KTRACE_OPT(KMMU2, Kern::Printf("DMemModelAlignedShPool::ReleaseMapping(0x%08x,0x%08x)",aMapping,aClient)); |
|
421 __NK_ASSERT_DEBUG(iLock.HeldByCurrentThread()); |
|
422 |
|
423 TInt r = KErrNone; |
|
424 |
|
425 if (aClient) |
|
426 { |
|
427 aClient->iMappingFreeList.AddHead(&aMapping->iObjLink); |
|
428 aMapping = NULL; |
|
429 } |
|
430 else |
|
431 { |
|
432 // pool has probably been closed delete mapping |
|
433 r = KErrNotFound; |
|
434 __KTRACE_OPT(KMMU2, Kern::Printf("DMemModelAlignedShPool::ReleaseMapping delete 0x%08x",aMapping)); |
|
435 UnlockPool(); // have to release fast lock for MappingDestroy |
|
436 MM::MappingDestroy(aMapping->iMapping); |
|
437 delete aMapping; |
|
438 aMapping = NULL; |
|
439 LockPool(); |
|
440 } |
|
441 |
|
442 return r; |
|
443 } |
|
444 |
|
445 TInt DMemModelAlignedShPool::SetBufferWindow(DProcess* aProcess, TInt aWindowSize) |
|
446 { |
|
447 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::SetBufferWindow()")); |
|
448 |
|
449 // Create and construct mappings but do not map |
|
450 // also allocate reserved handles |
|
451 TInt r = KErrNone; |
|
452 TUint noOfBuffers = aWindowSize; |
|
453 |
|
454 if (aWindowSize > static_cast<TInt>(iMaxBuffers)) |
|
455 return KErrArgument; |
|
456 |
|
457 Kern::MutexWait(*iProcessLock); |
|
458 |
|
459 LockPool(); |
|
460 DMemModelAlignedShPoolClient* client = reinterpret_cast<DMemModelAlignedShPoolClient*>(iClientMap->Find(reinterpret_cast<TUint>(aProcess))); |
|
461 UnlockPool(); |
|
462 |
|
463 if (client) |
|
464 { |
|
465 if (client->iWindowSize != 0) |
|
466 { |
|
467 Kern::MutexSignal(*iProcessLock); |
|
468 return KErrAlreadyExists; |
|
469 } |
|
470 |
|
471 if (aWindowSize < 0) |
|
472 { |
|
473 noOfBuffers = iTotalBuffers; |
|
474 } |
|
475 |
|
476 DMemModelProcess* pP = reinterpret_cast<DMemModelProcess*>(aProcess); |
|
477 r = CreateMappings(client, noOfBuffers, pP); |
|
478 |
|
479 if (r == KErrNone) |
|
480 { |
|
481 client->iWindowSize = aWindowSize; |
|
482 } |
|
483 else |
|
484 { |
|
485 DestroyMappings(client, noOfBuffers); |
|
486 } |
|
487 } |
|
488 else |
|
489 { |
|
490 r = KErrNotFound; |
|
491 } |
|
492 |
|
493 Kern::MutexSignal(*iProcessLock); |
|
494 |
|
495 return r; |
|
496 } |
|
497 |
|
498 TInt DMemModelAlignedShPool::MappingNew(DShBufMapping*& aMapping, DMemModelProcess* aProcess) |
|
499 { |
|
500 // Must be in critical section so we don't leak os asid references. |
|
501 __ASSERT_CRITICAL; |
|
502 |
|
503 TMappingCreateFlags flags=EMappingCreateDefault; |
|
504 |
|
505 FlagSet(flags, EMappingCreateReserveAllResources); |
|
506 |
|
507 // Open a reference to aProcess's os so it isn't freed and reused while |
|
508 // we're creating this mapping. |
|
509 TInt osAsid = aProcess->TryOpenOsAsid(); |
|
510 if (osAsid < 0) |
|
511 {// The process has freed its os asid so can't create a new mapping. |
|
512 return KErrDied; |
|
513 } |
|
514 |
|
515 DMemoryMapping* mapping = NULL; |
|
516 DShBufMapping* m = NULL; |
|
517 TInt r = MM::MappingNew(mapping, MM::RoundToPageCount(iBufGap), osAsid, flags); |
|
518 |
|
519 if (r == KErrNone) |
|
520 { |
|
521 m = new DShBufMapping; |
|
522 |
|
523 if (m) |
|
524 { |
|
525 m->iMapping = mapping; |
|
526 m->iOsAsid = osAsid; |
|
527 } |
|
528 else |
|
529 { |
|
530 MM::MappingDestroy(mapping); |
|
531 r = KErrNoMemory; |
|
532 } |
|
533 } |
|
534 |
|
535 // Close the reference on the os asid as while aMapping is valid then the |
|
536 // os asid must be also. |
|
537 aProcess->CloseOsAsid(); |
|
538 |
|
539 aMapping = m; |
|
540 __KTRACE_OPT(KMMU2, Kern::Printf("DMemModelAlignedShPool::MappingNew returns 0x%08x,%d",aMapping,r)); |
|
541 return r; |
|
542 } |
|
543 |
|
544 TInt DMemModelAlignedShPool::AddToProcess(DProcess* aProcess, TUint aAttr) |
|
545 { |
|
546 __KTRACE_OPT(KMMU,Kern::Printf("Adding DMemModelAlignedShPool %O to process %O",this,aProcess)); |
|
547 TInt r = KErrNone; |
|
548 |
|
549 Kern::MutexWait(*iProcessLock); |
|
550 |
|
551 LockPool(); |
|
552 DShPoolClient* client = reinterpret_cast<DShPoolClient*>(iClientMap->Find(reinterpret_cast<TUint>(aProcess))); |
|
553 UnlockPool(); |
|
554 |
|
555 if (!client) |
|
556 { |
|
557 client = new DMemModelAlignedShPoolClient; |
|
558 if (client) |
|
559 { |
|
560 client->iFlags = aAttr; |
|
561 r = iClientMap->Add(reinterpret_cast<TUint>(aProcess), client); |
|
562 |
|
563 if (r == KErrNone) |
|
564 { |
|
565 if (aProcess != K::TheKernelProcess) |
|
566 { |
|
567 r = aProcess->iHandles.Reserve(iTotalBuffers); |
|
568 |
|
569 if (r != KErrNone) |
|
570 { |
|
571 iClientMap->Remove(reinterpret_cast<TUint>(aProcess)); |
|
572 } |
|
573 } |
|
574 } |
|
575 if (r != KErrNone) |
|
576 { |
|
577 delete client; |
|
578 r = KErrNoMemory; |
|
579 } |
|
580 } |
|
581 else |
|
582 { |
|
583 r = KErrNoMemory; |
|
584 } |
|
585 } |
|
586 else |
|
587 { |
|
588 LockPool(); |
|
589 client->iAccessCount++; |
|
590 UnlockPool(); |
|
591 } |
|
592 |
|
593 Kern::MutexSignal(*iProcessLock); |
|
594 |
|
595 return r; |
|
596 } |
|
597 |
|
598 DMemModelAlignedShPool::DMemModelAlignedShPool() : DMemModelShPool() |
|
599 |
|
600 { |
|
601 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::DMemModelAlignedShPool")); |
|
602 } |
|
603 |
|
604 void DMemModelAlignedShPool::Free(DShBuf* aBuf) |
|
605 { |
|
606 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::Free (aBuf = 0x%08x)", aBuf)); |
|
607 |
|
608 LockPool(); |
|
609 #ifdef _DEBUG |
|
610 // Remove from allocated list |
|
611 aBuf->iObjLink.Deque(); |
|
612 #endif |
|
613 |
|
614 DMemModelAlignedShBuf* buf = reinterpret_cast<DMemModelAlignedShBuf*>(aBuf); |
|
615 |
|
616 if (MM::MemoryIsNotMapped(buf->iMemoryObject)) |
|
617 { |
|
618 UnlockPool(); // have to release fast mutex |
|
619 MM::MemoryWipe(buf->iMemoryObject); |
|
620 LockPool(); |
|
621 |
|
622 // we want to put the initial buffers at the head of the free list |
|
623 // and the grown buffers at the tail as this makes shrinking more efficient |
|
624 if (aBuf >= iInitialBuffersArray && aBuf < (iInitialBuffersArray + iInitialBuffers)) |
|
625 { |
|
626 iFreeList.AddHead(&aBuf->iObjLink); |
|
627 } |
|
628 else |
|
629 { |
|
630 iFreeList.Add(&aBuf->iObjLink); |
|
631 } |
|
632 ++iFreeBuffers; |
|
633 #ifdef _DEBUG |
|
634 --iAllocatedBuffers; |
|
635 #endif |
|
636 } |
|
637 else |
|
638 { |
|
639 iPendingList.Add(&aBuf->iObjLink); |
|
640 } |
|
641 |
|
642 iPoolFlags &= ~EShPoolSuppressShrink; // Allow shrinking again, if it was blocked |
|
643 UnlockPool(); |
|
644 |
|
645 // queue ManagementDfc which completes notifications as appropriate |
|
646 if (HaveWorkToDo()) |
|
647 KickManagementDfc(); |
|
648 |
|
649 DShPool::Close(NULL); // decrement pool reference count |
|
650 } |
|
651 |
|
652 TInt DMemModelAlignedShPool::UpdateFreeList() |
|
653 { |
|
654 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::UpdateFreeList")); |
|
655 |
|
656 LockPool(); |
|
657 SDblQueLink* pLink = iPendingList.First(); |
|
658 UnlockPool(); |
|
659 |
|
660 SDblQueLink* anchor = &iPendingList.iA; |
|
661 |
|
662 while (pLink != anchor) |
|
663 { |
|
664 DMemModelAlignedShBuf* buf = _LOFF(pLink, DMemModelAlignedShBuf, iObjLink); |
|
665 LockPool(); |
|
666 pLink = pLink->iNext; |
|
667 UnlockPool(); |
|
668 |
|
669 if (MM::MemoryIsNotMapped(buf->iMemoryObject)) |
|
670 { |
|
671 LockPool(); |
|
672 buf->iObjLink.Deque(); |
|
673 UnlockPool(); |
|
674 |
|
675 MM::MemoryWipe(buf->iMemoryObject); |
|
676 |
|
677 LockPool(); |
|
678 if (buf >= iInitialBuffersArray && buf < (iInitialBuffersArray + iInitialBuffers)) |
|
679 { |
|
680 iFreeList.AddHead(&buf->iObjLink); |
|
681 } |
|
682 else |
|
683 { |
|
684 iFreeList.Add(&buf->iObjLink); |
|
685 } |
|
686 ++iFreeBuffers; |
|
687 #ifdef _DEBUG |
|
688 --iAllocatedBuffers; |
|
689 #endif |
|
690 UnlockPool(); |
|
691 } |
|
692 } |
|
693 |
|
694 __KTRACE_OPT(KMMU, Kern::Printf("<DMemModelAlignedShPool::UpdateFreeList")); |
|
695 return KErrNone; |
|
696 } |
|
697 |
|
698 DMemModelAlignedShPool::~DMemModelAlignedShPool() |
|
699 { |
|
700 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::~DMemModelAlignedShPool")); |
|
701 } |
|
702 |
|
703 TInt DMemModelAlignedShPool::DoCreate(TShPoolCreateInfo& aInfo) |
|
704 { |
|
705 |
|
706 TUint64 maxSize64 = static_cast<TUint64>(aInfo.iInfo.iMaxBufs) * static_cast<TUint64>(iBufGap); |
|
707 |
|
708 if (maxSize64 > static_cast<TUint64>(KMaxTInt) || maxSize64 <= static_cast<TUint64>(0)) |
|
709 return KErrArgument; |
|
710 |
|
711 iMaxPages = MM::RoundToPageCount(static_cast<TInt>(maxSize64)); |
|
712 |
|
713 return KErrNone; |
|
714 } |
|
715 |
|
716 TInt DMemModelAlignedShPool::DestroyAllMappingsAndReservedHandles(DProcess* aProcess) |
|
717 { |
|
718 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::DestroyAllMappingsAndReservedHandles(0x%08x)", aProcess)); |
|
719 |
|
720 TInt r = KErrNone; |
|
721 Kern::MutexWait(*iProcessLock); |
|
722 DMemModelAlignedShPoolClient* client = reinterpret_cast<DMemModelAlignedShPoolClient*>(iClientMap->Remove(reinterpret_cast<TUint>(aProcess))); |
|
723 |
|
724 __NK_ASSERT_DEBUG(client); |
|
725 __NK_ASSERT_DEBUG(client->iAccessCount == 0); |
|
726 |
|
727 DestroyMappings(client, KMaxTInt); |
|
728 delete client; |
|
729 |
|
730 if (aProcess != K::TheKernelProcess) |
|
731 { |
|
732 // Remove reserved handles |
|
733 r = aProcess->iHandles.Reserve(-iTotalBuffers); |
|
734 } |
|
735 |
|
736 Kern::MutexSignal(*iProcessLock); |
|
737 |
|
738 __KTRACE_OPT(KMMU, Kern::Printf("<DMemModelAlignedShPool::DestroyAllMappingsAndReservedHandles(0x%08x)", aProcess)); |
|
739 |
|
740 return r; |
|
741 } |
|
742 |
|
743 TInt DMemModelAlignedShPool::DestroyMappings(DMemModelAlignedShPoolClient* aClient, TInt aNoOfMappings) |
|
744 { |
|
745 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::DestroyMappings(0x%08x)", aClient)); |
|
746 |
|
747 TInt r = KErrNone; |
|
748 TInt i = 0; |
|
749 |
|
750 DShBufMapping* m = NULL; |
|
751 SDblQueLink* pLink = NULL; |
|
752 |
|
753 while (i < aNoOfMappings && !aClient->iMappingFreeList.IsEmpty()) |
|
754 { |
|
755 LockPool(); |
|
756 pLink = aClient->iMappingFreeList.GetFirst(); |
|
757 UnlockPool(); |
|
758 |
|
759 if (pLink == NULL) |
|
760 break; |
|
761 |
|
762 m = _LOFF(pLink, DShBufMapping, iObjLink); |
|
763 __KTRACE_OPT(KMMU2, Kern::Printf("DMemModelAlignedShPool::DestroyMappings delete 0x%08x",m)); |
|
764 MM::MappingClose(m->iMapping); |
|
765 delete m; |
|
766 ++i; |
|
767 } |
|
768 |
|
769 __KTRACE_OPT(KMMU, Kern::Printf("<MemModelAlignedShPool::DestroyMappings")); |
|
770 |
|
771 return r; |
|
772 } |
|
773 |
|
774 |
|
775 TInt DMemModelAlignedShPool::CreateMappings(DMemModelAlignedShPoolClient* aClient, TInt aNoOfMappings, DMemModelProcess* aProcess) |
|
776 { |
|
777 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::CreateMappings")); |
|
778 |
|
779 __ASSERT_MUTEX(iProcessLock); |
|
780 |
|
781 TInt r = KErrNone; |
|
782 |
|
783 for (TInt i = 0; i < aNoOfMappings; ++i) |
|
784 { |
|
785 DShBufMapping* mapping; |
|
786 r = MappingNew(mapping, aProcess); |
|
787 if (r == KErrNone) |
|
788 { |
|
789 LockPool(); |
|
790 aClient->iMappingFreeList.AddHead(&mapping->iObjLink); |
|
791 UnlockPool(); |
|
792 } |
|
793 else |
|
794 { |
|
795 r = KErrNoMemory; |
|
796 break; |
|
797 } |
|
798 } |
|
799 |
|
800 return r; |
|
801 } |
|
802 |
|
803 TInt DMemModelAlignedShPool::UpdateMappingsAndReservedHandles(TInt aNoOfBuffers) |
|
804 { |
|
805 __KTRACE_OPT(KMMU2, Kern::Printf(">DMemModelAlignedShPool::UpdateMappingsAndReservedHandles(0x%08x)", aNoOfBuffers)); |
|
806 |
|
807 SMap::TIterator iter(*iClientMap); |
|
808 SMap::TEntry* entry; |
|
809 SMap::TEntry* lastEntry = NULL; |
|
810 DMemModelProcess* pP; |
|
811 DMemModelAlignedShPoolClient* client; |
|
812 TInt result = KErrNone; |
|
813 |
|
814 Kern::MutexWait(*iProcessLock); |
|
815 |
|
816 // First handle the case of increasing allocation |
|
817 if (aNoOfBuffers > 0) |
|
818 while ((entry = iter.Next()) != lastEntry) |
|
819 { |
|
820 // Try to update handle reservation; skip if process is null or has gone away |
|
821 client = (DMemModelAlignedShPoolClient*)(entry->iObj); |
|
822 pP = (DMemModelProcess*)(entry->iKey); |
|
823 if (!pP) |
|
824 continue; |
|
825 TInt r = pP->iHandles.Reserve(aNoOfBuffers); |
|
826 if (r) |
|
827 __KTRACE_OPT(KMMU2, Kern::Printf("?DMemModelAlignedShPool::UpdateMappingsAndReservedHandles(0x%08x) Reserve failed %d", aNoOfBuffers, r)); |
|
828 if (r == KErrDied) |
|
829 continue; |
|
830 |
|
831 if (r == KErrNone && client->iWindowSize <= 0) |
|
832 { |
|
833 // A positive window size means the number of mappings is fixed, so we don't need to reserve more. |
|
834 // But here zero or negative means a variable number, so we need to create extra mappings now. |
|
835 r = CreateMappings(client, aNoOfBuffers, pP); |
|
836 if (r != KErrNone) |
|
837 { |
|
838 __KTRACE_OPT(KMMU2, Kern::Printf("?DMemModelAlignedShPool::UpdateMappingsAndReservedHandles(0x%08x) CreateMappings failed %d", aNoOfBuffers, r)); |
|
839 pP->iHandles.Reserve(-aNoOfBuffers); // Creation failed, so release the handles reserved above |
|
840 } |
|
841 } |
|
842 |
|
843 if (r != KErrNone) |
|
844 { |
|
845 // Some problem; cleanup as best we can by falling into the loop below to undo what we've done |
|
846 result = r; |
|
847 iter.Reset(); |
|
848 lastEntry = entry; |
|
849 aNoOfBuffers = -aNoOfBuffers; |
|
850 break; |
|
851 } |
|
852 } |
|
853 |
|
854 // Now handle the case of decreasing allocation; also used for recovery from errors, in which case |
|
855 // this loop iterates only over the elements that were *successfully* processed by the loop above |
|
856 if (aNoOfBuffers < 0) |
|
857 while ((entry = iter.Next()) != lastEntry) |
|
858 { |
|
859 // Try to update handle reservation; skip if process is null or has gone away |
|
860 client = (DMemModelAlignedShPoolClient*)(entry->iObj); |
|
861 pP = (DMemModelProcess*)(entry->iKey); |
|
862 if (!pP) |
|
863 continue; |
|
864 TInt r = pP->iHandles.Reserve(aNoOfBuffers); |
|
865 if (r == KErrDied) |
|
866 continue; |
|
867 |
|
868 if (r == KErrNone && client->iWindowSize <= 0) |
|
869 r = DestroyMappings(client, -aNoOfBuffers); |
|
870 // De-allocation by Reserve(-n) and/or DestroyMappings() should never fail |
|
871 if (r != KErrNone) |
|
872 Kern::PanicCurrentThread(KLitDMemModelAlignedShPool, r); |
|
873 } |
|
874 |
|
875 Kern::MutexSignal(*iProcessLock); |
|
876 |
|
877 __KTRACE_OPT(KMMU2, Kern::Printf("<DMemModelAlignedShPool::UpdateMappingsAndReservedHandles(0x%08x) returning %d", aNoOfBuffers, result)); |
|
878 return result; |
|
879 } |
|
880 |
|
881 TInt DMemModelAlignedShPool::DeleteInitialBuffers() |
|
882 { |
|
883 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::DeleteInitialBuffers")); |
|
884 |
|
885 if (iInitialBuffersArray != NULL) |
|
886 { |
|
887 for (TUint i = 0; i < iInitialBuffers; i++) |
|
888 { |
|
889 iInitialBuffersArray[i].iObjLink.Deque(); // remove from free list |
|
890 iInitialBuffersArray[i].Dec(); |
|
891 iInitialBuffersArray[i].~DMemModelAlignedShBuf(); |
|
892 } |
|
893 } |
|
894 |
|
895 Kern::Free(iInitialBuffersArray); |
|
896 iInitialBuffersArray = NULL; |
|
897 |
|
898 return KErrNone; |
|
899 } |
|
900 |
|
901 TInt DMemModelAlignedShPool::Close(TAny* aPtr) |
|
902 { |
|
903 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::Close(0x%08x)", aPtr)); |
|
904 |
|
905 if (aPtr) |
|
906 { |
|
907 DProcess* pP = reinterpret_cast<DProcess*>(aPtr); |
|
908 |
|
909 CloseClient(pP); |
|
910 } |
|
911 __KTRACE_OPT(KMMU, Kern::Printf("<DMemModelAlignedShPool::Close(0x%08x)", aPtr)); |
|
912 return DShPool::Close(aPtr); |
|
913 } |
|
914 |
|
915 TInt DMemModelAlignedShPool::CreateInitialBuffers() |
|
916 { |
|
917 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::CreateInitialBuffers")); |
|
918 |
|
919 iInitialBuffersArray = reinterpret_cast<DMemModelAlignedShBuf*>(Kern::Alloc(iInitialBuffers * sizeof(DMemModelAlignedShBuf))); |
|
920 |
|
921 if (iInitialBuffersArray == NULL) |
|
922 return KErrNoMemory; |
|
923 |
|
924 for (TUint i = 0; i < iInitialBuffers; i++) |
|
925 { |
|
926 // always use kernel linear address in DShBuf |
|
927 DMemModelAlignedShBuf *buf = new (&iInitialBuffersArray[i]) DMemModelAlignedShBuf(this); |
|
928 TInt r = buf->Construct(); |
|
929 |
|
930 if (r == KErrNone) |
|
931 { |
|
932 iFreeList.Add(&buf->iObjLink); |
|
933 } |
|
934 else |
|
935 { |
|
936 iInitialBuffers = i; |
|
937 return KErrNoMemory; |
|
938 } |
|
939 } |
|
940 |
|
941 iFreeBuffers = iInitialBuffers; |
|
942 iTotalBuffers = iInitialBuffers; |
|
943 return KErrNone; |
|
944 } |
|
945 |
|
946 |
|
947 TInt DMemModelAlignedShPool::GrowPool() |
|
948 { |
|
949 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::GrowPool()")); |
|
950 TInt r = KErrNone; |
|
951 SDblQue temp; |
|
952 |
|
953 Kern::MutexWait(*iProcessLock); |
|
954 |
|
955 TUint32 headroom = iMaxBuffers - iTotalBuffers; |
|
956 |
|
957 // How many buffers to grow by? |
|
958 TUint32 grow = mult_fx248(iTotalBuffers, iGrowByRatio); |
|
959 if (grow == 0) // Handle round-to-zero |
|
960 grow = 1; |
|
961 if (grow > headroom) |
|
962 grow = headroom; |
|
963 |
|
964 TUint i; |
|
965 for (i = 0; i < grow; ++i) |
|
966 { |
|
967 DMemModelAlignedShBuf *buf = new DMemModelAlignedShBuf(this); |
|
968 |
|
969 if (buf == NULL) |
|
970 { |
|
971 r = KErrNoMemory; |
|
972 break; |
|
973 } |
|
974 |
|
975 TInt r = buf->Construct(); |
|
976 |
|
977 if (r != KErrNone) |
|
978 { |
|
979 buf->DObject::Close(NULL); |
|
980 break; |
|
981 } |
|
982 |
|
983 temp.Add(&buf->iObjLink); |
|
984 } |
|
985 |
|
986 r = UpdateMappingsAndReservedHandles(i); |
|
987 |
|
988 if (r == KErrNone) |
|
989 { |
|
990 LockPool(); |
|
991 iFreeList.MoveFrom(&temp); |
|
992 iFreeBuffers += i; |
|
993 iTotalBuffers += i; |
|
994 UnlockPool(); |
|
995 } |
|
996 else |
|
997 { |
|
998 // couldn't create either the mappings or reserve handles so have no choice but to |
|
999 // delete the buffers |
|
1000 SDblQueLink *pLink; |
|
1001 while ((pLink = temp.GetFirst()) != NULL) |
|
1002 { |
|
1003 DShBuf* buf = _LOFF(pLink, DShBuf, iObjLink); |
|
1004 buf->DObject::Close(NULL); |
|
1005 } |
|
1006 } |
|
1007 |
|
1008 CalculateGrowShrinkTriggers(); |
|
1009 |
|
1010 Kern::MutexSignal(*iProcessLock); |
|
1011 |
|
1012 __KTRACE_OPT(KMMU, Kern::Printf("<DMemModelAlignedShPool::GrowPool()")); |
|
1013 return r; |
|
1014 } |
|
1015 |
|
1016 TInt DMemModelAlignedShPool::ShrinkPool() |
|
1017 { |
|
1018 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::ShrinkPool()")) |
|
1019 |
|
1020 Kern::MutexWait(*iProcessLock); |
|
1021 |
|
1022 TUint32 grownBy = iTotalBuffers - iInitialBuffers; |
|
1023 |
|
1024 // How many buffers to shrink by? |
|
1025 TUint32 shrink = mult_fx248(iTotalBuffers, iShrinkByRatio); |
|
1026 if (shrink == 0) // Handle round-to-zero |
|
1027 shrink = 1; |
|
1028 if (shrink > grownBy) |
|
1029 shrink = grownBy; |
|
1030 if (shrink > iFreeBuffers) |
|
1031 shrink = iFreeBuffers; |
|
1032 |
|
1033 // work backwards as the grown buffers should be at the back |
|
1034 TUint i; |
|
1035 for (i = 0; i < shrink; i++) |
|
1036 { |
|
1037 LockPool(); |
|
1038 |
|
1039 if (iFreeList.IsEmpty()) |
|
1040 { |
|
1041 UnlockPool(); |
|
1042 break; |
|
1043 } |
|
1044 |
|
1045 DShBuf* buf = _LOFF(iFreeList.Last(), DShBuf, iObjLink); |
|
1046 |
|
1047 // can't delete initial buffers |
|
1048 if (buf >= iInitialBuffersArray && buf < (iInitialBuffersArray + iInitialBuffers)) |
|
1049 { |
|
1050 UnlockPool(); |
|
1051 break; |
|
1052 } |
|
1053 |
|
1054 buf->iObjLink.Deque(); |
|
1055 --iFreeBuffers; |
|
1056 --iTotalBuffers; |
|
1057 UnlockPool(); |
|
1058 buf->DObject::Close(NULL); |
|
1059 } |
|
1060 |
|
1061 TInt r = UpdateMappingsAndReservedHandles(-i); |
|
1062 |
|
1063 // If we couldn't shrink the pool by this many buffers, wait until we Free() another |
|
1064 // buffer before trying to shrink again. |
|
1065 if (i < shrink) |
|
1066 iPoolFlags |= EShPoolSuppressShrink; |
|
1067 |
|
1068 CalculateGrowShrinkTriggers(); |
|
1069 |
|
1070 Kern::MutexSignal(*iProcessLock); |
|
1071 |
|
1072 __KTRACE_OPT(KMMU, Kern::Printf("<DMemModelAlignedShPool::ShrinkPool()")); |
|
1073 return r; |
|
1074 } |
|
1075 |
|
1076 // Kernel side API |
|
1077 TInt DMemModelAlignedShPool::Alloc(DShBuf*& aShBuf) |
|
1078 { |
|
1079 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::Alloc (DShBuf)")); |
|
1080 |
|
1081 TInt r = KErrNoMemory; |
|
1082 aShBuf = NULL; |
|
1083 |
|
1084 LockPool(); |
|
1085 |
|
1086 if (!iFreeList.IsEmpty()) |
|
1087 { |
|
1088 aShBuf = _LOFF(iFreeList.GetFirst(), DShBuf, iObjLink); |
|
1089 |
|
1090 #ifdef _DEBUG |
|
1091 iAllocated.Add(&aShBuf->iObjLink); |
|
1092 iAllocatedBuffers++; |
|
1093 #endif |
|
1094 --iFreeBuffers; |
|
1095 Open(); // increment pool reference count |
|
1096 r = KErrNone; |
|
1097 } |
|
1098 |
|
1099 UnlockPool(); |
|
1100 |
|
1101 if (HaveWorkToDo()) |
|
1102 KickManagementDfc(); |
|
1103 |
|
1104 __KTRACE_OPT(KMMU, Kern::Printf("<DMemModelAlignedShPool::Alloc return buf = 0x%08x", aShBuf)); |
|
1105 return r; |
|
1106 } |
|
1107 |
|
1108 DMemModelNonAlignedShBuf::DMemModelNonAlignedShBuf(DShPool* aPool, TLinAddr aRelAddr) : DShBuf(aPool, aRelAddr) |
|
1109 { |
|
1110 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShBuf::DMemModelNonAlignedShBuf()")); |
|
1111 } |
|
1112 |
|
1113 DMemModelNonAlignedShBuf::~DMemModelNonAlignedShBuf() |
|
1114 { |
|
1115 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShBuf::~DMemModelNonAlignedShBuf()")); |
|
1116 } |
|
1117 |
|
1118 TInt DMemModelNonAlignedShBuf::Close(TAny* aPtr) |
|
1119 { |
|
1120 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShBuf::Close(0x%08x)", aPtr)); |
|
1121 |
|
1122 if (aPtr) |
|
1123 { |
|
1124 DProcess* pP = reinterpret_cast<DProcess*>(aPtr); |
|
1125 |
|
1126 // there no per buffer resources for kernel clients for non-aligned buffers |
|
1127 if (pP != K::TheKernelProcess) |
|
1128 iPool->CloseClient(pP); |
|
1129 } |
|
1130 |
|
1131 return DShBuf::Close(aPtr); |
|
1132 } |
|
1133 |
|
1134 TInt DMemModelNonAlignedShBuf::AddToProcess(DProcess* aProcess, TUint /* aAttr */) |
|
1135 { |
|
1136 __KTRACE_OPT(KMMU, Kern::Printf("Adding DMemModelShBuf %O to process %O", this, aProcess)); |
|
1137 TUint flags; |
|
1138 |
|
1139 return iPool->OpenClient(aProcess, flags); |
|
1140 } |
|
1141 |
|
1142 |
|
1143 TUint8* DMemModelNonAlignedShBuf::Base(DProcess* aProcess) |
|
1144 { |
|
1145 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShBuf::Base(0x%x)", aProcess)); |
|
1146 |
|
1147 TUint8* base = reinterpret_cast<DMemModelNonAlignedShPool*>(iPool)->Base(aProcess) + (TUint)iRelAddress; |
|
1148 |
|
1149 return base; |
|
1150 } |
|
1151 |
|
1152 TUint8* DMemModelNonAlignedShBuf::Base() |
|
1153 { |
|
1154 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShBuf::Base()")); |
|
1155 |
|
1156 TUint8* base = reinterpret_cast<DMemModelNonAlignedShPool*>(iPool)->Base(); |
|
1157 |
|
1158 return base ? base + iRelAddress : NULL; |
|
1159 } |
|
1160 |
|
1161 TInt DMemModelNonAlignedShBuf::Map(TUint /* aMapAttr */, DProcess* /* aProcess */, TLinAddr& /* aBase */) |
|
1162 { |
|
1163 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShBuf::Map()")); |
|
1164 |
|
1165 return KErrNotSupported; |
|
1166 } |
|
1167 |
|
1168 TInt DMemModelNonAlignedShBuf::UnMap(DProcess* /* aProcess */) |
|
1169 { |
|
1170 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShBuf::UnMap()")); |
|
1171 |
|
1172 return KErrNotSupported; |
|
1173 } |
|
1174 |
|
1175 TInt DMemModelNonAlignedShBuf::Pin(TPhysicalPinObject* aPinObject, TBool aReadOnly, TPhysAddr& aAddress, TPhysAddr* aPages, TUint32& aMapAttr, TUint& aColour) |
|
1176 { |
|
1177 CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"DMemModelNonAlignedShBuf::Pin"); |
|
1178 |
|
1179 DMemModelNonAlignedShPool* pool = reinterpret_cast<DMemModelNonAlignedShPool*>(iPool); |
|
1180 |
|
1181 NKern::ThreadEnterCS(); |
|
1182 |
|
1183 TInt startPage = iRelAddress >> KPageShift; |
|
1184 TInt lastPage = MM::RoundToPageCount(iRelAddress + Size()); |
|
1185 |
|
1186 TInt pages = lastPage - startPage; |
|
1187 |
|
1188 if (!pages) pages++; |
|
1189 |
|
1190 TInt r = MM::PinPhysicalMemory(pool->iMemoryObject, (DPhysicalPinMapping*)aPinObject, |
|
1191 startPage, pages, aReadOnly, aAddress, aPages, aMapAttr, aColour); |
|
1192 |
|
1193 // adjust physical address to start of the buffer |
|
1194 if (r == KErrNone) |
|
1195 { |
|
1196 aAddress += (iRelAddress - (startPage << KPageShift)); |
|
1197 } |
|
1198 NKern::ThreadLeaveCS(); |
|
1199 return r; |
|
1200 } |
|
1201 |
|
1202 DMemModelNonAlignedShPool::DMemModelNonAlignedShPool() : DMemModelShPool() |
|
1203 { |
|
1204 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::DMemModelNonAlignedShPool")); |
|
1205 } |
|
1206 |
|
1207 DMemModelNonAlignedShPool::~DMemModelNonAlignedShPool() |
|
1208 { |
|
1209 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::~DMemModelNonAlignedShPool")); |
|
1210 |
|
1211 MM::MemoryDestroy(iMemoryObject); |
|
1212 |
|
1213 delete iPagesMap; |
|
1214 delete iBufMap; |
|
1215 } |
|
1216 |
|
1217 TInt DMemModelNonAlignedShPool::DoCreate(TShPoolCreateInfo& aInfo) |
|
1218 { |
|
1219 __KTRACE_OPT(KMMU, Kern::Printf("DMemModelNonAlignedShPool::DoCreate(%d, %d, %d)", aInfo.iInfo.iMaxBufs, iBufGap, iBufSize)); |
|
1220 |
|
1221 TInt r; |
|
1222 TUint64 maxSize64 = static_cast<TUint64>(aInfo.iInfo.iMaxBufs) * static_cast<TUint64>(iBufGap); |
|
1223 |
|
1224 if (maxSize64 > static_cast<TUint64>(KMaxTInt) || maxSize64 <= static_cast<TUint64>(0)) |
|
1225 return KErrArgument; |
|
1226 |
|
1227 TInt maxPages = MM::RoundToPageCount(static_cast<TInt>(maxSize64)); |
|
1228 |
|
1229 iBufMap = TBitMapAllocator::New(aInfo.iInfo.iMaxBufs, (TBool)ETrue); |
|
1230 if (iBufMap == NULL) |
|
1231 return KErrNoMemory; |
|
1232 |
|
1233 iPagesMap = TBitMapAllocator::New(maxPages, (TBool)ETrue); |
|
1234 if (iPagesMap == NULL) |
|
1235 return KErrNoMemory; |
|
1236 |
|
1237 // Memory attributes |
|
1238 TMemoryAttributes attr = EMemoryAttributeStandard; |
|
1239 |
|
1240 // Memory type |
|
1241 TMemoryObjectType memoryType = (iPoolFlags & EShPoolPhysicalMemoryPool) ? EMemoryObjectHardware : EMemoryObjectUnpaged; |
|
1242 |
|
1243 // Memory flags |
|
1244 TMemoryCreateFlags memoryFlags = EMemoryCreateDefault; // Don't leave previous contents of memory |
|
1245 |
|
1246 // Now create the memory object |
|
1247 r = MM::MemoryNew(iMemoryObject, memoryType, maxPages, memoryFlags, attr); |
|
1248 if (r != KErrNone) |
|
1249 return r; |
|
1250 |
|
1251 // Make sure we give the caller the number of buffers they were expecting |
|
1252 iCommittedPages = MM::RoundToPageCount(iInitialBuffers * iBufGap); |
|
1253 |
|
1254 if (iPoolFlags & EShPoolPhysicalMemoryPool) |
|
1255 { |
|
1256 __KTRACE_OPT(KMMU, Kern::Printf("DMemModelNonAlignedShPool::DoCreate(iCommittedPages = 0x%08x, aInfo.iPhysAddr.iPhysAddrList = 0x%08x )", iCommittedPages, aInfo.iPhysAddr.iPhysAddrList)); |
|
1257 if (iPoolFlags & EShPoolContiguous) |
|
1258 { |
|
1259 r = MM::MemoryAddContiguous(iMemoryObject, 0, iCommittedPages, aInfo.iPhysAddr.iPhysAddr); |
|
1260 } |
|
1261 else |
|
1262 { |
|
1263 r = MM::MemoryAddPages(iMemoryObject, 0, iCommittedPages, aInfo.iPhysAddr.iPhysAddrList); |
|
1264 } |
|
1265 |
|
1266 iMaxPages = iCommittedPages; |
|
1267 } |
|
1268 else |
|
1269 { |
|
1270 __KTRACE_OPT(KMMU, Kern::Printf("DMemModelNonAlignedShPool::DoCreate(iCommittedPages = %d, contig = %d)", iCommittedPages, iPoolFlags & EShPoolContiguous)); |
|
1271 |
|
1272 if (iPoolFlags & EShPoolContiguous) |
|
1273 { |
|
1274 TPhysAddr paddr; |
|
1275 r = MM::MemoryAllocContiguous(iMemoryObject, 0, iCommittedPages, 0, paddr); |
|
1276 } |
|
1277 else |
|
1278 { |
|
1279 r = MM::MemoryAlloc(iMemoryObject, 0, iCommittedPages); |
|
1280 } |
|
1281 |
|
1282 iMaxPages = maxPages; |
|
1283 } |
|
1284 |
|
1285 iPagesMap->Alloc(0, iCommittedPages); |
|
1286 |
|
1287 return r; |
|
1288 } |
|
1289 |
|
1290 TUint8* DMemModelNonAlignedShPool::Base(DProcess* aProcess) |
|
1291 { |
|
1292 TUint8 *base = 0; |
|
1293 |
|
1294 LockPool(); |
|
1295 DMemModelNonAlignedShPoolClient* client = reinterpret_cast<DMemModelNonAlignedShPoolClient*>(iClientMap->Find(reinterpret_cast<TUint>(aProcess))); |
|
1296 |
|
1297 __NK_ASSERT_DEBUG(client); // ASSERT because pool must be already opened in the clients address space |
|
1298 __NK_ASSERT_DEBUG(client->iMapping); // ASSERT because non-aligned buffers are mapped by default in user space |
|
1299 |
|
1300 base = reinterpret_cast<TUint8*>(MM::MappingBase(client->iMapping)); |
|
1301 |
|
1302 UnlockPool(); |
|
1303 |
|
1304 return base; |
|
1305 } |
|
1306 |
|
1307 TInt DMemModelNonAlignedShPool::CreateInitialBuffers() |
|
1308 { |
|
1309 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::CreateInitialBuffers")); |
|
1310 |
|
1311 iInitialBuffersArray = reinterpret_cast<DMemModelNonAlignedShBuf*>(Kern::Alloc(iInitialBuffers * sizeof(DMemModelNonAlignedShBuf))); |
|
1312 |
|
1313 if (iInitialBuffersArray == NULL) |
|
1314 return KErrNoMemory; |
|
1315 |
|
1316 TLinAddr offset = 0; |
|
1317 for (TUint i = 0; i < iInitialBuffers; i++) |
|
1318 { |
|
1319 DMemModelNonAlignedShBuf *buf = new (&iInitialBuffersArray[i]) DMemModelNonAlignedShBuf(this, offset); |
|
1320 TInt r = buf->Construct(); |
|
1321 |
|
1322 if (r == KErrNone) |
|
1323 { |
|
1324 iFreeList.Add(&buf->iObjLink); |
|
1325 } |
|
1326 else |
|
1327 { |
|
1328 iInitialBuffers = i; |
|
1329 return KErrNoMemory; |
|
1330 } |
|
1331 |
|
1332 offset += iBufGap; |
|
1333 } |
|
1334 |
|
1335 iFreeBuffers = iInitialBuffers; |
|
1336 iTotalBuffers = iInitialBuffers; |
|
1337 iBufMap->Alloc(0, iInitialBuffers); |
|
1338 |
|
1339 return KErrNone; |
|
1340 } |
|
1341 |
|
1342 TInt DMemModelNonAlignedShPool::AddToProcess(DProcess* aProcess, TUint aAttr) |
|
1343 { |
|
1344 // Must be in critical section so we don't leak os asid references. |
|
1345 __ASSERT_CRITICAL; |
|
1346 __KTRACE_OPT(KMMU, Kern::Printf("Adding DMemModelShPool %O to process %O", this, aProcess)); |
|
1347 |
|
1348 DMemoryMapping* mapping = NULL; |
|
1349 |
|
1350 TBool write = (TBool)EFalse; |
|
1351 |
|
1352 // User = ETrue, ReadOnlyWrite = ETrue, Execute = EFalse |
|
1353 if (aAttr & EShPoolWriteable) |
|
1354 write = (TBool)ETrue; |
|
1355 |
|
1356 TMappingPermissions perm = MM::MappingPermissions(ETrue, // user |
|
1357 write, // writeable |
|
1358 EFalse); // execute |
|
1359 |
|
1360 TMappingCreateFlags mappingFlags = EMappingCreateDefault; |
|
1361 |
|
1362 DMemModelProcess* pP = reinterpret_cast<DMemModelProcess*>(aProcess); |
|
1363 |
|
1364 Kern::MutexWait(*iProcessLock); |
|
1365 TInt r = KErrNone; |
|
1366 |
|
1367 LockPool(); |
|
1368 DMemModelNonAlignedShPoolClient* client = reinterpret_cast<DMemModelNonAlignedShPoolClient*>(iClientMap->Find(reinterpret_cast<TUint>(aProcess))); |
|
1369 UnlockPool(); |
|
1370 |
|
1371 if (!client) |
|
1372 { |
|
1373 client = new DMemModelNonAlignedShPoolClient; |
|
1374 |
|
1375 if (client) |
|
1376 { |
|
1377 // map non aligned pools in userside processes by default |
|
1378 if (aAttr & EShPoolAutoMapBuf || pP != K::TheKernelProcess) |
|
1379 { |
|
1380 // Open a reference on the os asid so it doesn't get freed and reused. |
|
1381 TInt osAsid = pP->TryOpenOsAsid(); |
|
1382 if (osAsid < 0) |
|
1383 {// The process freed its os asid so can't create a new mapping. |
|
1384 r = KErrDied; |
|
1385 } |
|
1386 else |
|
1387 { |
|
1388 r = MM::MappingNew(mapping, iMemoryObject, perm, osAsid, mappingFlags); |
|
1389 // Close the reference as the mapping will be destroyed if the process dies. |
|
1390 pP->CloseOsAsid(); |
|
1391 } |
|
1392 |
|
1393 if ((r == KErrNone) && (pP == K::TheKernelProcess)) |
|
1394 { |
|
1395 iBaseAddress = MM::MappingBase(mapping); |
|
1396 } |
|
1397 } |
|
1398 |
|
1399 if (r == KErrNone) |
|
1400 { |
|
1401 client->iMapping = mapping; |
|
1402 client->iFlags = aAttr; |
|
1403 r = iClientMap->Add(reinterpret_cast<TUint>(aProcess), client); |
|
1404 |
|
1405 if (r == KErrNone) |
|
1406 { |
|
1407 if (pP != K::TheKernelProcess) |
|
1408 { |
|
1409 r = aProcess->iHandles.Reserve(iTotalBuffers); |
|
1410 |
|
1411 if (r != KErrNone) |
|
1412 { |
|
1413 iClientMap->Remove(reinterpret_cast<TUint>(aProcess)); |
|
1414 } |
|
1415 } |
|
1416 } |
|
1417 |
|
1418 if (r != KErrNone) |
|
1419 { |
|
1420 delete client; |
|
1421 MM::MappingDestroy(mapping); |
|
1422 } |
|
1423 } |
|
1424 else |
|
1425 { |
|
1426 delete client; |
|
1427 } |
|
1428 } |
|
1429 else |
|
1430 { |
|
1431 r = KErrNoMemory; |
|
1432 } |
|
1433 } |
|
1434 else |
|
1435 { |
|
1436 LockPool(); |
|
1437 client->iAccessCount++; |
|
1438 UnlockPool(); |
|
1439 } |
|
1440 |
|
1441 Kern::MutexSignal(*iProcessLock); |
|
1442 |
|
1443 return r; |
|
1444 } |
|
1445 |
|
1446 TInt DMemModelNonAlignedShPool::DeleteInitialBuffers() |
|
1447 { |
|
1448 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::DeleteInitialBuffers")); |
|
1449 |
|
1450 if (iInitialBuffersArray != NULL) |
|
1451 { |
|
1452 for (TUint i = 0; i < iInitialBuffers; i++) |
|
1453 { |
|
1454 iInitialBuffersArray[i].iObjLink.Deque(); // remove from free list |
|
1455 iInitialBuffersArray[i].Dec(); |
|
1456 iInitialBuffersArray[i].~DMemModelNonAlignedShBuf(); |
|
1457 } |
|
1458 } |
|
1459 |
|
1460 Kern::Free(iInitialBuffersArray); |
|
1461 iInitialBuffersArray = NULL; |
|
1462 |
|
1463 return KErrNone; |
|
1464 } |
|
1465 |
|
1466 TInt DMemModelNonAlignedShPool::DestroyAllMappingsAndReservedHandles(DProcess* aProcess) |
|
1467 { |
|
1468 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::DestroyAllMappingsAndReservedHandles(0x%08x)", aProcess)); |
|
1469 |
|
1470 TInt r = KErrNone; |
|
1471 Kern::MutexWait(*iProcessLock); |
|
1472 DMemModelNonAlignedShPoolClient* client = reinterpret_cast<DMemModelNonAlignedShPoolClient*>(iClientMap->Remove(reinterpret_cast<TUint>(aProcess))); |
|
1473 |
|
1474 __NK_ASSERT_DEBUG(client); |
|
1475 __NK_ASSERT_DEBUG(client->iAccessCount == 0); |
|
1476 |
|
1477 if (client->iMapping) |
|
1478 { |
|
1479 MM::MappingDestroy(client->iMapping); |
|
1480 } |
|
1481 delete client; |
|
1482 |
|
1483 if (aProcess != K::TheKernelProcess) |
|
1484 { |
|
1485 // Remove reserved handles |
|
1486 r = aProcess->iHandles.Reserve(-(iTotalBuffers)); |
|
1487 } |
|
1488 else |
|
1489 { |
|
1490 iBaseAddress = 0; |
|
1491 } |
|
1492 |
|
1493 Kern::MutexSignal(*iProcessLock); |
|
1494 |
|
1495 __KTRACE_OPT(KMMU, Kern::Printf("<DMemModelNonAlignedShPool::DestroyAllMappingsAndReservedHandles(0x%08x)", aProcess)); |
|
1496 |
|
1497 return r; |
|
1498 } |
|
1499 |
|
1500 |
|
1501 TInt DMemModelNonAlignedShPool::Close(TAny* aPtr) |
|
1502 { |
|
1503 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::Close(0x%08x)", aPtr)); |
|
1504 |
|
1505 if (aPtr) |
|
1506 { |
|
1507 DProcess* pP = reinterpret_cast<DProcess*>(aPtr); |
|
1508 |
|
1509 CloseClient(pP); |
|
1510 } |
|
1511 |
|
1512 return DShPool::Close(aPtr); |
|
1513 } |
|
1514 |
|
1515 void DMemModelNonAlignedShPool::FreeBufferPages(TUint aOffset) |
|
1516 { |
|
1517 TLinAddr firstByte = aOffset; // offset of first byte in buffer |
|
1518 TLinAddr lastByte = firstByte+iBufGap-1; // offset of last byte in buffer |
|
1519 TUint firstPage = firstByte>>KPageShift; // index of first page containing part of the buffer |
|
1520 TUint lastPage = lastByte>>KPageShift; // index of last page containing part of the buffer |
|
1521 |
|
1522 TUint firstBuffer = (firstByte&~KPageMask)/iBufGap; // index of first buffer which lies in firstPage |
|
1523 TUint lastBuffer = (lastByte|KPageMask)/iBufGap; // index of last buffer which lies in lastPage |
|
1524 TUint thisBuffer = firstByte/iBufGap; // index of the buffer to be freed |
|
1525 |
|
1526 // Ensure lastBuffer is within bounds (there may be room in the last |
|
1527 // page for more buffers than we have allocated). |
|
1528 if (lastBuffer >= iMaxBuffers) |
|
1529 lastBuffer = iMaxBuffers-1; |
|
1530 |
|
1531 if(firstBuffer!=thisBuffer && iBufMap->NotFree(firstBuffer,thisBuffer-firstBuffer)) |
|
1532 { |
|
1533 // first page has other allocated buffers in it, |
|
1534 // so we can't free it and must move on to next one... |
|
1535 if (firstPage >= lastPage) |
|
1536 return; |
|
1537 ++firstPage; |
|
1538 } |
|
1539 |
|
1540 if(lastBuffer!=thisBuffer && iBufMap->NotFree(thisBuffer+1,lastBuffer-thisBuffer)) |
|
1541 { |
|
1542 // last page has other allocated buffers in it, |
|
1543 // so we can't free it and must step back to previous one... |
|
1544 if (lastPage <= firstPage) |
|
1545 return; |
|
1546 --lastPage; |
|
1547 } |
|
1548 |
|
1549 if(firstPage<=lastPage) |
|
1550 { |
|
1551 // we can free pages firstPage trough to lastPage... |
|
1552 TUint numPages = lastPage-firstPage+1; |
|
1553 iPagesMap->SelectiveFree(firstPage,numPages); |
|
1554 MM::MemoryLock(iMemoryObject); |
|
1555 MM::MemoryFree(iMemoryObject, firstPage, numPages); |
|
1556 MM::MemoryUnlock(iMemoryObject); |
|
1557 iCommittedPages -= numPages; |
|
1558 } |
|
1559 } |
|
1560 |
|
1561 TInt DMemModelNonAlignedShPool::GrowPool() |
|
1562 { |
|
1563 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::GrowPool()")); |
|
1564 |
|
1565 // Don't do anything with physical memory pools |
|
1566 if (iPoolFlags & EShPoolPhysicalMemoryPool) |
|
1567 return KErrNone; |
|
1568 |
|
1569 Kern::MutexWait(*iProcessLock); |
|
1570 |
|
1571 TUint32 headroom = iMaxBuffers - iTotalBuffers; |
|
1572 |
|
1573 // How many buffers to grow by? |
|
1574 TUint32 grow = mult_fx248(iTotalBuffers, iGrowByRatio); |
|
1575 if (grow == 0) // Handle round-to-zero |
|
1576 grow = 1; |
|
1577 if (grow > headroom) |
|
1578 grow = headroom; |
|
1579 |
|
1580 TInt r = KErrNone; |
|
1581 SDblQue temp; |
|
1582 |
|
1583 TUint i; |
|
1584 for (i = 0; i < grow; ++i) |
|
1585 { |
|
1586 TInt offset = iBufMap->Alloc(); |
|
1587 |
|
1588 if (offset < 0) |
|
1589 { |
|
1590 r = KErrNoMemory; |
|
1591 break; |
|
1592 } |
|
1593 |
|
1594 offset *= iBufGap; |
|
1595 |
|
1596 TInt lastPage = (offset + iBufSize - 1) >> KPageShift; |
|
1597 |
|
1598 // Allocate one page at a time. |
|
1599 for (TInt page = offset >> KPageShift; page <= lastPage; ++page) |
|
1600 { |
|
1601 // Is the page allocated? |
|
1602 if (iPagesMap->NotAllocated(page, 1)) |
|
1603 { |
|
1604 MM::MemoryLock(iMemoryObject); |
|
1605 r = MM::MemoryAlloc(iMemoryObject, page, 1); |
|
1606 MM::MemoryUnlock(iMemoryObject); |
|
1607 |
|
1608 if (r != KErrNone) |
|
1609 { |
|
1610 break; |
|
1611 } |
|
1612 |
|
1613 ++iCommittedPages; |
|
1614 iPagesMap->Alloc(page, 1); |
|
1615 } |
|
1616 } |
|
1617 |
|
1618 if (r != KErrNone) |
|
1619 { |
|
1620 iBufMap->Free(offset / iBufGap); |
|
1621 FreeBufferPages(offset); |
|
1622 break; |
|
1623 } |
|
1624 |
|
1625 DMemModelNonAlignedShBuf *buf = new DMemModelNonAlignedShBuf(this, offset); |
|
1626 |
|
1627 if (buf == NULL) |
|
1628 { |
|
1629 iBufMap->Free(offset / iBufGap); |
|
1630 FreeBufferPages(offset); |
|
1631 r = KErrNoMemory; |
|
1632 break; |
|
1633 } |
|
1634 |
|
1635 r = buf->Construct(); |
|
1636 |
|
1637 if (r != KErrNone) |
|
1638 { |
|
1639 iBufMap->Free(offset / iBufGap); |
|
1640 FreeBufferPages(offset); |
|
1641 buf->DObject::Close(NULL); |
|
1642 break; |
|
1643 } |
|
1644 |
|
1645 temp.Add(&buf->iObjLink); |
|
1646 } |
|
1647 |
|
1648 r = UpdateReservedHandles(i); |
|
1649 |
|
1650 if (r == KErrNone) |
|
1651 { |
|
1652 LockPool(); |
|
1653 iFreeList.MoveFrom(&temp); |
|
1654 iFreeBuffers += i; |
|
1655 iTotalBuffers += i; |
|
1656 UnlockPool(); |
|
1657 } |
|
1658 else |
|
1659 { |
|
1660 // couldn't reserve handles so have no choice but to |
|
1661 // delete the buffers |
|
1662 __KTRACE_OPT(KMMU, Kern::Printf("GrowPool failed with %d, deleting buffers", r)); |
|
1663 SDblQueLink *pLink; |
|
1664 while ((pLink = temp.GetFirst()) != NULL) |
|
1665 { |
|
1666 DShBuf* buf = _LOFF(pLink, DShBuf, iObjLink); |
|
1667 TLinAddr offset = buf->iRelAddress; |
|
1668 iBufMap->Free(offset / iBufGap); |
|
1669 FreeBufferPages(offset); |
|
1670 buf->DObject::Close(NULL); |
|
1671 } |
|
1672 __KTRACE_OPT(KMMU, Kern::Printf("Buffers deleted")); |
|
1673 } |
|
1674 |
|
1675 CalculateGrowShrinkTriggers(); |
|
1676 |
|
1677 Kern::MutexSignal(*iProcessLock); |
|
1678 |
|
1679 __KTRACE_OPT(KMMU, Kern::Printf("<DMemModelNonAlignedShPool::GrowPool()")); |
|
1680 return r; |
|
1681 } |
|
1682 |
|
1683 TInt DMemModelNonAlignedShPool::ShrinkPool() |
|
1684 { |
|
1685 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::ShrinkPool()")); |
|
1686 |
|
1687 // Don't do anything with physical memory pools |
|
1688 if (iPoolFlags & EShPoolPhysicalMemoryPool) |
|
1689 return KErrNone; |
|
1690 |
|
1691 Kern::MutexWait(*iProcessLock); |
|
1692 |
|
1693 TUint32 grownBy = iTotalBuffers - iInitialBuffers; |
|
1694 |
|
1695 // How many buffers to shrink by? |
|
1696 TUint32 shrink = mult_fx248(iTotalBuffers, iShrinkByRatio); |
|
1697 if (shrink == 0) // Handle round-to-zero |
|
1698 shrink = 1; |
|
1699 if (shrink > grownBy) |
|
1700 shrink = grownBy; |
|
1701 if (shrink > iFreeBuffers) |
|
1702 shrink = iFreeBuffers; |
|
1703 |
|
1704 TUint i; |
|
1705 for (i = 0; i < shrink; ++i) |
|
1706 { |
|
1707 LockPool(); |
|
1708 |
|
1709 if (iFreeList.IsEmpty()) |
|
1710 { |
|
1711 UnlockPool(); |
|
1712 break; |
|
1713 } |
|
1714 |
|
1715 // work from the back of the queue |
|
1716 SDblQueLink *pLink = iFreeList.Last(); |
|
1717 |
|
1718 DShBuf* pBuf = _LOFF(pLink, DShBuf, iObjLink); |
|
1719 |
|
1720 if (pBuf >= iInitialBuffersArray && pBuf < (iInitialBuffersArray + iInitialBuffers)) |
|
1721 { |
|
1722 UnlockPool(); |
|
1723 break; |
|
1724 } |
|
1725 |
|
1726 --iFreeBuffers; |
|
1727 --iTotalBuffers; |
|
1728 pLink->Deque(); |
|
1729 UnlockPool(); |
|
1730 |
|
1731 TLinAddr offset = pBuf->iRelAddress; |
|
1732 iBufMap->Free(offset / iBufGap); |
|
1733 FreeBufferPages(offset); |
|
1734 |
|
1735 pBuf->DObject::Close(NULL); |
|
1736 } |
|
1737 |
|
1738 UpdateReservedHandles(-(TInt)i); |
|
1739 |
|
1740 // If we couldn't shrink the pool by this many buffers, wait until we Free() another |
|
1741 // buffer before trying to shrink again. |
|
1742 if (i < shrink) |
|
1743 iPoolFlags |= EShPoolSuppressShrink; |
|
1744 |
|
1745 CalculateGrowShrinkTriggers(); |
|
1746 |
|
1747 Kern::MutexSignal(*iProcessLock); |
|
1748 |
|
1749 __KTRACE_OPT(KMMU, Kern::Printf("<DMemModelNonAlignedShPool::ShrinkPool()")); |
|
1750 |
|
1751 return KErrNone; |
|
1752 } |
|
1753 |
|
1754 TInt DMemModelNonAlignedShPool::UpdateFreeList() |
|
1755 { |
|
1756 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::UpdateFreeList")); |
|
1757 |
|
1758 SDblQue temp; |
|
1759 |
|
1760 LockPool(); |
|
1761 while(!iAltFreeList.IsEmpty()) |
|
1762 { |
|
1763 // sort a temporary list of 'n' object with the lowest index first |
|
1764 for (TInt n = 0; n < 8 && !iAltFreeList.IsEmpty(); ++n) |
|
1765 { |
|
1766 // bit of an assumption, lets assume that the lower indexes will be allocated and freed first |
|
1767 // and therefore will be nearer the front of the list |
|
1768 DShBuf* buf = _LOFF(iAltFreeList.GetFirst(), DShBuf, iObjLink); |
|
1769 |
|
1770 SDblQueLink* anchor = reinterpret_cast<SDblQueLink*>(&temp); |
|
1771 SDblQueLink* pLink = temp.Last(); |
|
1772 |
|
1773 while (ETrue) |
|
1774 { |
|
1775 // traverse the list starting at the back |
|
1776 if ((pLink != anchor) && (_LOFF(pLink, DShBuf, iObjLink)->iRelAddress > buf->iRelAddress)) |
|
1777 { |
|
1778 pLink = pLink->iPrev; |
|
1779 } |
|
1780 else |
|
1781 { |
|
1782 buf->iObjLink.InsertAfter(pLink); |
|
1783 break; |
|
1784 } |
|
1785 } |
|
1786 } |
|
1787 |
|
1788 // now merge with the free list |
|
1789 while(!temp.IsEmpty()) |
|
1790 { |
|
1791 if (iFreeList.IsEmpty()) |
|
1792 { |
|
1793 iFreeList.MoveFrom(&temp); |
|
1794 break; |
|
1795 } |
|
1796 |
|
1797 // working backwards with the highest index |
|
1798 DShBuf* buf = _LOFF(temp.Last(), DShBuf, iObjLink); |
|
1799 SDblQueLink* anchor = reinterpret_cast<SDblQueLink*>(&iFreeList); |
|
1800 SDblQueLink* pLink = iFreeList.Last(); |
|
1801 |
|
1802 while (!NKern::FMFlash(&iLock)) |
|
1803 { |
|
1804 if ((pLink != anchor) && (_LOFF(pLink, DShBuf, iObjLink)->iRelAddress > buf->iRelAddress)) |
|
1805 { |
|
1806 pLink = pLink->iPrev; |
|
1807 } |
|
1808 else |
|
1809 { |
|
1810 buf->iObjLink.Deque(); |
|
1811 buf->iObjLink.InsertAfter(pLink); |
|
1812 // next buffer |
|
1813 if (temp.IsEmpty()) |
|
1814 break; |
|
1815 buf = _LOFF(temp.Last(), DShBuf, iObjLink); |
|
1816 } |
|
1817 } |
|
1818 } |
|
1819 NKern::FMFlash(&iLock); |
|
1820 } |
|
1821 UnlockPool(); |
|
1822 |
|
1823 __KTRACE_OPT(KMMU, Kern::Printf("<DMemModelNonAlignedShPool::UpdateFreeList")); |
|
1824 return KErrNone; |
|
1825 } |
|
1826 |
|
1827 void DMemModelNonAlignedShPool::Free(DShBuf* aBuf) |
|
1828 { |
|
1829 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::Free (aBuf = 0x%08x, aBuf->Base() 0x%08x)", aBuf, aBuf->iRelAddress)); |
|
1830 |
|
1831 LockPool(); |
|
1832 #ifdef _DEBUG |
|
1833 // Remove from allocated list |
|
1834 aBuf->iObjLink.Deque(); |
|
1835 #endif |
|
1836 |
|
1837 // we want to put the initial buffers at the head of the free list |
|
1838 // and the grown buffers at the tail as this makes shrinking more efficient |
|
1839 if (aBuf >= iInitialBuffersArray && aBuf < (iInitialBuffersArray + iInitialBuffers)) |
|
1840 { |
|
1841 iFreeList.AddHead(&aBuf->iObjLink); |
|
1842 } |
|
1843 else |
|
1844 { |
|
1845 iAltFreeList.Add(&aBuf->iObjLink); |
|
1846 } |
|
1847 |
|
1848 ++iFreeBuffers; |
|
1849 #ifdef _DEBUG |
|
1850 --iAllocatedBuffers; |
|
1851 #endif |
|
1852 iPoolFlags &= ~EShPoolSuppressShrink; // Allow shrinking again, if it was blocked |
|
1853 UnlockPool(); |
|
1854 |
|
1855 // queue ManagementDfc which completes notifications as appropriate |
|
1856 if (HaveWorkToDo()) |
|
1857 KickManagementDfc(); |
|
1858 |
|
1859 DShPool::Close(NULL); // decrement pool reference count |
|
1860 } |
|
1861 |
|
1862 // Kernel side API |
|
1863 TInt DMemModelNonAlignedShPool::Alloc(DShBuf*& aShBuf) |
|
1864 { |
|
1865 __KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::Alloc (DShBuf)")); |
|
1866 |
|
1867 aShBuf = NULL; |
|
1868 |
|
1869 LockPool(); |
|
1870 |
|
1871 if (!iFreeList.IsEmpty()) |
|
1872 { |
|
1873 aShBuf = _LOFF(iFreeList.GetFirst(), DShBuf, iObjLink); |
|
1874 #ifdef _DEBUG |
|
1875 iAllocated.Add(&aShBuf->iObjLink); |
|
1876 iAllocatedBuffers++; |
|
1877 #endif |
|
1878 } |
|
1879 else |
|
1880 { |
|
1881 // try alternative free list |
|
1882 if (!iAltFreeList.IsEmpty()) |
|
1883 { |
|
1884 aShBuf = _LOFF(iAltFreeList.GetFirst(), DShBuf, iObjLink); |
|
1885 #ifdef _DEBUG |
|
1886 iAllocated.Add(&aShBuf->iObjLink); |
|
1887 iAllocatedBuffers++; |
|
1888 #endif |
|
1889 } |
|
1890 else |
|
1891 { |
|
1892 UnlockPool(); |
|
1893 KickManagementDfc(); // Try to grow |
|
1894 return KErrNoMemory; |
|
1895 } |
|
1896 } |
|
1897 |
|
1898 --iFreeBuffers; |
|
1899 Open(); // increment pool reference count |
|
1900 |
|
1901 UnlockPool(); |
|
1902 |
|
1903 if (HaveWorkToDo()) |
|
1904 KickManagementDfc(); |
|
1905 |
|
1906 __KTRACE_OPT(KMMU, Kern::Printf("<DMemModelNonAlignedShPool::Alloc return buf = 0x%08x", aShBuf)); |
|
1907 return KErrNone; |
|
1908 } |