Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1542744
  • 博文数量: 237
  • 博客积分: 5139
  • 博客等级: 大校
  • 技术积分: 2751
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-18 14:48
文章分类

全部博文(237)

文章存档

2016年(1)

2012年(4)

2011年(120)

2010年(36)

2009年(64)

2008年(12)

分类:

2009-11-09 21:33:40

Process and Thread Memory

In Symbian, process address space includes:

-  System-wide memory for ROM and RAM loaded DLLs
-  Process-wide memory such as code and data segment
-  Thread-wide memory such as stack and heap (not always)

When a thread is created, by default each thread will have its own stack of size 8KB. We can change this by specifying the stack size while creating the thread. We can set the thread size in mmp file also using epocstaksize keyword. A thread's stack cannot grow once after the thread has been started. If all stack variables cannot be accommodated on that thread's stack, it will PANIC. When a thread is created, it can either have its own heap, or can share the parent thread's heap. By default, a thread can have minimum of 4KB and maximum of 1 MB heap area. We can change this using mmp file with epocheapsize keyword. We can also specify, these two parameters while creating the thread also. A thread's default heap can grow if the current heap cannot accommodate all heap resources. If system free list does not have enough pages, then, even this will fail with out-of-memory error.

Typically, in Symbian, as executable can be EXE (executable with single main entry at E32Main) or DLL (library of program code with many entry points). All ROM based executables are executed in-place where as those executable not in ROM, must be first loaded into RAM.

Each instance of a RAM based EXE will have its own area for code, read-only data and read-write data. When it comes to ROM based EXE, there is some amount of optimization; each instance of ROM based EXE will have its own RAM area for read/write data. Code and read-only data are shared and read directly from ROM.

ROM based DLLs are not loaded at all. They are simply used in-place in ROM. RAM based DLL's are relocated to a particular address. When 2nd process requires the same DLL, it will be attached with existing code. Symbian OS will have a reference count so that DLL will be unloaded when no more threads are linked (attached) to it. So, DLLs are shared with all the process they are linked with.

Since DLLs are shared, there is some issue when it comes to accessing write-able global data of DLL. These data are called as WSD (Write-able Static Data). Each DLL that has WSD would require a separate chunk of memory of RAM (which is 4KB) to be allocated in every process that links to this DLL. Assuming a DLL has a global non-constant char as WSD and there are some 50 applications links to them, then 50 * 4 = 200 KB of RAM memory will be allocated for this WSD, which will take just 50 Bytes (50 * size of char) of memory! Assume a situation where there are hundreds of such DLLs linking to hundreds of applications, then huge amount of RAM (100*100*4 KB) will be consumed only for WSD.

Because of the problem, which I have mentioned above, Symbian does not encourage the use of WSD in our DLLs. In fact till Symbian 9.1, we cannot have WSD in a Symbian DLL. But from Symbian 9.1 onwards Symbian allows this by making of use of EPOCALLOWDLLDATA keyword in mmp file. Main reason for this one is for porting some non-Symbian applications onto Symbian. But Symbian does not encourage the use of this keyword. Instead of this Symbian provides some alternatives like:

-  Use of Client-Server framework
-  Use of TLS (Thread Local Storage)

Use of TLS for WSD:

Each DLL will have one word entity called as TLS (Thread Local Storage) that exists per thread per DLL basis.

All the global and static data in the DLL can be grouped together into a single structure and this particular structure will be created on heap when the thread is created. And thread's TLS will be assigned with this pointer to the structure. For this Dll::SetTls() api is used. For accessing/modifying any of the global data, we need to follow these steps:

  1. use Dll::Tls() for getting the pointer to the structure
  2. use the pointer for referencing the actual data.

During the destruction of the thread, TLS pointed structure can be deleted and the TLS can be set to zero.

Typically each DLL, which uses this technique, will have one function, which will be called just before using any of the DLL's functionality (api). This function will take care of creating the structure that contains all global data on heap and setting up the Dll's Tls. The code will look something like this:

void InitLibrary()
        {
        //allocate the structure containing global data on heap
        GlobalData* p = new GlobalData();
        if ( p )
                {
                Dll::SetTls( p ); //Set this Dll's Tls with this structure pointer
                }
        else
                //Panic the thread
        }

Such DLL will have one more function, which will take care of freeing up resources. When done with the usage of this DLL, thread will call this function. The functionality of this function will look something like this.

void CleanupLibrary()
        {
        //Get the Dll's Tls
        GlobalData* p = (GlobalData*) Dll::Tls();
        if ( p )
                {
                //Do some global variable specific cleanup activity if required
                Cleanup( p );
                delete p;  //Deallocate the memory now
                }
        }

Typically other exported api's of DLL will get the DLL's Tls and use the global variables. It will be implemented something like this most of time:

//defined in some header.
typedef struct
        {
        int globalVal1;
        ...
        char globalValn
        }GlobalData;

//some .c or .cpp file
EXPORT_C void FunctionOne()
        {
        //Get the Dll's Tls
        GlobalData* p = (GlobalData*) Dll::Tls();
        FunctionOne_r ( p );
        }
//re-entrant version of above function
void FunctionOne_r( GlobalData* p )
        {
        //use all those variables required pointed by the structure p
        p->globalVal1 += 10;
        p->globalValn =  Â‘C';
        }

Assuming MyDLL.DLL is a DLL, which links to two more DLLs namely LIBRARYONE.DLL and LIBRARYTWO.DLL, then the thread in MyDLL.DLL will have 2 TLS each for above 2 DLLs. When MyDLL.DLL uses some functionality of LIBRARYONE.DLL, its TLS will be different and when it uses some functionality of LIBRARYTWO.DLL, its TLS will be different.

Use of Client Server Framework for WSD:

As EXE's are not sharable, Symbian OS supports writeable global static data in EXEs. Server, which runs as a thread, can be an independent thread/process separate from its client or both client and server can be embedded in same process as two different threads. When Server runs as a separate process, then it will be an EXE. As EXE's can have WSD, a common strategy is to keep all global data in the server and to expose some APIs as client interface that modify these global variables for clients.

文章转自:


阅读(1548) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~