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