sl@0: // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32\personality\example\personality.cpp sl@0: // Example RTOS personality. sl@0: // sl@0: // sl@0: sl@0: #include "personality_int.h" sl@0: sl@0: /****************************************************************************** sl@0: * Memory pool management sl@0: ******************************************************************************/ sl@0: sl@0: // Create a single memory pool consisting of a specified number of equal sized blocks. sl@0: TInt PMemPool::Create(const poolinfo* aInfo) sl@0: { sl@0: iBlockSize = aInfo->block_size; sl@0: TUint bsize = iBlockSize + sizeof(PMemPool*); sl@0: TInt n = (TInt)aInfo->block_count; sl@0: __KTRACE_OPT(KBOOT, Kern::Printf("PMemPool::Create %08x iBlockSize=%04x bsize=%04x n=%04x", this, iBlockSize, bsize, n)); sl@0: if (bsize < sizeof(SMemBlock) || (bsize & 3)) sl@0: return KErrArgument; sl@0: TInt total_size = n * bsize; sl@0: iFirstFree = (SMemBlock*)Kern::Alloc(total_size); sl@0: __KTRACE_OPT(KBOOT, Kern::Printf("PMemPool::Create %08x iFirstFree=%08x", this, iFirstFree)); sl@0: if (!iFirstFree) sl@0: return KErrNoMemory; sl@0: TInt i; sl@0: for (i=0; iiPool = this; sl@0: p->iNext = q; sl@0: } sl@0: __KTRACE_OPT(KBOOT, Kern::Printf("PMemPool::Create OK")); sl@0: return KErrNone; sl@0: } sl@0: sl@0: // Call with interrupts disabled sl@0: void* PMemPool::Alloc() sl@0: { sl@0: SMemBlock* p = iFirstFree; sl@0: if (p) sl@0: { sl@0: iFirstFree = p->iNext; sl@0: __KTRACE_OPT(KBOOT, Kern::Printf("AL:%08x->%08x", this, &p->iNext)); sl@0: return &p->iNext; sl@0: } sl@0: __KTRACE_OPT(KBOOT, Kern::Printf("AL:%08x->0", this)); sl@0: return NULL; sl@0: } sl@0: sl@0: // Call with interrupts disabled sl@0: void PMemPool::Free(void* aBlock) sl@0: { sl@0: __KTRACE_OPT(KBOOT, Kern::Printf("FR:%08x<-%08x", this, aBlock)); sl@0: SMemBlock* b = (SMemBlock*)aBlock; sl@0: __NK_ASSERT_DEBUG(b->iPool==this); sl@0: b->iNext = iFirstFree; sl@0: iFirstFree = b; sl@0: } sl@0: sl@0: PMemMgr* PMemMgr::TheMgr; sl@0: sl@0: // Create a 'size bucket' memory manager consisting of a number of memory pools sl@0: // each containing blocks of the same size. The block size increases from one sl@0: // pool to the next. sl@0: void PMemMgr::Create(const poolinfo* aInfo) sl@0: { sl@0: TInt n; sl@0: for (n=0; aInfo[n].block_size; ++n) {} sl@0: PMemMgr* m = (PMemMgr*)Kern::Alloc(sizeof(PMemMgr) + (n-1)*sizeof(PMemPool)); sl@0: __KTRACE_OPT(KBOOT, Kern::Printf("PMemMgr::Create %08x NumPools=%d", m, n)); sl@0: __NK_ASSERT_ALWAYS(m!=NULL); sl@0: m->iPoolCount = n; sl@0: TInt i; sl@0: size_t prev_sz=0; sl@0: for (i=0; i prev_sz); sl@0: prev_sz = aInfo[i].block_size; sl@0: TInt r = m->iPools[i].Create(aInfo+i); sl@0: __NK_ASSERT_ALWAYS(r==KErrNone); sl@0: } sl@0: TheMgr = m; sl@0: } sl@0: sl@0: // Allocate a memory block of the requested size (or the next larger size if necessary). sl@0: void* PMemMgr::Alloc(size_t aSize) sl@0: { sl@0: __KTRACE_OPT(KBOOT, Kern::Printf("MA:%04x", aSize)); sl@0: void* b = NULL; sl@0: PMemPool* p = &TheMgr->iPools[0]; sl@0: PMemPool* q = p + TheMgr->iPoolCount; sl@0: for (; piBlockSize < aSize; ++p) {} sl@0: if (p < q) sl@0: { sl@0: TInt irq = NKern::DisableAllInterrupts(); sl@0: b = p->Alloc(); sl@0: NKern::RestoreInterrupts(irq); sl@0: } sl@0: return b; sl@0: } sl@0: sl@0: // Free a memory block sl@0: void PMemMgr::Free(void* aPtr) sl@0: { sl@0: __KTRACE_OPT(KBOOT, Kern::Printf("MF:%08x", aPtr)); sl@0: SMemBlock* b = _LOFF(aPtr, SMemBlock, iNext); sl@0: TInt irq = NKern::DisableAllInterrupts(); sl@0: b->iPool->Free(b); sl@0: NKern::RestoreInterrupts(irq); sl@0: } sl@0: sl@0: sl@0: /* Memory management APIs */ sl@0: extern "C" { sl@0: void* alloc_mem_block(size_t size) sl@0: { sl@0: return PMemMgr::Alloc(size); sl@0: } sl@0: sl@0: void free_mem_block(void* block) sl@0: { sl@0: PMemMgr::Free(block); sl@0: } sl@0: } sl@0: sl@0: /****************************************************************************** sl@0: * Task management sl@0: ******************************************************************************/ sl@0: sl@0: TInt PThread::NumTasks; sl@0: TInt PThread::MaxTaskId; sl@0: PThread** PThread::TaskTable; sl@0: sl@0: // RTOS priority to nanokernel priority mapping sl@0: const TUint8 PThread::NThreadPriorityTable[MAX_TASK_PRIORITY+1] = sl@0: { sl@0: 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, sl@0: 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, sl@0: 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, sl@0: 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, sl@0: 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, sl@0: 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, sl@0: 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b, sl@0: 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, sl@0: 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, sl@0: 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, sl@0: 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, sl@0: 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, sl@0: 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, sl@0: 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, 0x37, 0x37, sl@0: 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, sl@0: 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f sl@0: }; sl@0: sl@0: // Handlers for personality layer threads sl@0: const SNThreadHandlers PThread::Handlers = sl@0: { sl@0: NULL, // no exit handler sl@0: &StateHandler, sl@0: &ExceptionHandler, sl@0: NULL // no timeout handler sl@0: }; sl@0: sl@0: // Create a personality layer thread sl@0: TInt PThread::Create(PThread*& aThread, const taskinfo* a) sl@0: { sl@0: if (!a->entry_pt) sl@0: return BAD_ENTRY_POINT; sl@0: if (a->priority < MIN_TASK_PRIORITY || a->priority > MAX_TASK_PRIORITY) sl@0: return BAD_PRIORITY; sl@0: if (a->stack_size & 3 || a->stack_size < MIN_STACK_SIZE) sl@0: return BAD_STACK_SIZE; sl@0: if (a->task_id < 0) sl@0: return BAD_TASK_ID; sl@0: TInt memsize = sizeof(PThread) + a->stack_size; sl@0: PThread* t = (PThread*)Kern::Alloc(memsize); sl@0: if (!t) sl@0: return OUT_OF_MEMORY; sl@0: t->iTaskId = a->task_id; sl@0: t->iSetPriority = a->priority; sl@0: t->iFirstMsg = NULL; sl@0: t->iLastMsg = NULL; sl@0: t->iISRFirstMsg = NULL; sl@0: t->iISRLastMsg = NULL; sl@0: new (&t->iMsgQIDfc) TDfc(&MsgQIDfcFn, t); sl@0: TAny* stack = t + 1; sl@0: memset(stack, 0xbb, a->stack_size); sl@0: SNThreadCreateInfo info; sl@0: info.iFunction = (NThreadFunction)a->entry_pt; sl@0: info.iStackBase = stack; sl@0: info.iStackSize = a->stack_size; sl@0: info.iPriority = NThreadPriorityTable[a->priority]; sl@0: info.iTimeslice = -1; // no timeslicing sl@0: info.iAttributes = 0; sl@0: info.iHandlers = &Handlers; sl@0: info.iFastExecTable = NULL; sl@0: info.iSlowExecTable = NULL; sl@0: info.iParameterBlock = NULL; sl@0: info.iParameterBlockSize = 0; sl@0: TInt r = NKern::ThreadCreate(t, info); sl@0: __NK_ASSERT_ALWAYS(r==KErrNone); sl@0: aThread = t; sl@0: return OK; sl@0: } sl@0: sl@0: // Create all required personality layer threads sl@0: void PThread::CreateAll(const taskinfo* a) sl@0: { sl@0: TInt n = 0; sl@0: TInt maxid = -1; sl@0: for (; a[n].entry_pt; ++n) sl@0: { sl@0: if (a[n].task_id > maxid) sl@0: maxid = a[n].task_id; sl@0: } sl@0: NumTasks = n; sl@0: MaxTaskId = maxid; sl@0: TaskTable = (PThread**)Kern::AllocZ((maxid+1) * sizeof(PThread*)); sl@0: __NK_ASSERT_ALWAYS(TaskTable != NULL); sl@0: TInt i; sl@0: for (i=0; iHandleSuspend(); sl@0: break; sl@0: case NThreadBase::EResume: sl@0: case NThreadBase::EForceResume: sl@0: t->HandleResume(); sl@0: break; sl@0: case NThreadBase::ERelease: sl@0: t->HandleRelease(aParam); sl@0: break; sl@0: case NThreadBase::EChangePriority: sl@0: t->HandlePriorityChange(aParam); sl@0: break; sl@0: case NThreadBase::ETimeout: sl@0: t->HandleTimeout(); sl@0: break; sl@0: case NThreadBase::ELeaveCS: sl@0: default: sl@0: __NK_ASSERT_ALWAYS(0); sl@0: } sl@0: } sl@0: sl@0: // Exception handler - just fault sl@0: void PThread::ExceptionHandler(TAny* aContext, NThread* aThread) sl@0: { sl@0: (void)aThread; sl@0: Exc::Fault(aContext); sl@0: } sl@0: sl@0: // Post a message to this thread from an ISR sl@0: void PThread::ISRPost(msghdr* aM) sl@0: { sl@0: aM->next = NULL; sl@0: aM->sending_task_id = TASK_ID_ISR; sl@0: msghdr* prev = (msghdr*)__e32_atomic_swp_ord_ptr(&iISRLastMsg, aM); sl@0: if (prev) sl@0: prev->next = aM; sl@0: else sl@0: { sl@0: iISRFirstMsg = aM; sl@0: iMsgQIDfc.Add(); sl@0: } sl@0: } sl@0: sl@0: // IDFC used to post message from ISR sl@0: void PThread::MsgQIDfcFn(TAny* aPtr) sl@0: { sl@0: PThread* t = (PThread*)aPtr; sl@0: TInt irq = NKern::DisableAllInterrupts(); sl@0: msghdr* m = t->iISRFirstMsg; sl@0: msghdr* l = t->iISRLastMsg; sl@0: t->iISRFirstMsg = NULL; sl@0: t->iISRLastMsg = NULL; sl@0: NKern::RestoreInterrupts(irq); sl@0: t->Post(m, l); sl@0: } sl@0: sl@0: // Post a chain of messages to this thread from an IDFC or thread sl@0: // Enter and return with preemption disabled sl@0: void PThread::Post(msghdr* aFirst, msghdr* aLast) sl@0: { sl@0: msghdr* l = iLastMsg; sl@0: iLastMsg = aLast; sl@0: if (l) sl@0: { sl@0: l->next = aFirst; sl@0: return; // queue was not empty so thread can't be waiting sl@0: } sl@0: iFirstMsg = aFirst; sl@0: if (iNState == EWaitMsgQ) sl@0: Release(KErrNone); sl@0: } sl@0: sl@0: // Dequeue and return the first message if there is one sl@0: // Return NULL if no messages waiting sl@0: // Enter and return with preemption disabled sl@0: msghdr* PThread::GetMsg() sl@0: { sl@0: msghdr* m = iFirstMsg; sl@0: if (m) sl@0: { sl@0: iFirstMsg = m->next; sl@0: if (!iFirstMsg) sl@0: iLastMsg = NULL; sl@0: } sl@0: return m; sl@0: } sl@0: sl@0: void PThread::HandleSuspend() sl@0: { sl@0: switch(iNState) sl@0: { sl@0: case EWaitMsgQ: sl@0: break; sl@0: case EWaitSemaphore: sl@0: ((PSemaphore*)iWaitObj)->SuspendWaitingThread(this); sl@0: break; sl@0: default: sl@0: __NK_ASSERT_ALWAYS(0); sl@0: } sl@0: } sl@0: sl@0: void PThread::HandleResume() sl@0: { sl@0: switch(iNState) sl@0: { sl@0: case EWaitMsgQ: sl@0: break; sl@0: case EWaitSemaphore: sl@0: ((PSemaphore*)iWaitObj)->ResumeWaitingThread(this); sl@0: break; sl@0: default: sl@0: __NK_ASSERT_ALWAYS(0); sl@0: } sl@0: } sl@0: sl@0: void PThread::HandleRelease(TInt aReturnCode) sl@0: { sl@0: (void)aReturnCode; sl@0: switch(iNState) sl@0: { sl@0: case EWaitMsgQ: sl@0: CheckSuspendThenReady(); sl@0: break; sl@0: case EWaitSemaphore: sl@0: if (aReturnCode<0) sl@0: ((PSemaphore*)iWaitObj)->WaitCancel(this); sl@0: else sl@0: CheckSuspendThenReady(); sl@0: break; sl@0: default: sl@0: __NK_ASSERT_ALWAYS(0); sl@0: } sl@0: } sl@0: sl@0: void PThread::HandlePriorityChange(TInt aNewPriority) sl@0: { sl@0: (void)aNewPriority; sl@0: switch(iNState) sl@0: { sl@0: case EWaitMsgQ: sl@0: iPriority = (TUint8)aNewPriority; sl@0: break; sl@0: case EWaitSemaphore: sl@0: ((PSemaphore*)iWaitObj)->ChangeWaitingThreadPriority(this, aNewPriority); sl@0: break; sl@0: default: sl@0: __NK_ASSERT_ALWAYS(0); sl@0: } sl@0: } sl@0: sl@0: void PThread::HandleTimeout() sl@0: { sl@0: switch(iNState) sl@0: { sl@0: case EWaitMsgQ: sl@0: CheckSuspendThenReady(); sl@0: break; sl@0: case EWaitSemaphore: sl@0: ((PSemaphore*)iWaitObj)->WaitCancel(this); sl@0: break; sl@0: default: sl@0: __NK_ASSERT_ALWAYS(0); sl@0: } sl@0: } sl@0: sl@0: sl@0: /* Task APIs */ sl@0: extern "C" { sl@0: int suspend_task(int id) sl@0: { sl@0: if (TUint(id) > TUint(PThread::MaxTaskId)) sl@0: return BAD_TASK_ID; sl@0: PThread* t = PThread::TaskTable[id]; sl@0: if (!t) sl@0: return BAD_TASK_ID; sl@0: NKern::ThreadSuspend(t, 1); sl@0: return OK; sl@0: } sl@0: sl@0: int resume_task(int id) sl@0: { sl@0: if (TUint(id) > TUint(PThread::MaxTaskId)) sl@0: return BAD_TASK_ID; sl@0: PThread* t = PThread::TaskTable[id]; sl@0: if (!t) sl@0: return BAD_TASK_ID; sl@0: NKern::ThreadResume(t); sl@0: return OK; sl@0: } sl@0: sl@0: int get_task_priority(int id) sl@0: { sl@0: if (TUint(id) > TUint(PThread::MaxTaskId)) sl@0: return BAD_TASK_ID; sl@0: PThread* t = PThread::TaskTable[id]; sl@0: if (!t) sl@0: return BAD_TASK_ID; sl@0: return t->iSetPriority; sl@0: } sl@0: sl@0: int set_task_priority(int id, int priority) sl@0: { sl@0: if (TUint(id) > TUint(PThread::MaxTaskId)) sl@0: return BAD_TASK_ID; sl@0: PThread* t = PThread::TaskTable[id]; sl@0: if (!t) sl@0: return BAD_TASK_ID; sl@0: if (priority < MIN_TASK_PRIORITY || priority > MAX_TASK_PRIORITY) sl@0: return BAD_PRIORITY; sl@0: NKern::Lock(); sl@0: t->iSetPriority = priority; sl@0: t->SetPriority(PThread::NThreadPriorityTable[priority]); sl@0: NKern::Unlock(); sl@0: return OK; sl@0: } sl@0: sl@0: int current_task_id(void) sl@0: { sl@0: TInt c = NKern::CurrentContext(); sl@0: if (c == NKern::EInterrupt) sl@0: return TASK_ID_ISR; sl@0: PThread* t = (PThread*)NKern::CurrentThread(); sl@0: if (t->iHandlers == &PThread::Handlers) sl@0: return t->iTaskId; sl@0: return TASK_ID_UNKNOWN; sl@0: } sl@0: sl@0: void disable_preemption(void) sl@0: { sl@0: NKern::Lock(); sl@0: } sl@0: sl@0: void enable_preemption(void) sl@0: { sl@0: NKern::Unlock(); sl@0: } sl@0: sl@0: int disable_interrupts(void) sl@0: { sl@0: return NKern::DisableAllInterrupts(); sl@0: } sl@0: sl@0: void restore_interrupts(int level) sl@0: { sl@0: NKern::RestoreInterrupts(level); sl@0: } sl@0: sl@0: sl@0: /* Message APIs */ sl@0: int send_msg(int task_id, msghdr* msg) sl@0: { sl@0: if (TUint(task_id) > TUint(PThread::MaxTaskId)) sl@0: return BAD_TASK_ID; sl@0: PThread* t = PThread::TaskTable[task_id]; sl@0: if (!t) sl@0: return BAD_TASK_ID; sl@0: TInt c = NKern::CurrentContext(); sl@0: if (c == NKern::EInterrupt) sl@0: { sl@0: t->ISRPost(msg); sl@0: return OK; sl@0: } sl@0: msg->next = NULL; sl@0: PThread* st = (PThread*)NKern::CurrentThread(); sl@0: msg->sending_task_id = (st->iHandlers == &PThread::Handlers) ? st->iTaskId : TASK_ID_UNKNOWN; sl@0: NKern::Lock(); sl@0: t->Post(msg, msg); sl@0: NKern::Unlock(); sl@0: return OK; sl@0: } sl@0: sl@0: int recv_msg(msghdr** msgptr, int time_ticks) sl@0: { sl@0: if (time_ticks < WAIT_FOREVER) sl@0: return BAD_TIME_INTERVAL; sl@0: PThread* t = (PThread*)NKern::CurrentThread(); sl@0: NKern::Lock(); sl@0: msghdr* m = t->GetMsg(); sl@0: if (!m && time_ticks != NO_WAIT) sl@0: { sl@0: NKern::NanoBlock(time_ticks>0 ? time_ticks : 0, PThread::EWaitMsgQ, NULL); sl@0: NKern::PreemptionPoint(); sl@0: m = t->GetMsg(); sl@0: } sl@0: NKern::Unlock(); sl@0: *msgptr = m; sl@0: return m ? OK : TIMED_OUT; sl@0: } sl@0: } sl@0: sl@0: /****************************************************************************** sl@0: * Timer management sl@0: ******************************************************************************/ sl@0: sl@0: TInt PTimer::NumTimers; sl@0: PTimer* PTimer::TimerTable; sl@0: sl@0: // Create all required timers sl@0: void PTimer::CreateAll() sl@0: { sl@0: NumTimers = timer_count; sl@0: TimerTable = new PTimer[timer_count]; sl@0: __NK_ASSERT_ALWAYS(TimerTable != NULL); sl@0: } sl@0: sl@0: PTimer::PTimer() sl@0: : NTimer(NTimerExpired, this), sl@0: iPeriod(0), sl@0: iCookie(0), sl@0: iThread(0), sl@0: iExpiryCount(0) sl@0: { sl@0: } sl@0: sl@0: void PTimer::NTimerExpired(TAny* aPtr) sl@0: { sl@0: timer_msg* m = (timer_msg*)alloc_mem_block(sizeof(timer_msg)); sl@0: m->header.next = 0; sl@0: m->header.msg_id = MSG_ID_TIMEOUT; sl@0: PTimer* p = (PTimer*)aPtr; sl@0: TInt irq = NKern::DisableAllInterrupts(); sl@0: PThread* t = p->iThread; sl@0: m->count = ++p->iExpiryCount; sl@0: m->cookie = p->iCookie; sl@0: if (p->iPeriod > 0) sl@0: p->Again(p->iPeriod); sl@0: NKern::RestoreInterrupts(irq); sl@0: t->ISRPost(&m->header); sl@0: } sl@0: sl@0: /* Timer APIs */ sl@0: extern "C" { sl@0: unsigned tick_count(void) sl@0: { sl@0: return NKern::TickCount(); sl@0: } sl@0: sl@0: void delay(int time_interval) sl@0: { sl@0: __NK_ASSERT_ALWAYS(time_interval > 0); sl@0: NKern::Sleep(time_interval); sl@0: } sl@0: sl@0: int start_one_shot_timer(int timer_id, int task_id, int time_ticks, void* cookie) sl@0: { sl@0: if (time_ticks <= 0) sl@0: return BAD_TIME_INTERVAL; sl@0: if (TUint(timer_id) >= TUint(PTimer::NumTimers)) sl@0: return BAD_TIMER_ID; sl@0: PTimer* tmr = PTimer::TimerTable + timer_id; sl@0: if (TUint(task_id) > TUint(PThread::MaxTaskId)) sl@0: return BAD_TASK_ID; sl@0: PThread* t = PThread::TaskTable[task_id]; sl@0: if (!t) sl@0: return BAD_TASK_ID; sl@0: TInt r = OK; sl@0: TInt irq = NKern::DisableAllInterrupts(); sl@0: if (tmr->iThread) sl@0: r = TIMER_IN_USE; sl@0: else sl@0: { sl@0: tmr->iPeriod = 0; sl@0: tmr->iCookie = cookie; sl@0: tmr->iThread = t; sl@0: tmr->iExpiryCount = 0; sl@0: tmr->OneShot(time_ticks, EFalse); sl@0: } sl@0: NKern::RestoreInterrupts(irq); sl@0: return r; sl@0: } sl@0: sl@0: int start_periodic_timer(int timer_id, int task_id, int initial_time_ticks, int period_ticks, void* cookie) sl@0: { sl@0: if (initial_time_ticks <= 0 || period_ticks <= 0) sl@0: return BAD_TIME_INTERVAL; sl@0: if (TUint(timer_id) >= TUint(PTimer::NumTimers)) sl@0: return BAD_TIMER_ID; sl@0: PTimer* tmr = PTimer::TimerTable + timer_id; sl@0: if (TUint(task_id) > TUint(PThread::MaxTaskId)) sl@0: return BAD_TASK_ID; sl@0: PThread* t = PThread::TaskTable[task_id]; sl@0: if (!t) sl@0: return BAD_TASK_ID; sl@0: TInt r = OK; sl@0: TInt irq = NKern::DisableAllInterrupts(); sl@0: if (tmr->iThread) sl@0: r = TIMER_IN_USE; sl@0: else sl@0: { sl@0: tmr->iPeriod = period_ticks; sl@0: tmr->iCookie = cookie; sl@0: tmr->iThread = t; sl@0: tmr->iExpiryCount = 0; sl@0: tmr->OneShot(initial_time_ticks, EFalse); sl@0: } sl@0: NKern::RestoreInterrupts(irq); sl@0: return r; sl@0: } sl@0: sl@0: int stop_timer(int timer_id) sl@0: { sl@0: if (TUint(timer_id) >= TUint(PTimer::NumTimers)) sl@0: return BAD_TIMER_ID; sl@0: PTimer* tmr = PTimer::TimerTable + timer_id; sl@0: TInt irq = NKern::DisableAllInterrupts(); sl@0: tmr->Cancel(); sl@0: tmr->iThread = NULL; sl@0: NKern::RestoreInterrupts(irq); sl@0: return OK; sl@0: } sl@0: } sl@0: sl@0: sl@0: /****************************************************************************** sl@0: * Semaphore management sl@0: ******************************************************************************/ sl@0: sl@0: TInt PSemaphore::NumSemaphores; sl@0: PSemaphore* PSemaphore::SemaphoreTable; sl@0: sl@0: void PSemaphore::CreateAll() sl@0: { sl@0: NumSemaphores = semaphore_count; sl@0: SemaphoreTable = new PSemaphore[semaphore_count]; sl@0: __NK_ASSERT_ALWAYS(SemaphoreTable != NULL); sl@0: } sl@0: sl@0: PSemaphore::PSemaphore() sl@0: : iCount(0), sl@0: iISRCount(0), sl@0: iIDfc(IDfcFn, this) sl@0: { sl@0: } sl@0: sl@0: void PSemaphore::WaitCancel(PThread* aThread) sl@0: { sl@0: if (aThread->iSuspendCount == 0) sl@0: { sl@0: iWaitQ.Remove(aThread); sl@0: ++iCount; sl@0: } sl@0: else sl@0: aThread->Deque(); sl@0: aThread->CheckSuspendThenReady(); sl@0: } sl@0: sl@0: void PSemaphore::SuspendWaitingThread(PThread* aThread) sl@0: { sl@0: // do nothing if already suspended sl@0: if (aThread->iSuspendCount == 0) sl@0: { sl@0: iWaitQ.Remove(aThread); sl@0: ++iCount; sl@0: iSuspendedQ.Add(aThread); sl@0: } sl@0: } sl@0: sl@0: void PSemaphore::ResumeWaitingThread(PThread* aThread) sl@0: { sl@0: aThread->Deque(); sl@0: if (--iCount<0) sl@0: { sl@0: iWaitQ.Add(aThread); sl@0: } sl@0: else sl@0: { sl@0: aThread->iWaitObj=NULL; sl@0: aThread->Ready(); sl@0: } sl@0: } sl@0: sl@0: void PSemaphore::ChangeWaitingThreadPriority(PThread* aThread, TInt aNewPriority) sl@0: { sl@0: if (aThread->iSuspendCount == 0) sl@0: iWaitQ.ChangePriority(aThread, aNewPriority); sl@0: else sl@0: aThread->iPriority = (TUint8)aNewPriority; sl@0: } sl@0: sl@0: void PSemaphore::Signal() sl@0: { sl@0: if (++iCount <= 0) sl@0: { sl@0: // must wake up next thread sl@0: PThread* t = iWaitQ.First(); sl@0: iWaitQ.Remove(t); sl@0: t->Release(KErrNone); sl@0: } sl@0: } sl@0: sl@0: void PSemaphore::ISRSignal() sl@0: { sl@0: if (__e32_atomic_add_ord32(&iISRCount, 1) == 0) sl@0: iIDfc.Add(); sl@0: } sl@0: sl@0: void PSemaphore::IDfcFn(TAny* aPtr) sl@0: { sl@0: PSemaphore* s = (PSemaphore*)aPtr; sl@0: TInt count = (TInt)__e32_atomic_swp_ord32(&s->iISRCount, 0); sl@0: while (count--) sl@0: s->Signal(); sl@0: } sl@0: sl@0: /* Semaphore APIs */ sl@0: extern "C" { sl@0: int semaphore_wait(int sem_id, int time_ticks) sl@0: { sl@0: if (time_ticks < WAIT_FOREVER) sl@0: return BAD_TIME_INTERVAL; sl@0: if (TUint(sem_id) >= TUint(PSemaphore::NumSemaphores)) sl@0: return BAD_SEM_ID; sl@0: PSemaphore* s = PSemaphore::SemaphoreTable + sem_id; sl@0: PThread* t = (PThread*)NKern::CurrentThread(); sl@0: TInt r = OK; sl@0: NKern::Lock(); sl@0: if (time_ticks == NO_WAIT) sl@0: { sl@0: if (s->iCount <= 0) sl@0: r = TIMED_OUT; sl@0: else sl@0: --s->iCount; sl@0: NKern::Unlock(); sl@0: return r; sl@0: } sl@0: if (--s->iCount < 0) sl@0: { sl@0: NKern::NanoBlock(time_ticks>0 ? time_ticks : 0, PThread::EWaitSemaphore, s); sl@0: s->iWaitQ.Add(t); sl@0: NKern::PreemptionPoint(); sl@0: if (t->iReturnValue == KErrTimedOut) sl@0: r = TIMED_OUT; sl@0: } sl@0: NKern::Unlock(); sl@0: return r; sl@0: } sl@0: sl@0: int semaphore_signal(int sem_id) sl@0: { sl@0: if (TUint(sem_id) >= TUint(PSemaphore::NumSemaphores)) sl@0: return BAD_SEM_ID; sl@0: PSemaphore* s = PSemaphore::SemaphoreTable + sem_id; sl@0: TInt c = NKern::CurrentContext(); sl@0: if (c == NKern::EInterrupt) sl@0: { sl@0: s->ISRSignal(); sl@0: return OK; sl@0: } sl@0: NKern::Lock(); sl@0: s->Signal(); sl@0: NKern::Unlock(); sl@0: return OK; sl@0: } sl@0: sl@0: void init_personality(void) sl@0: { sl@0: __KTRACE_OPT(KBOOT,Kern::Printf("Starting example personality")); sl@0: sl@0: PMemMgr::Create(pool_list); sl@0: PTimer::CreateAll(); sl@0: PSemaphore::CreateAll(); sl@0: PThread::CreateAll(task_list); sl@0: } sl@0: } sl@0: sl@0: /****************************************************************************** sl@0: * Communication with EPOC sl@0: ******************************************************************************/ sl@0: TPMsgQ* TPMsgQ::ThePMsgQ; sl@0: sl@0: TPMsgQ::TPMsgQ(TDfcFn aFunction, TAny* aPtr, TDfcQue* aDfcQ, TInt aPriority) sl@0: : TDfc(aFunction, aPtr, aDfcQ, aPriority), sl@0: iFirstMsg(NULL), sl@0: iLastMsg(NULL), sl@0: iReady(EFalse) sl@0: { sl@0: } sl@0: sl@0: extern "C" void send_to_epoc(msghdr* m) sl@0: { sl@0: TPMsgQ* q = TPMsgQ::ThePMsgQ; sl@0: m->next = NULL; sl@0: m->sending_task_id = current_task_id(); sl@0: NKern::Lock(); sl@0: msghdr* l = q->iLastMsg; sl@0: q->iLastMsg = m; sl@0: if (l) sl@0: { sl@0: l->next = m; sl@0: NKern::Unlock(); sl@0: return; // queue was not empty so thread can't be waiting sl@0: } sl@0: q->iFirstMsg = m; sl@0: if (q->iReady) sl@0: { sl@0: q->iReady = EFalse; sl@0: q->DoEnque(); sl@0: } sl@0: NKern::Unlock(); sl@0: } sl@0: sl@0: void TPMsgQ::Receive() sl@0: { sl@0: NKern::Lock(); sl@0: if (iFirstMsg) sl@0: DoEnque(); sl@0: else sl@0: iReady = ETrue; sl@0: NKern::Unlock(); sl@0: } sl@0: sl@0: msghdr* TPMsgQ::Get() sl@0: { sl@0: NKern::Lock(); sl@0: msghdr* m = iFirstMsg; sl@0: if (m) sl@0: { sl@0: iFirstMsg = m->next; sl@0: if (!iFirstMsg) sl@0: iLastMsg = NULL; sl@0: } sl@0: NKern::Unlock(); sl@0: return m; sl@0: } sl@0: sl@0: void TPMsgQ::CancelReceive() sl@0: { sl@0: iReady = EFalse; sl@0: Cancel(); sl@0: } sl@0: sl@0: