diff -r ebc84c812384 -r 46218c8b8afa Symbian3/PDK/Source/GUID-42F8FA5A-BBE4-50DE-917E-D05755019FEC.dita --- a/Symbian3/PDK/Source/GUID-42F8FA5A-BBE4-50DE-917E-D05755019FEC.dita Thu Mar 11 15:24:26 2010 +0000 +++ b/Symbian3/PDK/Source/GUID-42F8FA5A-BBE4-50DE-917E-D05755019FEC.dita Thu Mar 11 18:02:22 2010 +0000 @@ -1,242 +1,242 @@ - - - - - -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.

-
-Nanokernel - -Personality -Layer for Real Time Applications + + + + + +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.

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