Adaptation/GUID-42F8FA5A-BBE4-50DE-917E-D05755019FEC.dita
changeset 15 307f4279f433
equal deleted inserted replaced
14:578be2adaf3e 15:307f4279f433
       
     1 <?xml version="1.0" encoding="utf-8"?>
       
     2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
       
     3 <!-- This component and the accompanying materials are made available under the terms of the License 
       
     4 "Eclipse Public License v1.0" which accompanies this distribution, 
       
     5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
       
     6 <!-- Initial Contributors:
       
     7     Nokia Corporation - initial contribution.
       
     8 Contributors: 
       
     9 -->
       
    10 <!DOCTYPE concept
       
    11   PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
       
    12 <concept id="GUID-42F8FA5A-BBE4-50DE-917E-D05755019FEC" xml:lang="en"><title>Personality Layer Design</title><shortdesc>Provides some guidelines for the design of a personality
       
    13 layer for real time Applications for the Kernel.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
       
    14 <section id="GUID-A0EC87BF-170D-46B4-AEFF-F21D7483149B"><title>Memory
       
    15 management</title> <p>The personality layer assumes that the RTA will
       
    16 run in a single flat address space in which there is neither protection
       
    17 between different parts of the application nor protection of any hardware
       
    18 or CPU resource from any part of the application. For example, any
       
    19 part of the application code can access any I/O port, and can disable
       
    20 interrupts. </p> <p>To get this behaviour under the Kernel Architecture
       
    21 2, the RTA must run in supervisor mode in the kernel address space.
       
    22 The obvious way to do this is to make the RTA together with the personality
       
    23 layer a kernel extension. This also ensures that it is started automatically
       
    24 early on in the boot process. </p> <p>In general the RTA will have
       
    25 its own memory management strategy and will not wish to use the standard
       
    26 Symbian platform memory management system. To achieve this, the personality
       
    27 layer will allocate a certain fixed amount of RAM for use by the real
       
    28 time application at boot time. For a telephony stack this will be
       
    29 around 128K - 256K. This can be done either by including it in the
       
    30 kernel extension's <filepath>.bss</filepath> section, or by making
       
    31 a one-time allocation on the kernel heap at boot time. Depending on
       
    32 the RTA requirements, the personality layer can manage this area of
       
    33 RAM (if the RTOS being emulated provides memory management primitives)
       
    34 or the RTA can manage it. </p> </section>
       
    35 <section id="GUID-FAA30849-282F-4E2D-ABDA-63E130A2D2FB"><title>Threads
       
    36 and mapping thread priorities</title> <p>A nanokernel thread will
       
    37 be used for each RTOS thread </p> <p>A priority mapping scheme will
       
    38 be required to map RTOS priorities, of which there are typically 64
       
    39 to 256 distinct values, to nanokernel priorities. As long as the RTA
       
    40 does not use more than 35 threads running simultaneously, which is
       
    41 usually the case, it should be possible to produce a mapping scheme
       
    42 that allows each thread to have a distinct priority, if needed. If
       
    43 this limit is exceeded, it will be necessary to fold some priorities
       
    44 together. </p> <p>Note that any attempt to increase the number of
       
    45 priorities supported by both the nanokernel and the Symbian platform
       
    46 kernel would be <i>prohibitively</i> expensive in terms of RAM usage. </p> </section>
       
    47 <section id="GUID-169604BD-A22A-5B56-8279-13F875AB4AB6"><title>Communication
       
    48 between Symbian platform and the RTOS Environments</title> <p>To allow
       
    49 the functionality of the RTA to be available to Symbian platform applications,
       
    50 it is necessary that a mechanism exist by which Symbian platform code
       
    51 and the RTA may communicate with each other. In practice this means: </p> <ul>
       
    52 <li id="GUID-DC8AF97D-EA8A-5852-96FF-CCA19D69F614"><p>it must be possible
       
    53 for a Symbian platform thread to cause an RTOS thread to be scheduled
       
    54 and vice-versa </p> </li>
       
    55 <li id="GUID-EF671D7A-28B6-505D-823C-5B51C378225E"><p>it must be possible
       
    56 for data to be transferred between Symbian platform and RTOS threads
       
    57 in both directions. </p> </li>
       
    58 </ul> <p>It will usually be possible for a Symbian platform thread
       
    59 to make standard personality layer calls (the same calls that RTOS
       
    60 threads would make) in order to cause an RTOS thread to be scheduled.
       
    61 This is because the nanokernel underlies both types of thread and
       
    62 most 'signal' type operations (i.e. those that make threads ready
       
    63 rather than blocking them) can be implemented using operations which
       
    64 make no reference to the calling thread, and which are therefore not
       
    65 sensitive to which type of thread they are called from. </p> <p>The
       
    66 standard personality layer calls will not work in the other direction,
       
    67 since it will not be possible for a Symbian platform thread to wait
       
    68 on a personality layer wait object. The most straightforward way for
       
    69 RTOS threads to trigger scheduling of a Symbian platform thread would
       
    70 be to enque a DFC on a queue operated by a Symbian platform thread.
       
    71 Another possibility would be for the Symbian platform thread to wait
       
    72 on a fast semaphore which could then be signalled by the RTOS thread.
       
    73 However the DFC method fits better with the way device drivers are
       
    74 generally written. A device driver will be necessary to mediate communication
       
    75 between Symbian platform user mode processes and the RTA since the
       
    76 latter runs kernel side. </p> <p>All data transfer between the two
       
    77 environments must occur kernel side. It will not be possible for any
       
    78 RTOS thread to access normal user side memory since the functions
       
    79 provided for doing so access parts of the <xref href="GUID-38D1534C-AA01-33AF-9937-CDD818A85F97.dita"><apiname>DThread</apiname></xref> structure representing the Symbian platform calling thread, for
       
    80 example to perform exception trapping. Some possibilities for the
       
    81 data transfer mechanism are: </p> <ul>
       
    82 <li id="GUID-96A247AA-BA1C-50E5-8400-5487DFF5991D"><p>A fairly common
       
    83 architecture for real time applications involves a fixed block size
       
    84 memory manager and message queues for inter-thread communication.
       
    85 The memory manager supports allocation and freeing of memory in constant
       
    86 time. The sending thread allocates a memory block, places data in
       
    87 it and posts it to the receiving thread's message queue. The receiving
       
    88 thread then processes the data and frees the memory block, or possibly
       
    89 passes the block to yet another thread. It would be a simple proposition
       
    90 to produce such a system in which the memory manager could be used
       
    91 by any thread. In that case a Symbian platform thread could pass messages
       
    92 to RTOS threads in the same way as other RTOS threads. Passing data
       
    93 back would involve a special type of message queue implemented in
       
    94 the personality layer. When a message was sent to a Symbian platform
       
    95 thread a DFC would be enqueued. That DFC would then process the message
       
    96 data and free the memory block as usual. This scheme combines the
       
    97 data transfer and scheduling aspects of communication. </p> </li>
       
    98 <li id="GUID-1D2B6085-7B3A-51EF-BFF6-865D4AF94E5A"><p>Any standard
       
    99 buffering arrangement could be used between the RTA and the device
       
   100 driver (e.g. circular buffers). Contention between threads could be
       
   101 prevented using nanokernel fast mutexes, on which any thread can wait,
       
   102 or by the simpler means of disabling preemption or disabling interrupts.
       
   103 It will also be possible for RTOS threads to make use of shared I/O
       
   104 buffers for transfer direct to user mode clients, provided that these
       
   105 buffers are set up by the Symbian platform device driver thread. This
       
   106 may be useful as a way to reduce copying overhead if bulk data transfer
       
   107 is necessary between the two domains. </p> </li>
       
   108 </ul> </section>
       
   109 <section id="GUID-09CC8168-50FD-49ED-8376-05C00C3243FA"><title>Synchronisation/communication
       
   110 primitives</title> <p>The nanokernel does not support most of the
       
   111 synchronisation and communication primitives provided by a standard
       
   112 RTOS. Any such primitives required by the RTA will have to be implemented
       
   113 in the personality layer. This means that the personality layer needs
       
   114 to define new types of object on which threads can wait. This in turn
       
   115 means that new nanokernel thread states (N-state) must be defined
       
   116 to signify that a thread is waiting on an object of the new type.
       
   117 In general, each new type of wait object requires an accompanying
       
   118 new nanokernel thread state. </p> <p><b>Blocking a thread on a wait object</b> </p> <p>To make a thread
       
   119 block on a new type of wait object, call the nanokernel function <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-72F2E4E0-B498-32D2-BB24-E79AC66EFDDB"><apiname>Kern::NanoBlock()</apiname></xref>, passing the maximum time for which the
       
   120 thread should block, the new N-state value, and a pointer to the wait
       
   121 object. </p> <p>Use the <codeph>TPriListLink</codeph> base class of <xref href="GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC.dita"><apiname>NThreadBase</apiname></xref> to attach the thread to a list of threads waiting
       
   122 on the object. Note that this must be done after calling <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-72F2E4E0-B498-32D2-BB24-E79AC66EFDDB"><apiname>Kern::NanoBlock()</apiname></xref>. As preemption is disabled before this
       
   123 function is called, a reschedule will not occur immediately, but will
       
   124 be deferred until preemption is reenabled. </p> <p id="GUID-5017FB0A-5C1E-5C88-9315-E12C12D9639F"><b>State handler</b> </p> <p>Every thread that can use a new type of wait object, must
       
   125 have a nanokernel state handler installed to handle operations on
       
   126 that thread when it is waiting on that wait object. A nanokernel state
       
   127 handler is a function that has the following signature: </p> <codeblock id="GUID-31E807F7-250B-552D-8480-5F282C151565" xml:space="preserve">void StateHandler(NThread* aThread, TInt aOp, TInt aParam);</codeblock> <ul>
       
   128 <li id="GUID-B8ECADB3-0345-56CB-8C7A-6D4E8CE15726"><p> <codeph> aThread</codeph> is a pointer to the thread involved. </p> </li>
       
   129 <li id="GUID-711957A1-4D01-5F8B-BF67-70EB8F39D20B"><p> <codeph> aOp</codeph> is one of the <xref href="GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC.dita#GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC/GUID-FF52640A-87C9-319B-B4C6-F6B860171229"><apiname>NThreadBase::NThreadOperation</apiname></xref> values
       
   130 that indicates which operation is being performed on the thread. </p> </li>
       
   131 <li id="GUID-FF54386A-D163-5F53-B230-296BE402C9E6"><p> <codeph> aParam</codeph> is a parameter that depends on <codeph>aOp</codeph>. </p> </li>
       
   132 </ul> <p>Note that the state handler is always called with preemption
       
   133 disabled. </p> <p>The possible values of <codeph>aOp</codeph> are: </p> <table id="GUID-F4372C47-F491-55E2-B06E-2C68628B5BC5">
       
   134 <tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
       
   135 <tbody>
       
   136 <row>
       
   137 <entry><p> <codeph>aOp</codeph> value </p> </entry>
       
   138 <entry><p>Description </p> </entry>
       
   139 </row>
       
   140 <row>
       
   141 <entry><p> <codeph>ESuspend</codeph>  </p> </entry>
       
   142 <entry><p>Called if the thread is suspended while not in a critical
       
   143 section and not holding a fast mutex. Called in whichever context <xref href="GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC.dita#GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC/GUID-FF94D458-C2D0-3D20-ADD6-AAE68A3296C3"><apiname>NThreadBase::Suspend()</apiname></xref> is called from. </p> <p> <codeph>aParam</codeph> contains the requested suspension count. </p> </entry>
       
   144 </row>
       
   145 <row>
       
   146 <entry><p> <codeph>EResume</codeph>  </p> </entry>
       
   147 <entry><p>Called if the thread is resumed while actually suspended,
       
   148 and the last suspension has been removed. Called in whichever context <xref href="GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC.dita#GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC/GUID-C0A6E734-7DE6-37B9-AAB2-A2A0E2664731"><apiname>NThreadBase::Resume()</apiname></xref> is called from. </p> <p> <codeph>aParam</codeph> contains no additional information. </p> </entry>
       
   149 </row>
       
   150 <row>
       
   151 <entry><p> <codeph>EForceResume</codeph>  </p> </entry>
       
   152 <entry><p>Called if the thread has all suspensions cancelled while
       
   153 actually suspended. Called in whichever context <xref href="GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC.dita#GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC/GUID-BE92FBC3-A7D9-3576-A1A9-7BBA6EE64226"><apiname>NThreadBase::ForceResume()</apiname></xref> is called from. </p> <p> <codeph>aParam</codeph> contains no additional
       
   154 information. </p> </entry>
       
   155 </row>
       
   156 <row>
       
   157 <entry><p> <codeph>ERelease</codeph>  </p> </entry>
       
   158 <entry><p>Called if the thread is released from its wait. This call
       
   159 should make the thread ready if necessary. Called in whichever context <xref href="GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC.dita#GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC/GUID-1B24AC4E-C4A1-32AE-BC6E-DC3131116EF8"><apiname>NThreadBase::Release()</apiname></xref> was called from. </p> <p> <codeph>aParam</codeph> is the value passed into <xref href="GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC.dita#GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC/GUID-1B24AC4E-C4A1-32AE-BC6E-DC3131116EF8"><apiname>NThreadBase::Release()</apiname></xref> to be used as a return code. </p> <p>If <codeph>aParam</codeph> is
       
   160 non-negative, this indicates normal termination of the wait condition. </p> <p>If <codeph>aParam</codeph> is negative, it indicates early or
       
   161 abnormal termination of the wait; in this case the wait object should
       
   162 be rolled back as if the wait had never occurred. For example, a semaphore's
       
   163 count needs to be incremented if <codeph>aParam</codeph> is negative,
       
   164 since in that case the waiting thread never acquired the semaphore. </p> </entry>
       
   165 </row>
       
   166 <row>
       
   167 <entry><p> <codeph>EChangePriority</codeph>  </p> </entry>
       
   168 <entry><p>Called if the thread's priority is changed. Called in whichever
       
   169 context <xref href="GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC.dita#GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC/GUID-A92E7B01-C1D0-3997-B3E1-2E54229FFA75"><apiname>NThreadBase::SetPriority()</apiname></xref> is called from.
       
   170 This function should set the <codeph>iPriority</codeph> field of the
       
   171 thread, after doing any necessary priority queue manipulations. </p> <p> <codeph>aParam</codeph> contains the new priority. </p> </entry>
       
   172 </row>
       
   173 <row>
       
   174 <entry><p> <codeph>ELeaveCS</codeph>  </p> </entry>
       
   175 <entry><p>Called in the context of the thread concerned if the thread
       
   176 calls <xref href="GUID-3A3C08F3-3D33-3D9E-80E7-7855C7B21E02.dita#GUID-3A3C08F3-3D33-3D9E-80E7-7855C7B21E02/GUID-2C897BA5-2BD7-3ABA-9F2B-F0B1AC14D1AE"><apiname>NKern::ThreadLeaveCS()</apiname></xref> with an unknown <codeph>iCsFunction</codeph> that is negative but not equal to <codeph>ECsExitPending</codeph>. </p> <p>aParam contains the value of <codeph>iCsFunction</codeph>. </p> </entry>
       
   177 </row>
       
   178 <row>
       
   179 <entry><p> <codeph>ETimeout</codeph>  </p> </entry>
       
   180 <entry><p>Called if the thread's wait time-out expires and no time-out
       
   181 handler is defined for that thread. Called in the context of the nanokernel
       
   182 timer thread (DfcThread1). This should cancel the wait and arrange
       
   183 for an appropriate error code to be returned. The handler for this
       
   184 condition will usually do the same thing as the handler for <codeph>ERelease</codeph> with a parameter of <xref href="GUID-BAC2386E-8168-3CDB-9F9F-180319EF6920.dita"><apiname>KErrTimedOut</apiname></xref>. </p> <p> <codeph>aParam</codeph> contains no additional information. </p> </entry>
       
   185 </row>
       
   186 </tbody>
       
   187 </tgroup>
       
   188 </table> <p>See the code in <filepath>...\e32\personality\example\...</filepath> for practical examples. </p> <p><b>Releasing the thread</b> </p> <p>When a thread's wait condition
       
   189 is resolved, the nanokernel function <xref href="GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC.dita#GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC/GUID-1B24AC4E-C4A1-32AE-BC6E-DC3131116EF8"><apiname>NThreadBase::Release()</apiname></xref> should be called. This takes a single <xref href="GUID-7A2A43EC-6125-3BFE-834B-23C37F7B40D5.dita"><apiname>TInt</apiname></xref> parameter. </p> <p>The parameter is usually <xref href="GUID-6CA4F1ED-7947-3087-B618-D35858FAA3BC.dita"><apiname>KErrNone</apiname></xref>, if the
       
   190 wait condition is resolved normally. A typical example is where the
       
   191 semaphore on which the thread is waiting, is signalled. A negative
       
   192 parameter value is used for an abnormal termination, and in this case,
       
   193 the wait object may need to be rolled back. </p> <p> <xref href="GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC.dita#GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC/GUID-1B24AC4E-C4A1-32AE-BC6E-DC3131116EF8"><apiname>NThreadBase::Release()</apiname></xref> should be called with preemption disabled. It performs the following
       
   194 actions: </p> <ul>
       
   195 <li id="GUID-6697024F-ED05-5C5A-A834-EA89402AE173"><p>sets the <codeph>NThreadBase::iWaitObj</codeph> field to NULL </p> </li>
       
   196 <li id="GUID-C1DF3120-4FD3-5B6C-90F8-6D8C7CAD0B88"><p>cancels the
       
   197 wait timer if it is still running </p> </li>
       
   198 <li id="GUID-6E346E2B-4F94-56FB-8372-8260BCC4CA8C"><p>stores the supplied
       
   199 return code in <codeph>NThreadBase::iReturnCode</codeph>  </p> </li>
       
   200 <li id="GUID-3AF577DB-41A9-553E-9EFD-6F0DA2FADCEA"><p>calls the <xref href="GUID-42F8FA5A-BBE4-50DE-917E-D05755019FEC.dita#GUID-42F8FA5A-BBE4-50DE-917E-D05755019FEC/GUID-5017FB0A-5C1E-5C88-9315-E12C12D9639F">state handler</xref> passing <codeph>ERelease</codeph> and the return
       
   201 code. If the return code is negative this should remove the thread
       
   202 from any wait queues and roll back the state of the wait object. In
       
   203 any case it should call <xref href="GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC.dita#GUID-379D9320-AC3C-3206-8A5D-EE6E5983EBDC/GUID-82E43D79-721D-31A9-B9ED-1277F2300914"><apiname>NThreadBase::CheckSuspendThenReady()</apiname></xref> to make the thread ready again if necessary. </p> </li>
       
   204 </ul> </section>
       
   205 <section id="GUID-1FF1CFE8-41E3-4912-AE28-39D289442BB7"><title>Thread
       
   206 scheduling following a hardware interrupt</title> <p>Most RTOS allow
       
   207 interrupt service routines (ISRs) to perform operations such as semaphore
       
   208 signal, queue post, set event flag directly, usually using the same
       
   209 API as would be used in a thread context. The Kernel Architecture
       
   210 2 nanokernel does not allow this; ISRs can only queue an IDFC or DFC. </p> <p>The way to get round this limitation is to incorporate an IDFC
       
   211 into each personality layer wait object. The personality layer API
       
   212 involved then needs to check whether it is being invoked from an ISR
       
   213 or a thread and, in the first case, it queues the IDFC. It may need
       
   214 to save some other information for use by the IDFC, for example, it
       
   215 may need to maintain a list of messages queued from ISRs, a count
       
   216 of semaphore signals from ISRs or a bit mask of event flags set by
       
   217 ISRs. Checking for invocation from an ISR can be done either by using <xref href="GUID-3A3C08F3-3D33-3D9E-80E7-7855C7B21E02.dita#GUID-3A3C08F3-3D33-3D9E-80E7-7855C7B21E02/GUID-9542588A-2920-3CB0-A2C0-A55FA6BC29A2"><apiname>NKern::CurrentContext()</apiname></xref>, or by checking the CPSR directly;
       
   218 if doing the latter note that any mode other than USR or SVC on the
       
   219 ARM counts as interrupt context. </p> <p>Hardware interrupts serviced
       
   220 by the RTA will need to conform to the same pattern as those serviced
       
   221 by Symbian platform extensions or device drivers. This means that
       
   222 the standard preamble must run before the actual service routine and
       
   223 the nanokernel interrupt postamble must run after the service routine
       
   224 to enable reschedules to occur if necessary. This can be done by calling <codeph>Interrupt::Bind()</codeph> as provided by the base port during RTA
       
   225 initialisation (possibly via a personality layer call if it must be
       
   226 called from C code). See also <xref href="GUID-3C34724F-B476-5329-B0B1-6D5A34294979.dita">Interrupt Dispatcher
       
   227 Tutorial</xref>. </p> </section>
       
   228 </conbody><related-links>
       
   229 <link href="GUID-2700AAC8-A034-5E7D-B0E0-26B49E68BB18.dita">
       
   230 <linktext>Personality Layer for Real                 Time Applications</linktext>
       
   231 </link>
       
   232 </related-links></concept>