|
1 // Copyright (c) 2003-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\personality\example\personality.cpp |
|
15 // Example RTOS personality. |
|
16 // |
|
17 // |
|
18 |
|
19 #include "personality_int.h" |
|
20 |
|
21 /****************************************************************************** |
|
22 * Memory pool management |
|
23 ******************************************************************************/ |
|
24 |
|
25 // Create a single memory pool consisting of a specified number of equal sized blocks. |
|
26 TInt PMemPool::Create(const poolinfo* aInfo) |
|
27 { |
|
28 iBlockSize = aInfo->block_size; |
|
29 TUint bsize = iBlockSize + sizeof(PMemPool*); |
|
30 TInt n = (TInt)aInfo->block_count; |
|
31 __KTRACE_OPT(KBOOT, Kern::Printf("PMemPool::Create %08x iBlockSize=%04x bsize=%04x n=%04x", this, iBlockSize, bsize, n)); |
|
32 if (bsize < sizeof(SMemBlock) || (bsize & 3)) |
|
33 return KErrArgument; |
|
34 TInt total_size = n * bsize; |
|
35 iFirstFree = (SMemBlock*)Kern::Alloc(total_size); |
|
36 __KTRACE_OPT(KBOOT, Kern::Printf("PMemPool::Create %08x iFirstFree=%08x", this, iFirstFree)); |
|
37 if (!iFirstFree) |
|
38 return KErrNoMemory; |
|
39 TInt i; |
|
40 for (i=0; i<n; ++i) |
|
41 { |
|
42 SMemBlock* p = (SMemBlock*)(TLinAddr(iFirstFree) + i*bsize); |
|
43 SMemBlock* q = (i<n-1) ? (SMemBlock*)(TLinAddr(p) + bsize) : NULL; |
|
44 p->iPool = this; |
|
45 p->iNext = q; |
|
46 } |
|
47 __KTRACE_OPT(KBOOT, Kern::Printf("PMemPool::Create OK")); |
|
48 return KErrNone; |
|
49 } |
|
50 |
|
51 // Call with interrupts disabled |
|
52 void* PMemPool::Alloc() |
|
53 { |
|
54 SMemBlock* p = iFirstFree; |
|
55 if (p) |
|
56 { |
|
57 iFirstFree = p->iNext; |
|
58 __KTRACE_OPT(KBOOT, Kern::Printf("AL:%08x->%08x", this, &p->iNext)); |
|
59 return &p->iNext; |
|
60 } |
|
61 __KTRACE_OPT(KBOOT, Kern::Printf("AL:%08x->0", this)); |
|
62 return NULL; |
|
63 } |
|
64 |
|
65 // Call with interrupts disabled |
|
66 void PMemPool::Free(void* aBlock) |
|
67 { |
|
68 __KTRACE_OPT(KBOOT, Kern::Printf("FR:%08x<-%08x", this, aBlock)); |
|
69 SMemBlock* b = (SMemBlock*)aBlock; |
|
70 __NK_ASSERT_DEBUG(b->iPool==this); |
|
71 b->iNext = iFirstFree; |
|
72 iFirstFree = b; |
|
73 } |
|
74 |
|
75 PMemMgr* PMemMgr::TheMgr; |
|
76 |
|
77 // Create a 'size bucket' memory manager consisting of a number of memory pools |
|
78 // each containing blocks of the same size. The block size increases from one |
|
79 // pool to the next. |
|
80 void PMemMgr::Create(const poolinfo* aInfo) |
|
81 { |
|
82 TInt n; |
|
83 for (n=0; aInfo[n].block_size; ++n) {} |
|
84 PMemMgr* m = (PMemMgr*)Kern::Alloc(sizeof(PMemMgr) + (n-1)*sizeof(PMemPool)); |
|
85 __KTRACE_OPT(KBOOT, Kern::Printf("PMemMgr::Create %08x NumPools=%d", m, n)); |
|
86 __NK_ASSERT_ALWAYS(m!=NULL); |
|
87 m->iPoolCount = n; |
|
88 TInt i; |
|
89 size_t prev_sz=0; |
|
90 for (i=0; i<n; ++i) |
|
91 { |
|
92 __NK_ASSERT_ALWAYS(aInfo[i].block_size > prev_sz); |
|
93 prev_sz = aInfo[i].block_size; |
|
94 TInt r = m->iPools[i].Create(aInfo+i); |
|
95 __NK_ASSERT_ALWAYS(r==KErrNone); |
|
96 } |
|
97 TheMgr = m; |
|
98 } |
|
99 |
|
100 // Allocate a memory block of the requested size (or the next larger size if necessary). |
|
101 void* PMemMgr::Alloc(size_t aSize) |
|
102 { |
|
103 __KTRACE_OPT(KBOOT, Kern::Printf("MA:%04x", aSize)); |
|
104 void* b = NULL; |
|
105 PMemPool* p = &TheMgr->iPools[0]; |
|
106 PMemPool* q = p + TheMgr->iPoolCount; |
|
107 for (; p<q && p->iBlockSize < aSize; ++p) {} |
|
108 if (p < q) |
|
109 { |
|
110 TInt irq = NKern::DisableAllInterrupts(); |
|
111 b = p->Alloc(); |
|
112 NKern::RestoreInterrupts(irq); |
|
113 } |
|
114 return b; |
|
115 } |
|
116 |
|
117 // Free a memory block |
|
118 void PMemMgr::Free(void* aPtr) |
|
119 { |
|
120 __KTRACE_OPT(KBOOT, Kern::Printf("MF:%08x", aPtr)); |
|
121 SMemBlock* b = _LOFF(aPtr, SMemBlock, iNext); |
|
122 TInt irq = NKern::DisableAllInterrupts(); |
|
123 b->iPool->Free(b); |
|
124 NKern::RestoreInterrupts(irq); |
|
125 } |
|
126 |
|
127 |
|
128 /* Memory management APIs */ |
|
129 extern "C" { |
|
130 void* alloc_mem_block(size_t size) |
|
131 { |
|
132 return PMemMgr::Alloc(size); |
|
133 } |
|
134 |
|
135 void free_mem_block(void* block) |
|
136 { |
|
137 PMemMgr::Free(block); |
|
138 } |
|
139 } |
|
140 |
|
141 /****************************************************************************** |
|
142 * Task management |
|
143 ******************************************************************************/ |
|
144 |
|
145 TInt PThread::NumTasks; |
|
146 TInt PThread::MaxTaskId; |
|
147 PThread** PThread::TaskTable; |
|
148 |
|
149 // RTOS priority to nanokernel priority mapping |
|
150 const TUint8 PThread::NThreadPriorityTable[MAX_TASK_PRIORITY+1] = |
|
151 { |
|
152 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, |
|
153 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, |
|
154 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, |
|
155 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, |
|
156 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, |
|
157 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, |
|
158 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b, |
|
159 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, |
|
160 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, |
|
161 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, |
|
162 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, |
|
163 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, |
|
164 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, |
|
165 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, 0x37, 0x37, |
|
166 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, |
|
167 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f |
|
168 }; |
|
169 |
|
170 // Handlers for personality layer threads |
|
171 const SNThreadHandlers PThread::Handlers = |
|
172 { |
|
173 NULL, // no exit handler |
|
174 &StateHandler, |
|
175 &ExceptionHandler, |
|
176 NULL // no timeout handler |
|
177 }; |
|
178 |
|
179 // Create a personality layer thread |
|
180 TInt PThread::Create(PThread*& aThread, const taskinfo* a) |
|
181 { |
|
182 if (!a->entry_pt) |
|
183 return BAD_ENTRY_POINT; |
|
184 if (a->priority < MIN_TASK_PRIORITY || a->priority > MAX_TASK_PRIORITY) |
|
185 return BAD_PRIORITY; |
|
186 if (a->stack_size & 3 || a->stack_size < MIN_STACK_SIZE) |
|
187 return BAD_STACK_SIZE; |
|
188 if (a->task_id < 0) |
|
189 return BAD_TASK_ID; |
|
190 TInt memsize = sizeof(PThread) + a->stack_size; |
|
191 PThread* t = (PThread*)Kern::Alloc(memsize); |
|
192 if (!t) |
|
193 return OUT_OF_MEMORY; |
|
194 t->iTaskId = a->task_id; |
|
195 t->iSetPriority = a->priority; |
|
196 t->iFirstMsg = NULL; |
|
197 t->iLastMsg = NULL; |
|
198 t->iISRFirstMsg = NULL; |
|
199 t->iISRLastMsg = NULL; |
|
200 new (&t->iMsgQIDfc) TDfc(&MsgQIDfcFn, t); |
|
201 TAny* stack = t + 1; |
|
202 memset(stack, 0xbb, a->stack_size); |
|
203 SNThreadCreateInfo info; |
|
204 info.iFunction = (NThreadFunction)a->entry_pt; |
|
205 info.iStackBase = stack; |
|
206 info.iStackSize = a->stack_size; |
|
207 info.iPriority = NThreadPriorityTable[a->priority]; |
|
208 info.iTimeslice = -1; // no timeslicing |
|
209 info.iAttributes = 0; |
|
210 info.iHandlers = &Handlers; |
|
211 info.iFastExecTable = NULL; |
|
212 info.iSlowExecTable = NULL; |
|
213 info.iParameterBlock = NULL; |
|
214 info.iParameterBlockSize = 0; |
|
215 TInt r = NKern::ThreadCreate(t, info); |
|
216 __NK_ASSERT_ALWAYS(r==KErrNone); |
|
217 aThread = t; |
|
218 return OK; |
|
219 } |
|
220 |
|
221 // Create all required personality layer threads |
|
222 void PThread::CreateAll(const taskinfo* a) |
|
223 { |
|
224 TInt n = 0; |
|
225 TInt maxid = -1; |
|
226 for (; a[n].entry_pt; ++n) |
|
227 { |
|
228 if (a[n].task_id > maxid) |
|
229 maxid = a[n].task_id; |
|
230 } |
|
231 NumTasks = n; |
|
232 MaxTaskId = maxid; |
|
233 TaskTable = (PThread**)Kern::AllocZ((maxid+1) * sizeof(PThread*)); |
|
234 __NK_ASSERT_ALWAYS(TaskTable != NULL); |
|
235 TInt i; |
|
236 for (i=0; i<NumTasks; ++i) |
|
237 { |
|
238 TInt r = Create(TaskTable[a[i].task_id], a+i); |
|
239 __NK_ASSERT_ALWAYS(r == KErrNone); |
|
240 } |
|
241 // resume the tasks |
|
242 for (i=0; i<NumTasks; ++i) |
|
243 { |
|
244 if (a[i].auto_start) |
|
245 NKern::ThreadResume(TaskTable[i]); |
|
246 } |
|
247 } |
|
248 |
|
249 // State handler |
|
250 void PThread::StateHandler(NThread* aThread, TInt aOp, TInt aParam) |
|
251 { |
|
252 PThread* t = (PThread*)aThread; |
|
253 switch (aOp) |
|
254 { |
|
255 case NThreadBase::ESuspend: |
|
256 t->HandleSuspend(); |
|
257 break; |
|
258 case NThreadBase::EResume: |
|
259 case NThreadBase::EForceResume: |
|
260 t->HandleResume(); |
|
261 break; |
|
262 case NThreadBase::ERelease: |
|
263 t->HandleRelease(aParam); |
|
264 break; |
|
265 case NThreadBase::EChangePriority: |
|
266 t->HandlePriorityChange(aParam); |
|
267 break; |
|
268 case NThreadBase::ETimeout: |
|
269 t->HandleTimeout(); |
|
270 break; |
|
271 case NThreadBase::ELeaveCS: |
|
272 default: |
|
273 __NK_ASSERT_ALWAYS(0); |
|
274 } |
|
275 } |
|
276 |
|
277 // Exception handler - just fault |
|
278 void PThread::ExceptionHandler(TAny* aContext, NThread* aThread) |
|
279 { |
|
280 (void)aThread; |
|
281 Exc::Fault(aContext); |
|
282 } |
|
283 |
|
284 // Post a message to this thread from an ISR |
|
285 void PThread::ISRPost(msghdr* aM) |
|
286 { |
|
287 aM->next = NULL; |
|
288 aM->sending_task_id = TASK_ID_ISR; |
|
289 msghdr* prev = (msghdr*)__e32_atomic_swp_ord_ptr(&iISRLastMsg, aM); |
|
290 if (prev) |
|
291 prev->next = aM; |
|
292 else |
|
293 { |
|
294 iISRFirstMsg = aM; |
|
295 iMsgQIDfc.Add(); |
|
296 } |
|
297 } |
|
298 |
|
299 // IDFC used to post message from ISR |
|
300 void PThread::MsgQIDfcFn(TAny* aPtr) |
|
301 { |
|
302 PThread* t = (PThread*)aPtr; |
|
303 TInt irq = NKern::DisableAllInterrupts(); |
|
304 msghdr* m = t->iISRFirstMsg; |
|
305 msghdr* l = t->iISRLastMsg; |
|
306 t->iISRFirstMsg = NULL; |
|
307 t->iISRLastMsg = NULL; |
|
308 NKern::RestoreInterrupts(irq); |
|
309 t->Post(m, l); |
|
310 } |
|
311 |
|
312 // Post a chain of messages to this thread from an IDFC or thread |
|
313 // Enter and return with preemption disabled |
|
314 void PThread::Post(msghdr* aFirst, msghdr* aLast) |
|
315 { |
|
316 msghdr* l = iLastMsg; |
|
317 iLastMsg = aLast; |
|
318 if (l) |
|
319 { |
|
320 l->next = aFirst; |
|
321 return; // queue was not empty so thread can't be waiting |
|
322 } |
|
323 iFirstMsg = aFirst; |
|
324 if (iNState == EWaitMsgQ) |
|
325 Release(KErrNone); |
|
326 } |
|
327 |
|
328 // Dequeue and return the first message if there is one |
|
329 // Return NULL if no messages waiting |
|
330 // Enter and return with preemption disabled |
|
331 msghdr* PThread::GetMsg() |
|
332 { |
|
333 msghdr* m = iFirstMsg; |
|
334 if (m) |
|
335 { |
|
336 iFirstMsg = m->next; |
|
337 if (!iFirstMsg) |
|
338 iLastMsg = NULL; |
|
339 } |
|
340 return m; |
|
341 } |
|
342 |
|
343 void PThread::HandleSuspend() |
|
344 { |
|
345 switch(iNState) |
|
346 { |
|
347 case EWaitMsgQ: |
|
348 break; |
|
349 case EWaitSemaphore: |
|
350 ((PSemaphore*)iWaitObj)->SuspendWaitingThread(this); |
|
351 break; |
|
352 default: |
|
353 __NK_ASSERT_ALWAYS(0); |
|
354 } |
|
355 } |
|
356 |
|
357 void PThread::HandleResume() |
|
358 { |
|
359 switch(iNState) |
|
360 { |
|
361 case EWaitMsgQ: |
|
362 break; |
|
363 case EWaitSemaphore: |
|
364 ((PSemaphore*)iWaitObj)->ResumeWaitingThread(this); |
|
365 break; |
|
366 default: |
|
367 __NK_ASSERT_ALWAYS(0); |
|
368 } |
|
369 } |
|
370 |
|
371 void PThread::HandleRelease(TInt aReturnCode) |
|
372 { |
|
373 (void)aReturnCode; |
|
374 switch(iNState) |
|
375 { |
|
376 case EWaitMsgQ: |
|
377 CheckSuspendThenReady(); |
|
378 break; |
|
379 case EWaitSemaphore: |
|
380 if (aReturnCode<0) |
|
381 ((PSemaphore*)iWaitObj)->WaitCancel(this); |
|
382 else |
|
383 CheckSuspendThenReady(); |
|
384 break; |
|
385 default: |
|
386 __NK_ASSERT_ALWAYS(0); |
|
387 } |
|
388 } |
|
389 |
|
390 void PThread::HandlePriorityChange(TInt aNewPriority) |
|
391 { |
|
392 (void)aNewPriority; |
|
393 switch(iNState) |
|
394 { |
|
395 case EWaitMsgQ: |
|
396 iPriority = (TUint8)aNewPriority; |
|
397 break; |
|
398 case EWaitSemaphore: |
|
399 ((PSemaphore*)iWaitObj)->ChangeWaitingThreadPriority(this, aNewPriority); |
|
400 break; |
|
401 default: |
|
402 __NK_ASSERT_ALWAYS(0); |
|
403 } |
|
404 } |
|
405 |
|
406 void PThread::HandleTimeout() |
|
407 { |
|
408 switch(iNState) |
|
409 { |
|
410 case EWaitMsgQ: |
|
411 CheckSuspendThenReady(); |
|
412 break; |
|
413 case EWaitSemaphore: |
|
414 ((PSemaphore*)iWaitObj)->WaitCancel(this); |
|
415 break; |
|
416 default: |
|
417 __NK_ASSERT_ALWAYS(0); |
|
418 } |
|
419 } |
|
420 |
|
421 |
|
422 /* Task APIs */ |
|
423 extern "C" { |
|
424 int suspend_task(int id) |
|
425 { |
|
426 if (TUint(id) > TUint(PThread::MaxTaskId)) |
|
427 return BAD_TASK_ID; |
|
428 PThread* t = PThread::TaskTable[id]; |
|
429 if (!t) |
|
430 return BAD_TASK_ID; |
|
431 NKern::ThreadSuspend(t, 1); |
|
432 return OK; |
|
433 } |
|
434 |
|
435 int resume_task(int id) |
|
436 { |
|
437 if (TUint(id) > TUint(PThread::MaxTaskId)) |
|
438 return BAD_TASK_ID; |
|
439 PThread* t = PThread::TaskTable[id]; |
|
440 if (!t) |
|
441 return BAD_TASK_ID; |
|
442 NKern::ThreadResume(t); |
|
443 return OK; |
|
444 } |
|
445 |
|
446 int get_task_priority(int id) |
|
447 { |
|
448 if (TUint(id) > TUint(PThread::MaxTaskId)) |
|
449 return BAD_TASK_ID; |
|
450 PThread* t = PThread::TaskTable[id]; |
|
451 if (!t) |
|
452 return BAD_TASK_ID; |
|
453 return t->iSetPriority; |
|
454 } |
|
455 |
|
456 int set_task_priority(int id, int priority) |
|
457 { |
|
458 if (TUint(id) > TUint(PThread::MaxTaskId)) |
|
459 return BAD_TASK_ID; |
|
460 PThread* t = PThread::TaskTable[id]; |
|
461 if (!t) |
|
462 return BAD_TASK_ID; |
|
463 if (priority < MIN_TASK_PRIORITY || priority > MAX_TASK_PRIORITY) |
|
464 return BAD_PRIORITY; |
|
465 NKern::Lock(); |
|
466 t->iSetPriority = priority; |
|
467 t->SetPriority(PThread::NThreadPriorityTable[priority]); |
|
468 NKern::Unlock(); |
|
469 return OK; |
|
470 } |
|
471 |
|
472 int current_task_id(void) |
|
473 { |
|
474 TInt c = NKern::CurrentContext(); |
|
475 if (c == NKern::EInterrupt) |
|
476 return TASK_ID_ISR; |
|
477 PThread* t = (PThread*)NKern::CurrentThread(); |
|
478 if (t->iHandlers == &PThread::Handlers) |
|
479 return t->iTaskId; |
|
480 return TASK_ID_UNKNOWN; |
|
481 } |
|
482 |
|
483 void disable_preemption(void) |
|
484 { |
|
485 NKern::Lock(); |
|
486 } |
|
487 |
|
488 void enable_preemption(void) |
|
489 { |
|
490 NKern::Unlock(); |
|
491 } |
|
492 |
|
493 int disable_interrupts(void) |
|
494 { |
|
495 return NKern::DisableAllInterrupts(); |
|
496 } |
|
497 |
|
498 void restore_interrupts(int level) |
|
499 { |
|
500 NKern::RestoreInterrupts(level); |
|
501 } |
|
502 |
|
503 |
|
504 /* Message APIs */ |
|
505 int send_msg(int task_id, msghdr* msg) |
|
506 { |
|
507 if (TUint(task_id) > TUint(PThread::MaxTaskId)) |
|
508 return BAD_TASK_ID; |
|
509 PThread* t = PThread::TaskTable[task_id]; |
|
510 if (!t) |
|
511 return BAD_TASK_ID; |
|
512 TInt c = NKern::CurrentContext(); |
|
513 if (c == NKern::EInterrupt) |
|
514 { |
|
515 t->ISRPost(msg); |
|
516 return OK; |
|
517 } |
|
518 msg->next = NULL; |
|
519 PThread* st = (PThread*)NKern::CurrentThread(); |
|
520 msg->sending_task_id = (st->iHandlers == &PThread::Handlers) ? st->iTaskId : TASK_ID_UNKNOWN; |
|
521 NKern::Lock(); |
|
522 t->Post(msg, msg); |
|
523 NKern::Unlock(); |
|
524 return OK; |
|
525 } |
|
526 |
|
527 int recv_msg(msghdr** msgptr, int time_ticks) |
|
528 { |
|
529 if (time_ticks < WAIT_FOREVER) |
|
530 return BAD_TIME_INTERVAL; |
|
531 PThread* t = (PThread*)NKern::CurrentThread(); |
|
532 NKern::Lock(); |
|
533 msghdr* m = t->GetMsg(); |
|
534 if (!m && time_ticks != NO_WAIT) |
|
535 { |
|
536 NKern::NanoBlock(time_ticks>0 ? time_ticks : 0, PThread::EWaitMsgQ, NULL); |
|
537 NKern::PreemptionPoint(); |
|
538 m = t->GetMsg(); |
|
539 } |
|
540 NKern::Unlock(); |
|
541 *msgptr = m; |
|
542 return m ? OK : TIMED_OUT; |
|
543 } |
|
544 } |
|
545 |
|
546 /****************************************************************************** |
|
547 * Timer management |
|
548 ******************************************************************************/ |
|
549 |
|
550 TInt PTimer::NumTimers; |
|
551 PTimer* PTimer::TimerTable; |
|
552 |
|
553 // Create all required timers |
|
554 void PTimer::CreateAll() |
|
555 { |
|
556 NumTimers = timer_count; |
|
557 TimerTable = new PTimer[timer_count]; |
|
558 __NK_ASSERT_ALWAYS(TimerTable != NULL); |
|
559 } |
|
560 |
|
561 PTimer::PTimer() |
|
562 : NTimer(NTimerExpired, this), |
|
563 iPeriod(0), |
|
564 iCookie(0), |
|
565 iThread(0), |
|
566 iExpiryCount(0) |
|
567 { |
|
568 } |
|
569 |
|
570 void PTimer::NTimerExpired(TAny* aPtr) |
|
571 { |
|
572 timer_msg* m = (timer_msg*)alloc_mem_block(sizeof(timer_msg)); |
|
573 m->header.next = 0; |
|
574 m->header.msg_id = MSG_ID_TIMEOUT; |
|
575 PTimer* p = (PTimer*)aPtr; |
|
576 TInt irq = NKern::DisableAllInterrupts(); |
|
577 PThread* t = p->iThread; |
|
578 m->count = ++p->iExpiryCount; |
|
579 m->cookie = p->iCookie; |
|
580 if (p->iPeriod > 0) |
|
581 p->Again(p->iPeriod); |
|
582 NKern::RestoreInterrupts(irq); |
|
583 t->ISRPost(&m->header); |
|
584 } |
|
585 |
|
586 /* Timer APIs */ |
|
587 extern "C" { |
|
588 unsigned tick_count(void) |
|
589 { |
|
590 return NKern::TickCount(); |
|
591 } |
|
592 |
|
593 void delay(int time_interval) |
|
594 { |
|
595 __NK_ASSERT_ALWAYS(time_interval > 0); |
|
596 NKern::Sleep(time_interval); |
|
597 } |
|
598 |
|
599 int start_one_shot_timer(int timer_id, int task_id, int time_ticks, void* cookie) |
|
600 { |
|
601 if (time_ticks <= 0) |
|
602 return BAD_TIME_INTERVAL; |
|
603 if (TUint(timer_id) >= TUint(PTimer::NumTimers)) |
|
604 return BAD_TIMER_ID; |
|
605 PTimer* tmr = PTimer::TimerTable + timer_id; |
|
606 if (TUint(task_id) > TUint(PThread::MaxTaskId)) |
|
607 return BAD_TASK_ID; |
|
608 PThread* t = PThread::TaskTable[task_id]; |
|
609 if (!t) |
|
610 return BAD_TASK_ID; |
|
611 TInt r = OK; |
|
612 TInt irq = NKern::DisableAllInterrupts(); |
|
613 if (tmr->iThread) |
|
614 r = TIMER_IN_USE; |
|
615 else |
|
616 { |
|
617 tmr->iPeriod = 0; |
|
618 tmr->iCookie = cookie; |
|
619 tmr->iThread = t; |
|
620 tmr->iExpiryCount = 0; |
|
621 tmr->OneShot(time_ticks, EFalse); |
|
622 } |
|
623 NKern::RestoreInterrupts(irq); |
|
624 return r; |
|
625 } |
|
626 |
|
627 int start_periodic_timer(int timer_id, int task_id, int initial_time_ticks, int period_ticks, void* cookie) |
|
628 { |
|
629 if (initial_time_ticks <= 0 || period_ticks <= 0) |
|
630 return BAD_TIME_INTERVAL; |
|
631 if (TUint(timer_id) >= TUint(PTimer::NumTimers)) |
|
632 return BAD_TIMER_ID; |
|
633 PTimer* tmr = PTimer::TimerTable + timer_id; |
|
634 if (TUint(task_id) > TUint(PThread::MaxTaskId)) |
|
635 return BAD_TASK_ID; |
|
636 PThread* t = PThread::TaskTable[task_id]; |
|
637 if (!t) |
|
638 return BAD_TASK_ID; |
|
639 TInt r = OK; |
|
640 TInt irq = NKern::DisableAllInterrupts(); |
|
641 if (tmr->iThread) |
|
642 r = TIMER_IN_USE; |
|
643 else |
|
644 { |
|
645 tmr->iPeriod = period_ticks; |
|
646 tmr->iCookie = cookie; |
|
647 tmr->iThread = t; |
|
648 tmr->iExpiryCount = 0; |
|
649 tmr->OneShot(initial_time_ticks, EFalse); |
|
650 } |
|
651 NKern::RestoreInterrupts(irq); |
|
652 return r; |
|
653 } |
|
654 |
|
655 int stop_timer(int timer_id) |
|
656 { |
|
657 if (TUint(timer_id) >= TUint(PTimer::NumTimers)) |
|
658 return BAD_TIMER_ID; |
|
659 PTimer* tmr = PTimer::TimerTable + timer_id; |
|
660 TInt irq = NKern::DisableAllInterrupts(); |
|
661 tmr->Cancel(); |
|
662 tmr->iThread = NULL; |
|
663 NKern::RestoreInterrupts(irq); |
|
664 return OK; |
|
665 } |
|
666 } |
|
667 |
|
668 |
|
669 /****************************************************************************** |
|
670 * Semaphore management |
|
671 ******************************************************************************/ |
|
672 |
|
673 TInt PSemaphore::NumSemaphores; |
|
674 PSemaphore* PSemaphore::SemaphoreTable; |
|
675 |
|
676 void PSemaphore::CreateAll() |
|
677 { |
|
678 NumSemaphores = semaphore_count; |
|
679 SemaphoreTable = new PSemaphore[semaphore_count]; |
|
680 __NK_ASSERT_ALWAYS(SemaphoreTable != NULL); |
|
681 } |
|
682 |
|
683 PSemaphore::PSemaphore() |
|
684 : iCount(0), |
|
685 iISRCount(0), |
|
686 iIDfc(IDfcFn, this) |
|
687 { |
|
688 } |
|
689 |
|
690 void PSemaphore::WaitCancel(PThread* aThread) |
|
691 { |
|
692 if (aThread->iSuspendCount == 0) |
|
693 { |
|
694 iWaitQ.Remove(aThread); |
|
695 ++iCount; |
|
696 } |
|
697 else |
|
698 aThread->Deque(); |
|
699 aThread->CheckSuspendThenReady(); |
|
700 } |
|
701 |
|
702 void PSemaphore::SuspendWaitingThread(PThread* aThread) |
|
703 { |
|
704 // do nothing if already suspended |
|
705 if (aThread->iSuspendCount == 0) |
|
706 { |
|
707 iWaitQ.Remove(aThread); |
|
708 ++iCount; |
|
709 iSuspendedQ.Add(aThread); |
|
710 } |
|
711 } |
|
712 |
|
713 void PSemaphore::ResumeWaitingThread(PThread* aThread) |
|
714 { |
|
715 aThread->Deque(); |
|
716 if (--iCount<0) |
|
717 { |
|
718 iWaitQ.Add(aThread); |
|
719 } |
|
720 else |
|
721 { |
|
722 aThread->iWaitObj=NULL; |
|
723 aThread->Ready(); |
|
724 } |
|
725 } |
|
726 |
|
727 void PSemaphore::ChangeWaitingThreadPriority(PThread* aThread, TInt aNewPriority) |
|
728 { |
|
729 if (aThread->iSuspendCount == 0) |
|
730 iWaitQ.ChangePriority(aThread, aNewPriority); |
|
731 else |
|
732 aThread->iPriority = (TUint8)aNewPriority; |
|
733 } |
|
734 |
|
735 void PSemaphore::Signal() |
|
736 { |
|
737 if (++iCount <= 0) |
|
738 { |
|
739 // must wake up next thread |
|
740 PThread* t = iWaitQ.First(); |
|
741 iWaitQ.Remove(t); |
|
742 t->Release(KErrNone); |
|
743 } |
|
744 } |
|
745 |
|
746 void PSemaphore::ISRSignal() |
|
747 { |
|
748 if (__e32_atomic_add_ord32(&iISRCount, 1) == 0) |
|
749 iIDfc.Add(); |
|
750 } |
|
751 |
|
752 void PSemaphore::IDfcFn(TAny* aPtr) |
|
753 { |
|
754 PSemaphore* s = (PSemaphore*)aPtr; |
|
755 TInt count = (TInt)__e32_atomic_swp_ord32(&s->iISRCount, 0); |
|
756 while (count--) |
|
757 s->Signal(); |
|
758 } |
|
759 |
|
760 /* Semaphore APIs */ |
|
761 extern "C" { |
|
762 int semaphore_wait(int sem_id, int time_ticks) |
|
763 { |
|
764 if (time_ticks < WAIT_FOREVER) |
|
765 return BAD_TIME_INTERVAL; |
|
766 if (TUint(sem_id) >= TUint(PSemaphore::NumSemaphores)) |
|
767 return BAD_SEM_ID; |
|
768 PSemaphore* s = PSemaphore::SemaphoreTable + sem_id; |
|
769 PThread* t = (PThread*)NKern::CurrentThread(); |
|
770 TInt r = OK; |
|
771 NKern::Lock(); |
|
772 if (time_ticks == NO_WAIT) |
|
773 { |
|
774 if (s->iCount <= 0) |
|
775 r = TIMED_OUT; |
|
776 else |
|
777 --s->iCount; |
|
778 NKern::Unlock(); |
|
779 return r; |
|
780 } |
|
781 if (--s->iCount < 0) |
|
782 { |
|
783 NKern::NanoBlock(time_ticks>0 ? time_ticks : 0, PThread::EWaitSemaphore, s); |
|
784 s->iWaitQ.Add(t); |
|
785 NKern::PreemptionPoint(); |
|
786 if (t->iReturnValue == KErrTimedOut) |
|
787 r = TIMED_OUT; |
|
788 } |
|
789 NKern::Unlock(); |
|
790 return r; |
|
791 } |
|
792 |
|
793 int semaphore_signal(int sem_id) |
|
794 { |
|
795 if (TUint(sem_id) >= TUint(PSemaphore::NumSemaphores)) |
|
796 return BAD_SEM_ID; |
|
797 PSemaphore* s = PSemaphore::SemaphoreTable + sem_id; |
|
798 TInt c = NKern::CurrentContext(); |
|
799 if (c == NKern::EInterrupt) |
|
800 { |
|
801 s->ISRSignal(); |
|
802 return OK; |
|
803 } |
|
804 NKern::Lock(); |
|
805 s->Signal(); |
|
806 NKern::Unlock(); |
|
807 return OK; |
|
808 } |
|
809 |
|
810 void init_personality(void) |
|
811 { |
|
812 __KTRACE_OPT(KBOOT,Kern::Printf("Starting example personality")); |
|
813 |
|
814 PMemMgr::Create(pool_list); |
|
815 PTimer::CreateAll(); |
|
816 PSemaphore::CreateAll(); |
|
817 PThread::CreateAll(task_list); |
|
818 } |
|
819 } |
|
820 |
|
821 /****************************************************************************** |
|
822 * Communication with EPOC |
|
823 ******************************************************************************/ |
|
824 TPMsgQ* TPMsgQ::ThePMsgQ; |
|
825 |
|
826 TPMsgQ::TPMsgQ(TDfcFn aFunction, TAny* aPtr, TDfcQue* aDfcQ, TInt aPriority) |
|
827 : TDfc(aFunction, aPtr, aDfcQ, aPriority), |
|
828 iFirstMsg(NULL), |
|
829 iLastMsg(NULL), |
|
830 iReady(EFalse) |
|
831 { |
|
832 } |
|
833 |
|
834 extern "C" void send_to_epoc(msghdr* m) |
|
835 { |
|
836 TPMsgQ* q = TPMsgQ::ThePMsgQ; |
|
837 m->next = NULL; |
|
838 m->sending_task_id = current_task_id(); |
|
839 NKern::Lock(); |
|
840 msghdr* l = q->iLastMsg; |
|
841 q->iLastMsg = m; |
|
842 if (l) |
|
843 { |
|
844 l->next = m; |
|
845 NKern::Unlock(); |
|
846 return; // queue was not empty so thread can't be waiting |
|
847 } |
|
848 q->iFirstMsg = m; |
|
849 if (q->iReady) |
|
850 { |
|
851 q->iReady = EFalse; |
|
852 q->DoEnque(); |
|
853 } |
|
854 NKern::Unlock(); |
|
855 } |
|
856 |
|
857 void TPMsgQ::Receive() |
|
858 { |
|
859 NKern::Lock(); |
|
860 if (iFirstMsg) |
|
861 DoEnque(); |
|
862 else |
|
863 iReady = ETrue; |
|
864 NKern::Unlock(); |
|
865 } |
|
866 |
|
867 msghdr* TPMsgQ::Get() |
|
868 { |
|
869 NKern::Lock(); |
|
870 msghdr* m = iFirstMsg; |
|
871 if (m) |
|
872 { |
|
873 iFirstMsg = m->next; |
|
874 if (!iFirstMsg) |
|
875 iLastMsg = NULL; |
|
876 } |
|
877 NKern::Unlock(); |
|
878 return m; |
|
879 } |
|
880 |
|
881 void TPMsgQ::CancelReceive() |
|
882 { |
|
883 iReady = EFalse; |
|
884 Cancel(); |
|
885 } |
|
886 |
|
887 |