kernel/eka/personality/example/personality.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     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