diff -r 578be2adaf3e -r 307f4279f433 Adaptation/GUID-42F8FA5A-BBE4-50DE-917E-D05755019FEC.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adaptation/GUID-42F8FA5A-BBE4-50DE-917E-D05755019FEC.dita Fri Oct 15 14:32:18 2010 +0100 @@ -0,0 +1,232 @@ + + + + + +Personality Layer DesignProvides some guidelines for the design of a personality +layer for real time Applications for the Kernel. +
Memory +management

The personality layer assumes that the RTA will +run in a single flat address space in which there is neither protection +between different parts of the application nor protection of any hardware +or CPU resource from any part of the application. For example, any +part of the application code can access any I/O port, and can disable +interrupts.

To get this behaviour under the Kernel Architecture +2, the RTA must run in supervisor mode in the kernel address space. +The obvious way to do this is to make the RTA together with the personality +layer a kernel extension. This also ensures that it is started automatically +early on in the boot process.

In general the RTA will have +its own memory management strategy and will not wish to use the standard +Symbian platform memory management system. To achieve this, the personality +layer will allocate a certain fixed amount of RAM for use by the real +time application at boot time. For a telephony stack this will be +around 128K - 256K. This can be done either by including it in the +kernel extension's .bss section, or by making +a one-time allocation on the kernel heap at boot time. Depending on +the RTA requirements, the personality layer can manage this area of +RAM (if the RTOS being emulated provides memory management primitives) +or the RTA can manage it.

+
Threads +and mapping thread priorities

A nanokernel thread will +be used for each RTOS thread

A priority mapping scheme will +be required to map RTOS priorities, of which there are typically 64 +to 256 distinct values, to nanokernel priorities. As long as the RTA +does not use more than 35 threads running simultaneously, which is +usually the case, it should be possible to produce a mapping scheme +that allows each thread to have a distinct priority, if needed. If +this limit is exceeded, it will be necessary to fold some priorities +together.

Note that any attempt to increase the number of +priorities supported by both the nanokernel and the Symbian platform +kernel would be prohibitively expensive in terms of RAM usage.

+
Communication +between Symbian platform and the RTOS Environments

To allow +the functionality of the RTA to be available to Symbian platform applications, +it is necessary that a mechanism exist by which Symbian platform code +and the RTA may communicate with each other. In practice this means:

    +
  • it must be possible +for a Symbian platform thread to cause an RTOS thread to be scheduled +and vice-versa

  • +
  • it must be possible +for data to be transferred between Symbian platform and RTOS threads +in both directions.

  • +

It will usually be possible for a Symbian platform thread +to make standard personality layer calls (the same calls that RTOS +threads would make) in order to cause an RTOS thread to be scheduled. +This is because the nanokernel underlies both types of thread and +most 'signal' type operations (i.e. those that make threads ready +rather than blocking them) can be implemented using operations which +make no reference to the calling thread, and which are therefore not +sensitive to which type of thread they are called from.

The +standard personality layer calls will not work in the other direction, +since it will not be possible for a Symbian platform thread to wait +on a personality layer wait object. The most straightforward way for +RTOS threads to trigger scheduling of a Symbian platform thread would +be to enque a DFC on a queue operated by a Symbian platform thread. +Another possibility would be for the Symbian platform thread to wait +on a fast semaphore which could then be signalled by the RTOS thread. +However the DFC method fits better with the way device drivers are +generally written. A device driver will be necessary to mediate communication +between Symbian platform user mode processes and the RTA since the +latter runs kernel side.

All data transfer between the two +environments must occur kernel side. It will not be possible for any +RTOS thread to access normal user side memory since the functions +provided for doing so access parts of the DThread structure representing the Symbian platform calling thread, for +example to perform exception trapping. Some possibilities for the +data transfer mechanism are:

    +
  • A fairly common +architecture for real time applications involves a fixed block size +memory manager and message queues for inter-thread communication. +The memory manager supports allocation and freeing of memory in constant +time. The sending thread allocates a memory block, places data in +it and posts it to the receiving thread's message queue. The receiving +thread then processes the data and frees the memory block, or possibly +passes the block to yet another thread. It would be a simple proposition +to produce such a system in which the memory manager could be used +by any thread. In that case a Symbian platform thread could pass messages +to RTOS threads in the same way as other RTOS threads. Passing data +back would involve a special type of message queue implemented in +the personality layer. When a message was sent to a Symbian platform +thread a DFC would be enqueued. That DFC would then process the message +data and free the memory block as usual. This scheme combines the +data transfer and scheduling aspects of communication.

  • +
  • Any standard +buffering arrangement could be used between the RTA and the device +driver (e.g. circular buffers). Contention between threads could be +prevented using nanokernel fast mutexes, on which any thread can wait, +or by the simpler means of disabling preemption or disabling interrupts. +It will also be possible for RTOS threads to make use of shared I/O +buffers for transfer direct to user mode clients, provided that these +buffers are set up by the Symbian platform device driver thread. This +may be useful as a way to reduce copying overhead if bulk data transfer +is necessary between the two domains.

  • +
+
Synchronisation/communication +primitives

The nanokernel does not support most of the +synchronisation and communication primitives provided by a standard +RTOS. Any such primitives required by the RTA will have to be implemented +in the personality layer. This means that the personality layer needs +to define new types of object on which threads can wait. This in turn +means that new nanokernel thread states (N-state) must be defined +to signify that a thread is waiting on an object of the new type. +In general, each new type of wait object requires an accompanying +new nanokernel thread state.

Blocking a thread on a wait object

To make a thread +block on a new type of wait object, call the nanokernel function Kern::NanoBlock(), passing the maximum time for which the +thread should block, the new N-state value, and a pointer to the wait +object.

Use the TPriListLink base class of NThreadBase to attach the thread to a list of threads waiting +on the object. Note that this must be done after calling Kern::NanoBlock(). As preemption is disabled before this +function is called, a reschedule will not occur immediately, but will +be deferred until preemption is reenabled.

State handler

Every thread that can use a new type of wait object, must +have a nanokernel state handler installed to handle operations on +that thread when it is waiting on that wait object. A nanokernel state +handler is a function that has the following signature:

void StateHandler(NThread* aThread, TInt aOp, TInt aParam);
    +
  • aThread is a pointer to the thread involved.

  • +
  • aOp is one of the NThreadBase::NThreadOperation values +that indicates which operation is being performed on the thread.

  • +
  • aParam is a parameter that depends on aOp.

  • +

Note that the state handler is always called with preemption +disabled.

The possible values of aOp are:

+ + + +

aOp value

+

Description

+
+ +

ESuspend

+

Called if the thread is suspended while not in a critical +section and not holding a fast mutex. Called in whichever context NThreadBase::Suspend() is called from.

aParam contains the requested suspension count.

+
+ +

EResume

+

Called if the thread is resumed while actually suspended, +and the last suspension has been removed. Called in whichever context NThreadBase::Resume() is called from.

aParam contains no additional information.

+
+ +

EForceResume

+

Called if the thread has all suspensions cancelled while +actually suspended. Called in whichever context NThreadBase::ForceResume() is called from.

aParam contains no additional +information.

+
+ +

ERelease

+

Called if the thread is released from its wait. This call +should make the thread ready if necessary. Called in whichever context NThreadBase::Release() was called from.

aParam is the value passed into NThreadBase::Release() to be used as a return code.

If aParam is +non-negative, this indicates normal termination of the wait condition.

If aParam is negative, it indicates early or +abnormal termination of the wait; in this case the wait object should +be rolled back as if the wait had never occurred. For example, a semaphore's +count needs to be incremented if aParam is negative, +since in that case the waiting thread never acquired the semaphore.

+
+ +

EChangePriority

+

Called if the thread's priority is changed. Called in whichever +context NThreadBase::SetPriority() is called from. +This function should set the iPriority field of the +thread, after doing any necessary priority queue manipulations.

aParam contains the new priority.

+
+ +

ELeaveCS

+

Called in the context of the thread concerned if the thread +calls NKern::ThreadLeaveCS() with an unknown iCsFunction that is negative but not equal to ECsExitPending.

aParam contains the value of iCsFunction.

+
+ +

ETimeout

+

Called if the thread's wait time-out expires and no time-out +handler is defined for that thread. Called in the context of the nanokernel +timer thread (DfcThread1). This should cancel the wait and arrange +for an appropriate error code to be returned. The handler for this +condition will usually do the same thing as the handler for ERelease with a parameter of KErrTimedOut.

aParam contains no additional information.

+
+ + +

See the code in ...\e32\personality\example\... for practical examples.

Releasing the thread

When a thread's wait condition +is resolved, the nanokernel function NThreadBase::Release() should be called. This takes a single TInt parameter.

The parameter is usually KErrNone, if the +wait condition is resolved normally. A typical example is where the +semaphore on which the thread is waiting, is signalled. A negative +parameter value is used for an abnormal termination, and in this case, +the wait object may need to be rolled back.

NThreadBase::Release() should be called with preemption disabled. It performs the following +actions:

    +
  • sets the NThreadBase::iWaitObj field to NULL

  • +
  • cancels the +wait timer if it is still running

  • +
  • stores the supplied +return code in NThreadBase::iReturnCode

  • +
  • calls the state handler passing ERelease and the return +code. If the return code is negative this should remove the thread +from any wait queues and roll back the state of the wait object. In +any case it should call NThreadBase::CheckSuspendThenReady() to make the thread ready again if necessary.

  • +
+
Thread +scheduling following a hardware interrupt

Most RTOS allow +interrupt service routines (ISRs) to perform operations such as semaphore +signal, queue post, set event flag directly, usually using the same +API as would be used in a thread context. The Kernel Architecture +2 nanokernel does not allow this; ISRs can only queue an IDFC or DFC.

The way to get round this limitation is to incorporate an IDFC +into each personality layer wait object. The personality layer API +involved then needs to check whether it is being invoked from an ISR +or a thread and, in the first case, it queues the IDFC. It may need +to save some other information for use by the IDFC, for example, it +may need to maintain a list of messages queued from ISRs, a count +of semaphore signals from ISRs or a bit mask of event flags set by +ISRs. Checking for invocation from an ISR can be done either by using NKern::CurrentContext(), or by checking the CPSR directly; +if doing the latter note that any mode other than USR or SVC on the +ARM counts as interrupt context.

Hardware interrupts serviced +by the RTA will need to conform to the same pattern as those serviced +by Symbian platform extensions or device drivers. This means that +the standard preamble must run before the actual service routine and +the nanokernel interrupt postamble must run after the service routine +to enable reschedules to occur if necessary. This can be done by calling Interrupt::Bind() as provided by the base port during RTA +initialisation (possibly via a personality layer call if it must be +called from C code). See also Interrupt Dispatcher +Tutorial.

+
+ +Personality Layer for Real Time Applications + +
\ No newline at end of file