Symbian3/PDK/Source/GUID-5BDE6462-E6CA-5738-A587-C7D875574789.dita
changeset 1 25a17d01db0c
child 3 46218c8b8afa
equal deleted inserted replaced
0:89d6a7a84779 1:25a17d01db0c
       
     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-5BDE6462-E6CA-5738-A587-C7D875574789" xml:lang="en"><title>Static
       
    13 Data</title><prolog><metadata><keywords/></metadata></prolog><conbody>
       
    14 <p>Symbian developers used to PC operating systems, such as Windows, may be
       
    15 used to using writeable static data (typically meaning global variables) in
       
    16 DLLs. On the Symbian platform, this is possible, but not recommended, because
       
    17 it is expensive in memory, and has limited support in the Symbian platform
       
    18 Emulator. </p>
       
    19 <p>This page describes writeable static data (WSD), the alternatives to using
       
    20 WSD, and the costs and issues associated with its use. </p>
       
    21 <section><title>Global writeable static data</title> <p>Global writeable static
       
    22 data (WSD) is any per-process variable which exists for the lifetime of the
       
    23 process. In practice, this means any globally scoped data: data that is declared
       
    24 outside of a function, struct, or class, and function scoped static variables. </p> <codeblock id="GUID-C7F90E06-286B-5E64-B94A-7683AA0DA0FB" xml:space="preserve">TBufC&lt;20&gt; fileName; //WSD 
       
    25 void SetFileName()
       
    26  {
       
    27  static Tint iCount; //WSD ...
       
    28  }</codeblock> <p>Sometimes writeable static data appears in a non-obvious
       
    29 way. It is not always the case that <codeph>const</codeph> global variables
       
    30 are read-only data rather than global writeable static data. This is true
       
    31 for <codeph>const</codeph> objects with trivial constructors, such as integers.
       
    32 However if a <codeph>const</codeph> class has a non-trivial constructor, the <codeph>const</codeph> object
       
    33 will require a real variable and must be stored as WSD. For example: </p> <codeblock id="GUID-897D2E68-5AF6-5C69-A5AA-276A9FB89DEC" xml:space="preserve">const TInt myVariable=…; //OK – truly const
       
    34 const TPtrC KSomeConstPtr=...; //NOT OK – non trivial constructor 
       
    35 const TRgb KSomeConstCol=...; //NOT OK – non trivial constructor</codeblock> </section>
       
    36 <section><title>Support for global writeable static data on Symbian</title> <p>The
       
    37 Symbian platform supports global writeable static data in EXEs on all versions
       
    38 and handsets. </p> <p>Versions of Symbian OS based on the EKA2 kernel (8.1b
       
    39 and later) support WSD in DLLs on target hardware. Versions 8.1a and earlier,
       
    40 based on the EKA1 kernel, do not support global WSD in DLLs. </p> </section>
       
    41 <section><title>Clean up of global writeable static data</title> <p>Your program
       
    42 must make sure that global writeable static data that the program allocates
       
    43 is cleaned up. </p> <p>The clean up rules are as follows: </p> <ul>
       
    44 <li id="GUID-1D25BA8E-1A8E-5502-8FD9-7F74DBB39EF4"><p>Your program must clean
       
    45 up WSD objects that are defined in the process EXE or its statically-loaded
       
    46 DLLs. When a process exits, the Symbian platform does not automatically call
       
    47 the destructors of these WSD objects. </p> </li>
       
    48 <li id="GUID-7F1EB6D6-2EAD-5318-A066-DC9128A48EAF"><p>Your program does not
       
    49 need to clean up WSD objects defined in DLLs that the process has dynamically
       
    50 loaded using <xref href="GUID-25327159-83D6-3507-B187-09EA4BB3727F.dita"><apiname>RLibrary</apiname></xref>. The Symbian platform automatically
       
    51 calls destructors of these objects. </p> </li>
       
    52 </ul> </section>
       
    53 <section><title>Alternatives to using global writeable static data</title> <p>Native
       
    54 Symbian platform C++ code rarely uses WSD. </p> <p>However, code ported from
       
    55 other operating systems may contain large amounts of static data. For example,
       
    56 code written in the C programming language often makes use of WSD as the "glue"
       
    57 between C function calls. </p> <p>In EKA1, WSD is not supported, so there
       
    58 is no choice but to use the alternative mechanisms provided by the Symbian
       
    59 platform to port such code. Even in EKA2 where global data is supported, Symbian
       
    60 recommends that it only be used as a last resort. </p> <p>The following sections
       
    61 describe the alternatives that can be used to port code that makes use of
       
    62 global writeable static data. </p> <p><b>Use
       
    63 thread-local storage (TLS)</b> </p> <p>Thread Local Storage (TLS) is a single
       
    64 per-thread word that can be used to simulate global writeable static data. </p> <p>All
       
    65 the static data in the DLL is grouped into a single struct or class. On creation
       
    66 of the thread, an instance of the thread is allocated on the heap and a pointer
       
    67 to this data is saved to TLS (using <codeph>Dll::SetTls()</codeph>). On destruction
       
    68 of the thread, the data is destroyed. Throughout the DLL the code references
       
    69 the TLS data (using <codeph>Dll::Tls()</codeph>) rather than the original
       
    70 global writeable static data. </p> <p><b>Wrap
       
    71 in a server</b> </p> <p>The Symbian platform supports writeable global static
       
    72 data in EXEs. A common porting strategy is therefore to wrap the code in a
       
    73 Symbian server (which is an EXE), and expose its API as a client interface. </p> <p><b>Move global variables into your classes</b> </p> <p>With relatively small
       
    74 amounts of code, it may be possible to move most global data inside classes. </p> </section>
       
    75 <section><title>Enabling global writeable static data</title> <p>In order
       
    76 to enable global writeable static data, simply add a statement <codeph>epocallowdlldata</codeph> (case
       
    77 insensitive) to the project's MMP file: </p> <codeblock id="GUID-0E673C33-569E-5F7B-9E51-55C2FC233D70" xml:space="preserve">TARGET my.dll 
       
    78 TARGETTYPE dll 
       
    79 EPOCALLOWDLLDATA 
       
    80 … </codeblock> </section>
       
    81 <section><title>Costs and limitations</title> <p><b>Emulator
       
    82 only allows a DLL with WSD to load into a single process</b> </p> <p>The Symbian
       
    83 platform EKA2 Emulator only allows a DLL with WSD to be loaded into a single
       
    84 process. </p> <p>This is a very serious restriction. If you have a shared
       
    85 DLL with WSD, then the second process that attempts to load it in the emulator
       
    86 will fail with <codeph>KErrNotSupported</codeph>. </p> <p><b>Emulator allows WSD by default</b> </p> <p>The Emulator will allow WSD
       
    87 in DLLs even if <codeph>epocallowdlldata</codeph> is not declared in the mmp
       
    88 file. However the data will be truly global: there will be one copy for the
       
    89 entire emulator, rather than one copy for each emulated process. The only
       
    90 restriction is that if the data's initialisers call any Symbian platform kernel
       
    91 functions (i.e. executive calls), then the emulator will fault. </p> <p><b>RAM usage for WSD data chunk </b> </p> <p>When a process loads its first
       
    92 DLL containing WSD, it creates a single chunk to store the data. The data
       
    93 for subsequent WSD-enabled DLLs is loaded into the same chunk. </p> <p>The
       
    94 data chunk will occupy at least one 4K RAM page (the smallest possible RAM
       
    95 allocation), irrespective of how much static data is required. Any memory
       
    96 not used for WSD will be wasted. Since the memory is per-process, the memory
       
    97 wastage on the machine is: </p> <codeblock id="GUID-005105EF-A09A-5FF7-8056-7316AFCE1894" xml:space="preserve">(4Kb - WSD Bytes) × number-client-processes</codeblock> <p>It is very easy for a developer to add a few words of WSD to their DLL thinking
       
    98 that's all the memory that they are using. However, the cost is actually 4K
       
    99 for every process if a DLL with WSD has not already been loaded into the process.
       
   100 If for example the DLL is used by 4 processes, that's potentially an "invisible"
       
   101 cost of 16K. </p> <p><b>Chunks
       
   102 are a finite resource</b> </p> <p>EKA2 has a hard coded limit of 16 chunks
       
   103 per process; a limit that is required to ensure real-time behaviour. Every
       
   104 process loading WSD-enabled DLLs uses a chunk to hold the data, reducing the
       
   105 number of chunks available for other uses. </p> <p><b>ARM architecture 4 and 5 specific costs and limitations</b> </p> <p>There
       
   106 are other significant costs that apply only to DLLs that link against "fixed
       
   107 processes". Fixed processes are a feature of ARM v4 or v5 architecture only;
       
   108 the following behaviour does not apply to devices based on the ARMv6 architecture. </p> <p> <b>Case
       
   109 1: Non Execute-in-place DLLs</b>  </p> <p>For non-execute-in-place (non XIP)
       
   110 DLLs, an additional code chunk is required for every fixed process which links
       
   111 against the DLL. </p> <p>So imagine a 20Kb DLL (with a few bytes of WSD) that
       
   112 is loaded into 4 normal "non-fixed" processes, and 2 fixed processes. The
       
   113 (static) memory consumed is: </p> <ul>
       
   114 <li id="GUID-57F9041D-240C-5B75-BC0C-EFA66AB411B6"><p>Code chunk shared by
       
   115 all moving processes = 20 Kb </p> </li>
       
   116 <li id="GUID-1FCC1ED4-0A60-5983-AF5A-2F7C8622BC80"><p>Code chunk for each
       
   117 fixed process loading the DLL = 40 Kb </p> </li>
       
   118 <li id="GUID-6CD0DBDD-E406-5F7D-9207-8E55B4043779"><p>Data chunk for each
       
   119 process loading the DLL = 6×4Kb = 24 Kb </p> </li>
       
   120 </ul> <p>So to allow a few bytes of WSD there is a 64Kb increase in consumed
       
   121 memory. Note that the 20Kb code chunk shared by all processes is consumed
       
   122 whether or not WSD is enabled. </p> <p> <b>Case 2: Execute-in-place DLLs</b>  </p> <p>For
       
   123 XIP DLLs, there is no additional RAM cost other than the size of the WSD itself,
       
   124 rounded up to the next multiple of 4KB. However: </p> <ul>
       
   125 <li id="GUID-8B1EDEA4-8082-5DB1-87A8-E7B0FE5BB802"><p>An XIP DLL can be loaded
       
   126 by any non-fixed process, OR it may be loaded by a single fixed process (and
       
   127 therefore cannot be loaded by any other processes whatsoever) </p> </li>
       
   128 <li id="GUID-BA2D82B1-A036-5281-95EB-A46A7976605B"><p>The ROM build fails
       
   129 if a DLL with static data links to a fixed process <i>and</i> any other process. </p> </li>
       
   130 </ul> <p> <b>A few specific DLLs cannot have WSD</b>  </p> <p>DLLs that are
       
   131 required to initialise the file server cannot have WSD, e.g. HAL.DLL, EUSER.DLL,
       
   132 EFSRV.DLL. </p> </section>
       
   133 <section><title>Frequently asked questions</title> <p><b>How
       
   134 does Symbian's WSD implementation work ?</b> </p> <p> <b>Case 1. For moving
       
   135 processes:</b>  </p> <p>The Symbian platform supports a moving memory model,
       
   136 in which the data for a process is moved into a fixed virtual address space
       
   137 (the "run section") when the process is active, and then back into the processes
       
   138 "home" section when another process is active: </p> <ul>
       
   139 <li id="GUID-26E98921-9094-5260-BA99-2F7FA4F7D6A7"><p>The data of processes
       
   140 in the "home section" is uniquely addressed both in terms of physical RAM
       
   141 pages, and in the MMU virtual address space. The data is protected from other
       
   142 processes, except for the Kernel. </p> </li>
       
   143 <li id="GUID-BBE7C17A-6FF7-5329-91C5-DEAF88A61B69"><p>The data of processes
       
   144 in the run section occupies the same virtual address space as all other processes
       
   145 when they run (the MMU moves the physical RAM pages into the appropriate virtual
       
   146 address space). </p> </li>
       
   147 </ul> <p>When a DLL with WSD is loaded (or at ROM build time), its code is
       
   148 fixed to point to static data at specific addresses. In order to ensure that
       
   149 only a single copy of the DLL code is required, Symbian's moving-process WSD
       
   150 implementation ensures that the virtual addresses of static data is the same
       
   151 across every running process. </p> <p>The way this works is: </p> <ol id="GUID-66A040C2-7B0F-56E0-A634-501D3E133A12">
       
   152 <li id="GUID-964A78E1-D86E-50D0-8AA0-D3D9346A43E7"><p>A specific address space
       
   153 is reserved for a per-process static data chunk. This chunk is used to hold
       
   154 all the static data for all the DLLs loaded into the process. </p> </li>
       
   155 <li id="GUID-0A528F28-55B2-5B8B-A337-8B2377241CF0"><p>At ROM build time the
       
   156 kernel reserves specific addresses within the static data chunk for all the
       
   157 WSD in all the ROM loaded DLLs. The addresses for ROM based DLLs are reserved
       
   158 from the top of the static data chunk address space to the bottom. Note that
       
   159 static data addresses for RAM based DLLs are reserved when the DLL is first
       
   160 loaded into any process. In this case, addresses are reserved from the bottom
       
   161 of the static data chunk address space. </p> </li>
       
   162 <li id="GUID-1898478C-2E24-53B4-BDEB-765FEEDC539C"><p>When the first DLL with
       
   163 WSD is loaded into a process, a static data chunk is created to hold the static
       
   164 data for all DLLs that are loaded into the process. </p> </li>
       
   165 <li id="GUID-7A88C9EB-31F9-559E-8DBD-221848CA2A46"><p>Any global static data
       
   166 in the DLL is written to its specific reserved addresses. Note that addresses
       
   167 are reserved for that particular static data across all processes; if the
       
   168 DLL is loaded into another process, any static data will get the same virtual
       
   169 address. </p> </li>
       
   170 </ol> <p> <b>Case 2. For fixed processes:</b>  </p> <p>A fixed process is
       
   171 one in which the process data does not move; code is run on process data stored
       
   172 in the process "home section". </p> <p>Since the static data for every fixed
       
   173 process is uniquely addressed, and a DLL can only point to a single address
       
   174 for its data, the implication is that a separate copy of the DLL code is required
       
   175 for every fixed process that loads the DLL. </p> <p>The restrictions listed
       
   176 above for ARM architecture 4 and 5 directly result. </p> <ul>
       
   177 <li id="GUID-125EDB37-4540-5EDB-9C19-6F92A307627F"><p>For XIP based devices
       
   178 the DLL code chunk address is fixed at ROM build time, and there can only
       
   179 be one copy of the DLL code. Therefore the DLL code can address the data in
       
   180 either a single fixed process or the virtual address used by all moveable
       
   181 addresses. </p> </li>
       
   182 <li id="GUID-BC66EA5A-252D-5E37-80F6-BEC82C03DABA"><p>For non-XIP based devices
       
   183 the DLL is run from RAM, and the loader is able to fix-up the address that
       
   184 a DLL expects its data at load time (rather than ROM build time). Therefore
       
   185 in this case the loader creates a separate copy of DLL code for each fixed
       
   186 process that loads the DLL and a single copy shared by all moving processes. </p> </li>
       
   187 </ul> <p>Notes: Fixed processes are not supported or required on ARM v6 architectures.
       
   188 This discussion only applies to devices based on ARMv4 or v5. On ARM architecture
       
   189 6 each DLL with WSD has a reserved address, similar to the ARMv5 moving process
       
   190 case. However there is no 'home section' and memory is not relocated between
       
   191 low and high addresses on a context switch. Instead, each process uses its
       
   192 own set of page tables for the bottom half of virtual address space. </p> <p><b>Why does the EKA2 Emulator only allow a DLL with WSD to load into a single
       
   193 process?</b> </p> <p>The Symbian platform permits a DLL with global data to
       
   194 be loaded into only one Symbian platform process on the emulator. This limitation
       
   195 is a result of the way the Emulator is implemented on top of the Windows process
       
   196 model. </p> <p>On EKA2, separate Symbian platform processes are emulated within
       
   197 a single Windows process. To preserve Symbian platform semantics there should
       
   198 be one copy of the global data for each emulated process. However, this is
       
   199 not possible since a DLL on the emulator is just a Windows DLL; Windows gives
       
   200 it a single copy of any global data it needs when it is loaded. </p> <p><b>What happens if epocallowdlldata isn't declared for a DLL with WSD?</b> </p> <p> <b>Case
       
   201 1: On the EKA2 Emulator:</b>  </p> <p>Most constant data should be treated
       
   202 by the compiler as read-only rather than writeable static data (the exception
       
   203 is when the const data has a non-trivial constructor, so a real variable is
       
   204 required during initialisation). </p> <p>Unfortunately, different compilers
       
   205 sometimes treat const data as WSD. For example, CodeWarrior puts it in writeable
       
   206 data and initialises it at run time. MSVC generally puts it into read-only
       
   207 data, but occasionally puts it into writeable data. </p> <p>As most DLLs have
       
   208 const data, this means that the compilers have "accidentally" created WSD
       
   209 in almost every DLL. Symbian cannot therefore rigorously enforce the "single
       
   210 process can load a DLL with WSD" rule, as the Emulator would not work. </p> <p>On
       
   211 the EKA2 Emulator, the workaround Symbian have implemented is to recognise
       
   212 two types of DLL global data: </p> <ul>
       
   213 <li id="GUID-6AD2E89F-6361-5F1F-8EC1-A203801BCC8F"><p>'Deliberate' global
       
   214 data is where the programmer specifies that they want DLL global data (using
       
   215 the <codeph>epocallowdlldata</codeph> keyword in the MMP file. In this case
       
   216 any global data in the DLL is assumed to be deliberate, and the "DLL loaded
       
   217 into one-emulated-process" rule applies. </p> </li>
       
   218 <li id="GUID-225E44BE-434E-5C2A-8503-318E31B17EF0"><p>'Accidental' global
       
   219 data is the data introduced by the compiler with no encouragement from the
       
   220 programmer. If <codeph>epocallowdlldata</codeph> is absent, global data is
       
   221 assumed to be accidental and the rule does not apply. Note that the global
       
   222 data includes both const and non-const static data; there is no way to tell
       
   223 the compilers to only apply it to non-const data - if we could do that then
       
   224 we could force correct handling of const static data. </p> </li>
       
   225 </ul> <p>In order to prevent abuse of this workaround, there are restrictions
       
   226 on what can be done with accidental global data; specifically, the Emulator
       
   227 will fault if any of the global data's initialisers attempt to call the Symbian
       
   228 platform kernel functions (i.e. executive calls). </p> <p>Note that there
       
   229 is only one copy of the global data. Therefore it is possible for two processes
       
   230 to write to the same 'accidental' global data (causing undefined behaviour).
       
   231 The "DLL loaded into one-emulated-process" rule prevents this being a problem
       
   232 for deliberate global data. </p> <p> <b>Case 2: On the EKA1 Emulator</b>  </p> <p>The
       
   233 EKA1 emulator has no concept of separate Symbian platform processes. Global
       
   234 data is allowed on the Emulator as there is only one copy of any global data. </p> <p>Symbian
       
   235 developers often have problems when porting to real hardware, which does not
       
   236 support this type of data. This is discussed in the following section. </p> <p> <b>Case
       
   237 3: On native target builds</b>  </p> <p>On either EKA1 or EKA2, target compilers
       
   238 will fail the build with an error indicating that the code has initialised
       
   239 or un-initialised data. </p> <p>The error message does not specify the symbol(s)
       
   240 that are causing the problem. The <filepath>.map</filepath> files output by
       
   241 the linker can however be helpful in finding the problem symbol. The RVCT
       
   242 map files provide a list of global symbols and the object files in which they
       
   243 occur. FAQ-0329 on the <xref href="http://developer.symbian.org/wiki/index.php/Symbian_C++_Knowledgebase_Q&amp;As#How_can_I_find_the_.22uninitialised_data.22_in_my_DLL.3F" scope="external">DevNet knowledgebase</xref> works through an example of using
       
   244 a map file using the GCC compiler used on older Symbian platform releases. </p> <p><b>Can Kernel DLLs have WSD ?</b> </p> <p>Yes, WSD is supported for kernel
       
   245 DLLs in both EKA1 and EKA2 (through alternative mechanisms to those described
       
   246 here). </p> <p>Of course, kernel DLLs are guaranteed to be loaded into only
       
   247 one process, so the per-process multiplication of RAM usage does not apply.
       
   248 EKA2 will work correctly with global data in any kernel DLL. However EKA1
       
   249 does not call constructors for global C++ objects in kernel extensions or
       
   250 device drivers, and does not call destructors for global C++ objects in device
       
   251 drivers at driver unload time. </p> </section>
       
   252 </conbody></concept>