1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/personality/example/personality.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,887 @@
1.4 +// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32\personality\example\personality.cpp
1.18 +// Example RTOS personality.
1.19 +//
1.20 +//
1.21 +
1.22 +#include "personality_int.h"
1.23 +
1.24 +/******************************************************************************
1.25 + * Memory pool management
1.26 + ******************************************************************************/
1.27 +
1.28 +// Create a single memory pool consisting of a specified number of equal sized blocks.
1.29 +TInt PMemPool::Create(const poolinfo* aInfo)
1.30 + {
1.31 + iBlockSize = aInfo->block_size;
1.32 + TUint bsize = iBlockSize + sizeof(PMemPool*);
1.33 + TInt n = (TInt)aInfo->block_count;
1.34 + __KTRACE_OPT(KBOOT, Kern::Printf("PMemPool::Create %08x iBlockSize=%04x bsize=%04x n=%04x", this, iBlockSize, bsize, n));
1.35 + if (bsize < sizeof(SMemBlock) || (bsize & 3))
1.36 + return KErrArgument;
1.37 + TInt total_size = n * bsize;
1.38 + iFirstFree = (SMemBlock*)Kern::Alloc(total_size);
1.39 + __KTRACE_OPT(KBOOT, Kern::Printf("PMemPool::Create %08x iFirstFree=%08x", this, iFirstFree));
1.40 + if (!iFirstFree)
1.41 + return KErrNoMemory;
1.42 + TInt i;
1.43 + for (i=0; i<n; ++i)
1.44 + {
1.45 + SMemBlock* p = (SMemBlock*)(TLinAddr(iFirstFree) + i*bsize);
1.46 + SMemBlock* q = (i<n-1) ? (SMemBlock*)(TLinAddr(p) + bsize) : NULL;
1.47 + p->iPool = this;
1.48 + p->iNext = q;
1.49 + }
1.50 + __KTRACE_OPT(KBOOT, Kern::Printf("PMemPool::Create OK"));
1.51 + return KErrNone;
1.52 + }
1.53 +
1.54 +// Call with interrupts disabled
1.55 +void* PMemPool::Alloc()
1.56 + {
1.57 + SMemBlock* p = iFirstFree;
1.58 + if (p)
1.59 + {
1.60 + iFirstFree = p->iNext;
1.61 + __KTRACE_OPT(KBOOT, Kern::Printf("AL:%08x->%08x", this, &p->iNext));
1.62 + return &p->iNext;
1.63 + }
1.64 + __KTRACE_OPT(KBOOT, Kern::Printf("AL:%08x->0", this));
1.65 + return NULL;
1.66 + }
1.67 +
1.68 +// Call with interrupts disabled
1.69 +void PMemPool::Free(void* aBlock)
1.70 + {
1.71 + __KTRACE_OPT(KBOOT, Kern::Printf("FR:%08x<-%08x", this, aBlock));
1.72 + SMemBlock* b = (SMemBlock*)aBlock;
1.73 + __NK_ASSERT_DEBUG(b->iPool==this);
1.74 + b->iNext = iFirstFree;
1.75 + iFirstFree = b;
1.76 + }
1.77 +
1.78 +PMemMgr* PMemMgr::TheMgr;
1.79 +
1.80 +// Create a 'size bucket' memory manager consisting of a number of memory pools
1.81 +// each containing blocks of the same size. The block size increases from one
1.82 +// pool to the next.
1.83 +void PMemMgr::Create(const poolinfo* aInfo)
1.84 + {
1.85 + TInt n;
1.86 + for (n=0; aInfo[n].block_size; ++n) {}
1.87 + PMemMgr* m = (PMemMgr*)Kern::Alloc(sizeof(PMemMgr) + (n-1)*sizeof(PMemPool));
1.88 + __KTRACE_OPT(KBOOT, Kern::Printf("PMemMgr::Create %08x NumPools=%d", m, n));
1.89 + __NK_ASSERT_ALWAYS(m!=NULL);
1.90 + m->iPoolCount = n;
1.91 + TInt i;
1.92 + size_t prev_sz=0;
1.93 + for (i=0; i<n; ++i)
1.94 + {
1.95 + __NK_ASSERT_ALWAYS(aInfo[i].block_size > prev_sz);
1.96 + prev_sz = aInfo[i].block_size;
1.97 + TInt r = m->iPools[i].Create(aInfo+i);
1.98 + __NK_ASSERT_ALWAYS(r==KErrNone);
1.99 + }
1.100 + TheMgr = m;
1.101 + }
1.102 +
1.103 +// Allocate a memory block of the requested size (or the next larger size if necessary).
1.104 +void* PMemMgr::Alloc(size_t aSize)
1.105 + {
1.106 + __KTRACE_OPT(KBOOT, Kern::Printf("MA:%04x", aSize));
1.107 + void* b = NULL;
1.108 + PMemPool* p = &TheMgr->iPools[0];
1.109 + PMemPool* q = p + TheMgr->iPoolCount;
1.110 + for (; p<q && p->iBlockSize < aSize; ++p) {}
1.111 + if (p < q)
1.112 + {
1.113 + TInt irq = NKern::DisableAllInterrupts();
1.114 + b = p->Alloc();
1.115 + NKern::RestoreInterrupts(irq);
1.116 + }
1.117 + return b;
1.118 + }
1.119 +
1.120 +// Free a memory block
1.121 +void PMemMgr::Free(void* aPtr)
1.122 + {
1.123 + __KTRACE_OPT(KBOOT, Kern::Printf("MF:%08x", aPtr));
1.124 + SMemBlock* b = _LOFF(aPtr, SMemBlock, iNext);
1.125 + TInt irq = NKern::DisableAllInterrupts();
1.126 + b->iPool->Free(b);
1.127 + NKern::RestoreInterrupts(irq);
1.128 + }
1.129 +
1.130 +
1.131 +/* Memory management APIs */
1.132 +extern "C" {
1.133 +void* alloc_mem_block(size_t size)
1.134 + {
1.135 + return PMemMgr::Alloc(size);
1.136 + }
1.137 +
1.138 +void free_mem_block(void* block)
1.139 + {
1.140 + PMemMgr::Free(block);
1.141 + }
1.142 +}
1.143 +
1.144 +/******************************************************************************
1.145 + * Task management
1.146 + ******************************************************************************/
1.147 +
1.148 +TInt PThread::NumTasks;
1.149 +TInt PThread::MaxTaskId;
1.150 +PThread** PThread::TaskTable;
1.151 +
1.152 +// RTOS priority to nanokernel priority mapping
1.153 +const TUint8 PThread::NThreadPriorityTable[MAX_TASK_PRIORITY+1] =
1.154 + {
1.155 + 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
1.156 + 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07,
1.157 + 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b,
1.158 + 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
1.159 + 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
1.160 + 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
1.161 + 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b,
1.162 + 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f,
1.163 + 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23,
1.164 + 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27,
1.165 + 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b,
1.166 + 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f,
1.167 + 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33,
1.168 + 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, 0x37, 0x37,
1.169 + 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b,
1.170 + 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f
1.171 + };
1.172 +
1.173 +// Handlers for personality layer threads
1.174 +const SNThreadHandlers PThread::Handlers =
1.175 + {
1.176 + NULL, // no exit handler
1.177 + &StateHandler,
1.178 + &ExceptionHandler,
1.179 + NULL // no timeout handler
1.180 + };
1.181 +
1.182 +// Create a personality layer thread
1.183 +TInt PThread::Create(PThread*& aThread, const taskinfo* a)
1.184 + {
1.185 + if (!a->entry_pt)
1.186 + return BAD_ENTRY_POINT;
1.187 + if (a->priority < MIN_TASK_PRIORITY || a->priority > MAX_TASK_PRIORITY)
1.188 + return BAD_PRIORITY;
1.189 + if (a->stack_size & 3 || a->stack_size < MIN_STACK_SIZE)
1.190 + return BAD_STACK_SIZE;
1.191 + if (a->task_id < 0)
1.192 + return BAD_TASK_ID;
1.193 + TInt memsize = sizeof(PThread) + a->stack_size;
1.194 + PThread* t = (PThread*)Kern::Alloc(memsize);
1.195 + if (!t)
1.196 + return OUT_OF_MEMORY;
1.197 + t->iTaskId = a->task_id;
1.198 + t->iSetPriority = a->priority;
1.199 + t->iFirstMsg = NULL;
1.200 + t->iLastMsg = NULL;
1.201 + t->iISRFirstMsg = NULL;
1.202 + t->iISRLastMsg = NULL;
1.203 + new (&t->iMsgQIDfc) TDfc(&MsgQIDfcFn, t);
1.204 + TAny* stack = t + 1;
1.205 + memset(stack, 0xbb, a->stack_size);
1.206 + SNThreadCreateInfo info;
1.207 + info.iFunction = (NThreadFunction)a->entry_pt;
1.208 + info.iStackBase = stack;
1.209 + info.iStackSize = a->stack_size;
1.210 + info.iPriority = NThreadPriorityTable[a->priority];
1.211 + info.iTimeslice = -1; // no timeslicing
1.212 + info.iAttributes = 0;
1.213 + info.iHandlers = &Handlers;
1.214 + info.iFastExecTable = NULL;
1.215 + info.iSlowExecTable = NULL;
1.216 + info.iParameterBlock = NULL;
1.217 + info.iParameterBlockSize = 0;
1.218 + TInt r = NKern::ThreadCreate(t, info);
1.219 + __NK_ASSERT_ALWAYS(r==KErrNone);
1.220 + aThread = t;
1.221 + return OK;
1.222 + }
1.223 +
1.224 +// Create all required personality layer threads
1.225 +void PThread::CreateAll(const taskinfo* a)
1.226 + {
1.227 + TInt n = 0;
1.228 + TInt maxid = -1;
1.229 + for (; a[n].entry_pt; ++n)
1.230 + {
1.231 + if (a[n].task_id > maxid)
1.232 + maxid = a[n].task_id;
1.233 + }
1.234 + NumTasks = n;
1.235 + MaxTaskId = maxid;
1.236 + TaskTable = (PThread**)Kern::AllocZ((maxid+1) * sizeof(PThread*));
1.237 + __NK_ASSERT_ALWAYS(TaskTable != NULL);
1.238 + TInt i;
1.239 + for (i=0; i<NumTasks; ++i)
1.240 + {
1.241 + TInt r = Create(TaskTable[a[i].task_id], a+i);
1.242 + __NK_ASSERT_ALWAYS(r == KErrNone);
1.243 + }
1.244 + // resume the tasks
1.245 + for (i=0; i<NumTasks; ++i)
1.246 + {
1.247 + if (a[i].auto_start)
1.248 + NKern::ThreadResume(TaskTable[i]);
1.249 + }
1.250 + }
1.251 +
1.252 +// State handler
1.253 +void PThread::StateHandler(NThread* aThread, TInt aOp, TInt aParam)
1.254 + {
1.255 + PThread* t = (PThread*)aThread;
1.256 + switch (aOp)
1.257 + {
1.258 + case NThreadBase::ESuspend:
1.259 + t->HandleSuspend();
1.260 + break;
1.261 + case NThreadBase::EResume:
1.262 + case NThreadBase::EForceResume:
1.263 + t->HandleResume();
1.264 + break;
1.265 + case NThreadBase::ERelease:
1.266 + t->HandleRelease(aParam);
1.267 + break;
1.268 + case NThreadBase::EChangePriority:
1.269 + t->HandlePriorityChange(aParam);
1.270 + break;
1.271 + case NThreadBase::ETimeout:
1.272 + t->HandleTimeout();
1.273 + break;
1.274 + case NThreadBase::ELeaveCS:
1.275 + default:
1.276 + __NK_ASSERT_ALWAYS(0);
1.277 + }
1.278 + }
1.279 +
1.280 +// Exception handler - just fault
1.281 +void PThread::ExceptionHandler(TAny* aContext, NThread* aThread)
1.282 + {
1.283 + (void)aThread;
1.284 + Exc::Fault(aContext);
1.285 + }
1.286 +
1.287 +// Post a message to this thread from an ISR
1.288 +void PThread::ISRPost(msghdr* aM)
1.289 + {
1.290 + aM->next = NULL;
1.291 + aM->sending_task_id = TASK_ID_ISR;
1.292 + msghdr* prev = (msghdr*)__e32_atomic_swp_ord_ptr(&iISRLastMsg, aM);
1.293 + if (prev)
1.294 + prev->next = aM;
1.295 + else
1.296 + {
1.297 + iISRFirstMsg = aM;
1.298 + iMsgQIDfc.Add();
1.299 + }
1.300 + }
1.301 +
1.302 +// IDFC used to post message from ISR
1.303 +void PThread::MsgQIDfcFn(TAny* aPtr)
1.304 + {
1.305 + PThread* t = (PThread*)aPtr;
1.306 + TInt irq = NKern::DisableAllInterrupts();
1.307 + msghdr* m = t->iISRFirstMsg;
1.308 + msghdr* l = t->iISRLastMsg;
1.309 + t->iISRFirstMsg = NULL;
1.310 + t->iISRLastMsg = NULL;
1.311 + NKern::RestoreInterrupts(irq);
1.312 + t->Post(m, l);
1.313 + }
1.314 +
1.315 +// Post a chain of messages to this thread from an IDFC or thread
1.316 +// Enter and return with preemption disabled
1.317 +void PThread::Post(msghdr* aFirst, msghdr* aLast)
1.318 + {
1.319 + msghdr* l = iLastMsg;
1.320 + iLastMsg = aLast;
1.321 + if (l)
1.322 + {
1.323 + l->next = aFirst;
1.324 + return; // queue was not empty so thread can't be waiting
1.325 + }
1.326 + iFirstMsg = aFirst;
1.327 + if (iNState == EWaitMsgQ)
1.328 + Release(KErrNone);
1.329 + }
1.330 +
1.331 +// Dequeue and return the first message if there is one
1.332 +// Return NULL if no messages waiting
1.333 +// Enter and return with preemption disabled
1.334 +msghdr* PThread::GetMsg()
1.335 + {
1.336 + msghdr* m = iFirstMsg;
1.337 + if (m)
1.338 + {
1.339 + iFirstMsg = m->next;
1.340 + if (!iFirstMsg)
1.341 + iLastMsg = NULL;
1.342 + }
1.343 + return m;
1.344 + }
1.345 +
1.346 +void PThread::HandleSuspend()
1.347 + {
1.348 + switch(iNState)
1.349 + {
1.350 + case EWaitMsgQ:
1.351 + break;
1.352 + case EWaitSemaphore:
1.353 + ((PSemaphore*)iWaitObj)->SuspendWaitingThread(this);
1.354 + break;
1.355 + default:
1.356 + __NK_ASSERT_ALWAYS(0);
1.357 + }
1.358 + }
1.359 +
1.360 +void PThread::HandleResume()
1.361 + {
1.362 + switch(iNState)
1.363 + {
1.364 + case EWaitMsgQ:
1.365 + break;
1.366 + case EWaitSemaphore:
1.367 + ((PSemaphore*)iWaitObj)->ResumeWaitingThread(this);
1.368 + break;
1.369 + default:
1.370 + __NK_ASSERT_ALWAYS(0);
1.371 + }
1.372 + }
1.373 +
1.374 +void PThread::HandleRelease(TInt aReturnCode)
1.375 + {
1.376 + (void)aReturnCode;
1.377 + switch(iNState)
1.378 + {
1.379 + case EWaitMsgQ:
1.380 + CheckSuspendThenReady();
1.381 + break;
1.382 + case EWaitSemaphore:
1.383 + if (aReturnCode<0)
1.384 + ((PSemaphore*)iWaitObj)->WaitCancel(this);
1.385 + else
1.386 + CheckSuspendThenReady();
1.387 + break;
1.388 + default:
1.389 + __NK_ASSERT_ALWAYS(0);
1.390 + }
1.391 + }
1.392 +
1.393 +void PThread::HandlePriorityChange(TInt aNewPriority)
1.394 + {
1.395 + (void)aNewPriority;
1.396 + switch(iNState)
1.397 + {
1.398 + case EWaitMsgQ:
1.399 + iPriority = (TUint8)aNewPriority;
1.400 + break;
1.401 + case EWaitSemaphore:
1.402 + ((PSemaphore*)iWaitObj)->ChangeWaitingThreadPriority(this, aNewPriority);
1.403 + break;
1.404 + default:
1.405 + __NK_ASSERT_ALWAYS(0);
1.406 + }
1.407 + }
1.408 +
1.409 +void PThread::HandleTimeout()
1.410 + {
1.411 + switch(iNState)
1.412 + {
1.413 + case EWaitMsgQ:
1.414 + CheckSuspendThenReady();
1.415 + break;
1.416 + case EWaitSemaphore:
1.417 + ((PSemaphore*)iWaitObj)->WaitCancel(this);
1.418 + break;
1.419 + default:
1.420 + __NK_ASSERT_ALWAYS(0);
1.421 + }
1.422 + }
1.423 +
1.424 +
1.425 +/* Task APIs */
1.426 +extern "C" {
1.427 +int suspend_task(int id)
1.428 + {
1.429 + if (TUint(id) > TUint(PThread::MaxTaskId))
1.430 + return BAD_TASK_ID;
1.431 + PThread* t = PThread::TaskTable[id];
1.432 + if (!t)
1.433 + return BAD_TASK_ID;
1.434 + NKern::ThreadSuspend(t, 1);
1.435 + return OK;
1.436 + }
1.437 +
1.438 +int resume_task(int id)
1.439 + {
1.440 + if (TUint(id) > TUint(PThread::MaxTaskId))
1.441 + return BAD_TASK_ID;
1.442 + PThread* t = PThread::TaskTable[id];
1.443 + if (!t)
1.444 + return BAD_TASK_ID;
1.445 + NKern::ThreadResume(t);
1.446 + return OK;
1.447 + }
1.448 +
1.449 +int get_task_priority(int id)
1.450 + {
1.451 + if (TUint(id) > TUint(PThread::MaxTaskId))
1.452 + return BAD_TASK_ID;
1.453 + PThread* t = PThread::TaskTable[id];
1.454 + if (!t)
1.455 + return BAD_TASK_ID;
1.456 + return t->iSetPriority;
1.457 + }
1.458 +
1.459 +int set_task_priority(int id, int priority)
1.460 + {
1.461 + if (TUint(id) > TUint(PThread::MaxTaskId))
1.462 + return BAD_TASK_ID;
1.463 + PThread* t = PThread::TaskTable[id];
1.464 + if (!t)
1.465 + return BAD_TASK_ID;
1.466 + if (priority < MIN_TASK_PRIORITY || priority > MAX_TASK_PRIORITY)
1.467 + return BAD_PRIORITY;
1.468 + NKern::Lock();
1.469 + t->iSetPriority = priority;
1.470 + t->SetPriority(PThread::NThreadPriorityTable[priority]);
1.471 + NKern::Unlock();
1.472 + return OK;
1.473 + }
1.474 +
1.475 +int current_task_id(void)
1.476 + {
1.477 + TInt c = NKern::CurrentContext();
1.478 + if (c == NKern::EInterrupt)
1.479 + return TASK_ID_ISR;
1.480 + PThread* t = (PThread*)NKern::CurrentThread();
1.481 + if (t->iHandlers == &PThread::Handlers)
1.482 + return t->iTaskId;
1.483 + return TASK_ID_UNKNOWN;
1.484 + }
1.485 +
1.486 +void disable_preemption(void)
1.487 + {
1.488 + NKern::Lock();
1.489 + }
1.490 +
1.491 +void enable_preemption(void)
1.492 + {
1.493 + NKern::Unlock();
1.494 + }
1.495 +
1.496 +int disable_interrupts(void)
1.497 + {
1.498 + return NKern::DisableAllInterrupts();
1.499 + }
1.500 +
1.501 +void restore_interrupts(int level)
1.502 + {
1.503 + NKern::RestoreInterrupts(level);
1.504 + }
1.505 +
1.506 +
1.507 +/* Message APIs */
1.508 +int send_msg(int task_id, msghdr* msg)
1.509 + {
1.510 + if (TUint(task_id) > TUint(PThread::MaxTaskId))
1.511 + return BAD_TASK_ID;
1.512 + PThread* t = PThread::TaskTable[task_id];
1.513 + if (!t)
1.514 + return BAD_TASK_ID;
1.515 + TInt c = NKern::CurrentContext();
1.516 + if (c == NKern::EInterrupt)
1.517 + {
1.518 + t->ISRPost(msg);
1.519 + return OK;
1.520 + }
1.521 + msg->next = NULL;
1.522 + PThread* st = (PThread*)NKern::CurrentThread();
1.523 + msg->sending_task_id = (st->iHandlers == &PThread::Handlers) ? st->iTaskId : TASK_ID_UNKNOWN;
1.524 + NKern::Lock();
1.525 + t->Post(msg, msg);
1.526 + NKern::Unlock();
1.527 + return OK;
1.528 + }
1.529 +
1.530 +int recv_msg(msghdr** msgptr, int time_ticks)
1.531 + {
1.532 + if (time_ticks < WAIT_FOREVER)
1.533 + return BAD_TIME_INTERVAL;
1.534 + PThread* t = (PThread*)NKern::CurrentThread();
1.535 + NKern::Lock();
1.536 + msghdr* m = t->GetMsg();
1.537 + if (!m && time_ticks != NO_WAIT)
1.538 + {
1.539 + NKern::NanoBlock(time_ticks>0 ? time_ticks : 0, PThread::EWaitMsgQ, NULL);
1.540 + NKern::PreemptionPoint();
1.541 + m = t->GetMsg();
1.542 + }
1.543 + NKern::Unlock();
1.544 + *msgptr = m;
1.545 + return m ? OK : TIMED_OUT;
1.546 + }
1.547 +}
1.548 +
1.549 +/******************************************************************************
1.550 + * Timer management
1.551 + ******************************************************************************/
1.552 +
1.553 +TInt PTimer::NumTimers;
1.554 +PTimer* PTimer::TimerTable;
1.555 +
1.556 +// Create all required timers
1.557 +void PTimer::CreateAll()
1.558 + {
1.559 + NumTimers = timer_count;
1.560 + TimerTable = new PTimer[timer_count];
1.561 + __NK_ASSERT_ALWAYS(TimerTable != NULL);
1.562 + }
1.563 +
1.564 +PTimer::PTimer()
1.565 + : NTimer(NTimerExpired, this),
1.566 + iPeriod(0),
1.567 + iCookie(0),
1.568 + iThread(0),
1.569 + iExpiryCount(0)
1.570 + {
1.571 + }
1.572 +
1.573 +void PTimer::NTimerExpired(TAny* aPtr)
1.574 + {
1.575 + timer_msg* m = (timer_msg*)alloc_mem_block(sizeof(timer_msg));
1.576 + m->header.next = 0;
1.577 + m->header.msg_id = MSG_ID_TIMEOUT;
1.578 + PTimer* p = (PTimer*)aPtr;
1.579 + TInt irq = NKern::DisableAllInterrupts();
1.580 + PThread* t = p->iThread;
1.581 + m->count = ++p->iExpiryCount;
1.582 + m->cookie = p->iCookie;
1.583 + if (p->iPeriod > 0)
1.584 + p->Again(p->iPeriod);
1.585 + NKern::RestoreInterrupts(irq);
1.586 + t->ISRPost(&m->header);
1.587 + }
1.588 +
1.589 +/* Timer APIs */
1.590 +extern "C" {
1.591 +unsigned tick_count(void)
1.592 + {
1.593 + return NKern::TickCount();
1.594 + }
1.595 +
1.596 +void delay(int time_interval)
1.597 + {
1.598 + __NK_ASSERT_ALWAYS(time_interval > 0);
1.599 + NKern::Sleep(time_interval);
1.600 + }
1.601 +
1.602 +int start_one_shot_timer(int timer_id, int task_id, int time_ticks, void* cookie)
1.603 + {
1.604 + if (time_ticks <= 0)
1.605 + return BAD_TIME_INTERVAL;
1.606 + if (TUint(timer_id) >= TUint(PTimer::NumTimers))
1.607 + return BAD_TIMER_ID;
1.608 + PTimer* tmr = PTimer::TimerTable + timer_id;
1.609 + if (TUint(task_id) > TUint(PThread::MaxTaskId))
1.610 + return BAD_TASK_ID;
1.611 + PThread* t = PThread::TaskTable[task_id];
1.612 + if (!t)
1.613 + return BAD_TASK_ID;
1.614 + TInt r = OK;
1.615 + TInt irq = NKern::DisableAllInterrupts();
1.616 + if (tmr->iThread)
1.617 + r = TIMER_IN_USE;
1.618 + else
1.619 + {
1.620 + tmr->iPeriod = 0;
1.621 + tmr->iCookie = cookie;
1.622 + tmr->iThread = t;
1.623 + tmr->iExpiryCount = 0;
1.624 + tmr->OneShot(time_ticks, EFalse);
1.625 + }
1.626 + NKern::RestoreInterrupts(irq);
1.627 + return r;
1.628 + }
1.629 +
1.630 +int start_periodic_timer(int timer_id, int task_id, int initial_time_ticks, int period_ticks, void* cookie)
1.631 + {
1.632 + if (initial_time_ticks <= 0 || period_ticks <= 0)
1.633 + return BAD_TIME_INTERVAL;
1.634 + if (TUint(timer_id) >= TUint(PTimer::NumTimers))
1.635 + return BAD_TIMER_ID;
1.636 + PTimer* tmr = PTimer::TimerTable + timer_id;
1.637 + if (TUint(task_id) > TUint(PThread::MaxTaskId))
1.638 + return BAD_TASK_ID;
1.639 + PThread* t = PThread::TaskTable[task_id];
1.640 + if (!t)
1.641 + return BAD_TASK_ID;
1.642 + TInt r = OK;
1.643 + TInt irq = NKern::DisableAllInterrupts();
1.644 + if (tmr->iThread)
1.645 + r = TIMER_IN_USE;
1.646 + else
1.647 + {
1.648 + tmr->iPeriod = period_ticks;
1.649 + tmr->iCookie = cookie;
1.650 + tmr->iThread = t;
1.651 + tmr->iExpiryCount = 0;
1.652 + tmr->OneShot(initial_time_ticks, EFalse);
1.653 + }
1.654 + NKern::RestoreInterrupts(irq);
1.655 + return r;
1.656 + }
1.657 +
1.658 +int stop_timer(int timer_id)
1.659 + {
1.660 + if (TUint(timer_id) >= TUint(PTimer::NumTimers))
1.661 + return BAD_TIMER_ID;
1.662 + PTimer* tmr = PTimer::TimerTable + timer_id;
1.663 + TInt irq = NKern::DisableAllInterrupts();
1.664 + tmr->Cancel();
1.665 + tmr->iThread = NULL;
1.666 + NKern::RestoreInterrupts(irq);
1.667 + return OK;
1.668 + }
1.669 +}
1.670 +
1.671 +
1.672 +/******************************************************************************
1.673 + * Semaphore management
1.674 + ******************************************************************************/
1.675 +
1.676 +TInt PSemaphore::NumSemaphores;
1.677 +PSemaphore* PSemaphore::SemaphoreTable;
1.678 +
1.679 +void PSemaphore::CreateAll()
1.680 + {
1.681 + NumSemaphores = semaphore_count;
1.682 + SemaphoreTable = new PSemaphore[semaphore_count];
1.683 + __NK_ASSERT_ALWAYS(SemaphoreTable != NULL);
1.684 + }
1.685 +
1.686 +PSemaphore::PSemaphore()
1.687 + : iCount(0),
1.688 + iISRCount(0),
1.689 + iIDfc(IDfcFn, this)
1.690 + {
1.691 + }
1.692 +
1.693 +void PSemaphore::WaitCancel(PThread* aThread)
1.694 + {
1.695 + if (aThread->iSuspendCount == 0)
1.696 + {
1.697 + iWaitQ.Remove(aThread);
1.698 + ++iCount;
1.699 + }
1.700 + else
1.701 + aThread->Deque();
1.702 + aThread->CheckSuspendThenReady();
1.703 + }
1.704 +
1.705 +void PSemaphore::SuspendWaitingThread(PThread* aThread)
1.706 + {
1.707 + // do nothing if already suspended
1.708 + if (aThread->iSuspendCount == 0)
1.709 + {
1.710 + iWaitQ.Remove(aThread);
1.711 + ++iCount;
1.712 + iSuspendedQ.Add(aThread);
1.713 + }
1.714 + }
1.715 +
1.716 +void PSemaphore::ResumeWaitingThread(PThread* aThread)
1.717 + {
1.718 + aThread->Deque();
1.719 + if (--iCount<0)
1.720 + {
1.721 + iWaitQ.Add(aThread);
1.722 + }
1.723 + else
1.724 + {
1.725 + aThread->iWaitObj=NULL;
1.726 + aThread->Ready();
1.727 + }
1.728 + }
1.729 +
1.730 +void PSemaphore::ChangeWaitingThreadPriority(PThread* aThread, TInt aNewPriority)
1.731 + {
1.732 + if (aThread->iSuspendCount == 0)
1.733 + iWaitQ.ChangePriority(aThread, aNewPriority);
1.734 + else
1.735 + aThread->iPriority = (TUint8)aNewPriority;
1.736 + }
1.737 +
1.738 +void PSemaphore::Signal()
1.739 + {
1.740 + if (++iCount <= 0)
1.741 + {
1.742 + // must wake up next thread
1.743 + PThread* t = iWaitQ.First();
1.744 + iWaitQ.Remove(t);
1.745 + t->Release(KErrNone);
1.746 + }
1.747 + }
1.748 +
1.749 +void PSemaphore::ISRSignal()
1.750 + {
1.751 + if (__e32_atomic_add_ord32(&iISRCount, 1) == 0)
1.752 + iIDfc.Add();
1.753 + }
1.754 +
1.755 +void PSemaphore::IDfcFn(TAny* aPtr)
1.756 + {
1.757 + PSemaphore* s = (PSemaphore*)aPtr;
1.758 + TInt count = (TInt)__e32_atomic_swp_ord32(&s->iISRCount, 0);
1.759 + while (count--)
1.760 + s->Signal();
1.761 + }
1.762 +
1.763 +/* Semaphore APIs */
1.764 +extern "C" {
1.765 +int semaphore_wait(int sem_id, int time_ticks)
1.766 + {
1.767 + if (time_ticks < WAIT_FOREVER)
1.768 + return BAD_TIME_INTERVAL;
1.769 + if (TUint(sem_id) >= TUint(PSemaphore::NumSemaphores))
1.770 + return BAD_SEM_ID;
1.771 + PSemaphore* s = PSemaphore::SemaphoreTable + sem_id;
1.772 + PThread* t = (PThread*)NKern::CurrentThread();
1.773 + TInt r = OK;
1.774 + NKern::Lock();
1.775 + if (time_ticks == NO_WAIT)
1.776 + {
1.777 + if (s->iCount <= 0)
1.778 + r = TIMED_OUT;
1.779 + else
1.780 + --s->iCount;
1.781 + NKern::Unlock();
1.782 + return r;
1.783 + }
1.784 + if (--s->iCount < 0)
1.785 + {
1.786 + NKern::NanoBlock(time_ticks>0 ? time_ticks : 0, PThread::EWaitSemaphore, s);
1.787 + s->iWaitQ.Add(t);
1.788 + NKern::PreemptionPoint();
1.789 + if (t->iReturnValue == KErrTimedOut)
1.790 + r = TIMED_OUT;
1.791 + }
1.792 + NKern::Unlock();
1.793 + return r;
1.794 + }
1.795 +
1.796 +int semaphore_signal(int sem_id)
1.797 + {
1.798 + if (TUint(sem_id) >= TUint(PSemaphore::NumSemaphores))
1.799 + return BAD_SEM_ID;
1.800 + PSemaphore* s = PSemaphore::SemaphoreTable + sem_id;
1.801 + TInt c = NKern::CurrentContext();
1.802 + if (c == NKern::EInterrupt)
1.803 + {
1.804 + s->ISRSignal();
1.805 + return OK;
1.806 + }
1.807 + NKern::Lock();
1.808 + s->Signal();
1.809 + NKern::Unlock();
1.810 + return OK;
1.811 + }
1.812 +
1.813 +void init_personality(void)
1.814 + {
1.815 + __KTRACE_OPT(KBOOT,Kern::Printf("Starting example personality"));
1.816 +
1.817 + PMemMgr::Create(pool_list);
1.818 + PTimer::CreateAll();
1.819 + PSemaphore::CreateAll();
1.820 + PThread::CreateAll(task_list);
1.821 + }
1.822 +}
1.823 +
1.824 +/******************************************************************************
1.825 + * Communication with EPOC
1.826 + ******************************************************************************/
1.827 +TPMsgQ* TPMsgQ::ThePMsgQ;
1.828 +
1.829 +TPMsgQ::TPMsgQ(TDfcFn aFunction, TAny* aPtr, TDfcQue* aDfcQ, TInt aPriority)
1.830 + : TDfc(aFunction, aPtr, aDfcQ, aPriority),
1.831 + iFirstMsg(NULL),
1.832 + iLastMsg(NULL),
1.833 + iReady(EFalse)
1.834 + {
1.835 + }
1.836 +
1.837 +extern "C" void send_to_epoc(msghdr* m)
1.838 + {
1.839 + TPMsgQ* q = TPMsgQ::ThePMsgQ;
1.840 + m->next = NULL;
1.841 + m->sending_task_id = current_task_id();
1.842 + NKern::Lock();
1.843 + msghdr* l = q->iLastMsg;
1.844 + q->iLastMsg = m;
1.845 + if (l)
1.846 + {
1.847 + l->next = m;
1.848 + NKern::Unlock();
1.849 + return; // queue was not empty so thread can't be waiting
1.850 + }
1.851 + q->iFirstMsg = m;
1.852 + if (q->iReady)
1.853 + {
1.854 + q->iReady = EFalse;
1.855 + q->DoEnque();
1.856 + }
1.857 + NKern::Unlock();
1.858 + }
1.859 +
1.860 +void TPMsgQ::Receive()
1.861 + {
1.862 + NKern::Lock();
1.863 + if (iFirstMsg)
1.864 + DoEnque();
1.865 + else
1.866 + iReady = ETrue;
1.867 + NKern::Unlock();
1.868 + }
1.869 +
1.870 +msghdr* TPMsgQ::Get()
1.871 + {
1.872 + NKern::Lock();
1.873 + msghdr* m = iFirstMsg;
1.874 + if (m)
1.875 + {
1.876 + iFirstMsg = m->next;
1.877 + if (!iFirstMsg)
1.878 + iLastMsg = NULL;
1.879 + }
1.880 + NKern::Unlock();
1.881 + return m;
1.882 + }
1.883 +
1.884 +void TPMsgQ::CancelReceive()
1.885 + {
1.886 + iReady = EFalse;
1.887 + Cancel();
1.888 + }
1.889 +
1.890 +