diff -r 89d6a7a84779 -r 25a17d01db0c Symbian3/PDK/Source/GUID-5BDE6462-E6CA-5738-A587-C7D875574789.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Symbian3/PDK/Source/GUID-5BDE6462-E6CA-5738-A587-C7D875574789.dita Fri Jan 22 18:26:19 2010 +0000 @@ -0,0 +1,252 @@ + + + + + +Static +Data +

Symbian developers used to PC operating systems, such as Windows, may be +used to using writeable static data (typically meaning global variables) in +DLLs. On the Symbian platform, this is possible, but not recommended, because +it is expensive in memory, and has limited support in the Symbian platform +Emulator.

+

This page describes writeable static data (WSD), the alternatives to using +WSD, and the costs and issues associated with its use.

+
Global writeable static data

Global writeable static +data (WSD) is any per-process variable which exists for the lifetime of the +process. In practice, this means any globally scoped data: data that is declared +outside of a function, struct, or class, and function scoped static variables.

TBufC<20> fileName; //WSD +void SetFileName() + { + static Tint iCount; //WSD ... + }

Sometimes writeable static data appears in a non-obvious +way. It is not always the case that const global variables +are read-only data rather than global writeable static data. This is true +for const objects with trivial constructors, such as integers. +However if a const class has a non-trivial constructor, the const object +will require a real variable and must be stored as WSD. For example:

const TInt myVariable=…; //OK – truly const +const TPtrC KSomeConstPtr=...; //NOT OK – non trivial constructor +const TRgb KSomeConstCol=...; //NOT OK – non trivial constructor
+
Support for global writeable static data on Symbian

The +Symbian platform supports global writeable static data in EXEs on all versions +and handsets.

Versions of Symbian OS based on the EKA2 kernel (8.1b +and later) support WSD in DLLs on target hardware. Versions 8.1a and earlier, +based on the EKA1 kernel, do not support global WSD in DLLs.

+
Clean up of global writeable static data

Your program +must make sure that global writeable static data that the program allocates +is cleaned up.

The clean up rules are as follows:

    +
  • Your program must clean +up WSD objects that are defined in the process EXE or its statically-loaded +DLLs. When a process exits, the Symbian platform does not automatically call +the destructors of these WSD objects.

  • +
  • Your program does not +need to clean up WSD objects defined in DLLs that the process has dynamically +loaded using RLibrary. The Symbian platform automatically +calls destructors of these objects.

  • +
+
Alternatives to using global writeable static data

Native +Symbian platform C++ code rarely uses WSD.

However, code ported from +other operating systems may contain large amounts of static data. For example, +code written in the C programming language often makes use of WSD as the "glue" +between C function calls.

In EKA1, WSD is not supported, so there +is no choice but to use the alternative mechanisms provided by the Symbian +platform to port such code. Even in EKA2 where global data is supported, Symbian +recommends that it only be used as a last resort.

The following sections +describe the alternatives that can be used to port code that makes use of +global writeable static data.

Use +thread-local storage (TLS)

Thread Local Storage (TLS) is a single +per-thread word that can be used to simulate global writeable static data.

All +the static data in the DLL is grouped into a single struct or class. On creation +of the thread, an instance of the thread is allocated on the heap and a pointer +to this data is saved to TLS (using Dll::SetTls()). On destruction +of the thread, the data is destroyed. Throughout the DLL the code references +the TLS data (using Dll::Tls()) rather than the original +global writeable static data.

Wrap +in a server

The Symbian platform supports writeable global static +data in EXEs. A common porting strategy is therefore to wrap the code in a +Symbian server (which is an EXE), and expose its API as a client interface.

Move global variables into your classes

With relatively small +amounts of code, it may be possible to move most global data inside classes.

+
Enabling global writeable static data

In order +to enable global writeable static data, simply add a statement epocallowdlldata (case +insensitive) to the project's MMP file:

TARGET my.dll +TARGETTYPE dll +EPOCALLOWDLLDATA +…
+
Costs and limitations

Emulator +only allows a DLL with WSD to load into a single process

The Symbian +platform EKA2 Emulator only allows a DLL with WSD to be loaded into a single +process.

This is a very serious restriction. If you have a shared +DLL with WSD, then the second process that attempts to load it in the emulator +will fail with KErrNotSupported.

Emulator allows WSD by default

The Emulator will allow WSD +in DLLs even if epocallowdlldata is not declared in the mmp +file. However the data will be truly global: there will be one copy for the +entire emulator, rather than one copy for each emulated process. The only +restriction is that if the data's initialisers call any Symbian platform kernel +functions (i.e. executive calls), then the emulator will fault.

RAM usage for WSD data chunk

When a process loads its first +DLL containing WSD, it creates a single chunk to store the data. The data +for subsequent WSD-enabled DLLs is loaded into the same chunk.

The +data chunk will occupy at least one 4K RAM page (the smallest possible RAM +allocation), irrespective of how much static data is required. Any memory +not used for WSD will be wasted. Since the memory is per-process, the memory +wastage on the machine is:

(4Kb - WSD Bytes) × number-client-processes

It is very easy for a developer to add a few words of WSD to their DLL thinking +that's all the memory that they are using. However, the cost is actually 4K +for every process if a DLL with WSD has not already been loaded into the process. +If for example the DLL is used by 4 processes, that's potentially an "invisible" +cost of 16K.

Chunks +are a finite resource

EKA2 has a hard coded limit of 16 chunks +per process; a limit that is required to ensure real-time behaviour. Every +process loading WSD-enabled DLLs uses a chunk to hold the data, reducing the +number of chunks available for other uses.

ARM architecture 4 and 5 specific costs and limitations

There +are other significant costs that apply only to DLLs that link against "fixed +processes". Fixed processes are a feature of ARM v4 or v5 architecture only; +the following behaviour does not apply to devices based on the ARMv6 architecture.

Case +1: Non Execute-in-place DLLs

For non-execute-in-place (non XIP) +DLLs, an additional code chunk is required for every fixed process which links +against the DLL.

So imagine a 20Kb DLL (with a few bytes of WSD) that +is loaded into 4 normal "non-fixed" processes, and 2 fixed processes. The +(static) memory consumed is:

    +
  • Code chunk shared by +all moving processes = 20 Kb

  • +
  • Code chunk for each +fixed process loading the DLL = 40 Kb

  • +
  • Data chunk for each +process loading the DLL = 6×4Kb = 24 Kb

  • +

So to allow a few bytes of WSD there is a 64Kb increase in consumed +memory. Note that the 20Kb code chunk shared by all processes is consumed +whether or not WSD is enabled.

Case 2: Execute-in-place DLLs

For +XIP DLLs, there is no additional RAM cost other than the size of the WSD itself, +rounded up to the next multiple of 4KB. However:

    +
  • An XIP DLL can be loaded +by any non-fixed process, OR it may be loaded by a single fixed process (and +therefore cannot be loaded by any other processes whatsoever)

  • +
  • The ROM build fails +if a DLL with static data links to a fixed process and any other process.

  • +

A few specific DLLs cannot have WSD

DLLs that are +required to initialise the file server cannot have WSD, e.g. HAL.DLL, EUSER.DLL, +EFSRV.DLL.

+
Frequently asked questions

How +does Symbian's WSD implementation work ?

Case 1. For moving +processes:

The Symbian platform supports a moving memory model, +in which the data for a process is moved into a fixed virtual address space +(the "run section") when the process is active, and then back into the processes +"home" section when another process is active:

    +
  • The data of processes +in the "home section" is uniquely addressed both in terms of physical RAM +pages, and in the MMU virtual address space. The data is protected from other +processes, except for the Kernel.

  • +
  • The data of processes +in the run section occupies the same virtual address space as all other processes +when they run (the MMU moves the physical RAM pages into the appropriate virtual +address space).

  • +

When a DLL with WSD is loaded (or at ROM build time), its code is +fixed to point to static data at specific addresses. In order to ensure that +only a single copy of the DLL code is required, Symbian's moving-process WSD +implementation ensures that the virtual addresses of static data is the same +across every running process.

The way this works is:

    +
  1. A specific address space +is reserved for a per-process static data chunk. This chunk is used to hold +all the static data for all the DLLs loaded into the process.

  2. +
  3. At ROM build time the +kernel reserves specific addresses within the static data chunk for all the +WSD in all the ROM loaded DLLs. The addresses for ROM based DLLs are reserved +from the top of the static data chunk address space to the bottom. Note that +static data addresses for RAM based DLLs are reserved when the DLL is first +loaded into any process. In this case, addresses are reserved from the bottom +of the static data chunk address space.

  4. +
  5. When the first DLL with +WSD is loaded into a process, a static data chunk is created to hold the static +data for all DLLs that are loaded into the process.

  6. +
  7. Any global static data +in the DLL is written to its specific reserved addresses. Note that addresses +are reserved for that particular static data across all processes; if the +DLL is loaded into another process, any static data will get the same virtual +address.

  8. +

Case 2. For fixed processes:

A fixed process is +one in which the process data does not move; code is run on process data stored +in the process "home section".

Since the static data for every fixed +process is uniquely addressed, and a DLL can only point to a single address +for its data, the implication is that a separate copy of the DLL code is required +for every fixed process that loads the DLL.

The restrictions listed +above for ARM architecture 4 and 5 directly result.

    +
  • For XIP based devices +the DLL code chunk address is fixed at ROM build time, and there can only +be one copy of the DLL code. Therefore the DLL code can address the data in +either a single fixed process or the virtual address used by all moveable +addresses.

  • +
  • For non-XIP based devices +the DLL is run from RAM, and the loader is able to fix-up the address that +a DLL expects its data at load time (rather than ROM build time). Therefore +in this case the loader creates a separate copy of DLL code for each fixed +process that loads the DLL and a single copy shared by all moving processes.

  • +

Notes: Fixed processes are not supported or required on ARM v6 architectures. +This discussion only applies to devices based on ARMv4 or v5. On ARM architecture +6 each DLL with WSD has a reserved address, similar to the ARMv5 moving process +case. However there is no 'home section' and memory is not relocated between +low and high addresses on a context switch. Instead, each process uses its +own set of page tables for the bottom half of virtual address space.

Why does the EKA2 Emulator only allow a DLL with WSD to load into a single +process?

The Symbian platform permits a DLL with global data to +be loaded into only one Symbian platform process on the emulator. This limitation +is a result of the way the Emulator is implemented on top of the Windows process +model.

On EKA2, separate Symbian platform processes are emulated within +a single Windows process. To preserve Symbian platform semantics there should +be one copy of the global data for each emulated process. However, this is +not possible since a DLL on the emulator is just a Windows DLL; Windows gives +it a single copy of any global data it needs when it is loaded.

What happens if epocallowdlldata isn't declared for a DLL with WSD?

Case +1: On the EKA2 Emulator:

Most constant data should be treated +by the compiler as read-only rather than writeable static data (the exception +is when the const data has a non-trivial constructor, so a real variable is +required during initialisation).

Unfortunately, different compilers +sometimes treat const data as WSD. For example, CodeWarrior puts it in writeable +data and initialises it at run time. MSVC generally puts it into read-only +data, but occasionally puts it into writeable data.

As most DLLs have +const data, this means that the compilers have "accidentally" created WSD +in almost every DLL. Symbian cannot therefore rigorously enforce the "single +process can load a DLL with WSD" rule, as the Emulator would not work.

On +the EKA2 Emulator, the workaround Symbian have implemented is to recognise +two types of DLL global data:

    +
  • 'Deliberate' global +data is where the programmer specifies that they want DLL global data (using +the epocallowdlldata keyword in the MMP file. In this case +any global data in the DLL is assumed to be deliberate, and the "DLL loaded +into one-emulated-process" rule applies.

  • +
  • 'Accidental' global +data is the data introduced by the compiler with no encouragement from the +programmer. If epocallowdlldata is absent, global data is +assumed to be accidental and the rule does not apply. Note that the global +data includes both const and non-const static data; there is no way to tell +the compilers to only apply it to non-const data - if we could do that then +we could force correct handling of const static data.

  • +

In order to prevent abuse of this workaround, there are restrictions +on what can be done with accidental global data; specifically, the Emulator +will fault if any of the global data's initialisers attempt to call the Symbian +platform kernel functions (i.e. executive calls).

Note that there +is only one copy of the global data. Therefore it is possible for two processes +to write to the same 'accidental' global data (causing undefined behaviour). +The "DLL loaded into one-emulated-process" rule prevents this being a problem +for deliberate global data.

Case 2: On the EKA1 Emulator

The +EKA1 emulator has no concept of separate Symbian platform processes. Global +data is allowed on the Emulator as there is only one copy of any global data.

Symbian +developers often have problems when porting to real hardware, which does not +support this type of data. This is discussed in the following section.

Case +3: On native target builds

On either EKA1 or EKA2, target compilers +will fail the build with an error indicating that the code has initialised +or un-initialised data.

The error message does not specify the symbol(s) +that are causing the problem. The .map files output by +the linker can however be helpful in finding the problem symbol. The RVCT +map files provide a list of global symbols and the object files in which they +occur. FAQ-0329 on the DevNet knowledgebase works through an example of using +a map file using the GCC compiler used on older Symbian platform releases.

Can Kernel DLLs have WSD ?

Yes, WSD is supported for kernel +DLLs in both EKA1 and EKA2 (through alternative mechanisms to those described +here).

Of course, kernel DLLs are guaranteed to be loaded into only +one process, so the per-process multiplication of RAM usage does not apply. +EKA2 will work correctly with global data in any kernel DLL. However EKA1 +does not call constructors for global C++ objects in kernel extensions or +device drivers, and does not call destructors for global C++ objects in device +drivers at driver unload time.

+
\ No newline at end of file