Memory Chunks
Symbian OS provides support for shared memory regions that can be accessed directly across multiple processes. These shared memory regions are known as memory chunks. You can create your own memory chunks or access existing memory chunks by using the RChunk API class.
In order for your memory chunks to be shared between processes, they must be created as global (you can also have local memory chunks available just to a single process). Let's look at a simple example of creating and using a global memory chunk:
//Process A RChunk chk;
_LIT(KChunkName,"My Global Chunk");
Tint rc=chk.CreateGlobal(KChunkName,0x1000,0x1000);
/* error occurred creating chunk, handle here */ }
Tint *ptr =( Tint *)chk.Base(); //write some data into chunk using *ptr
This code creates a global memory chunk named "My Global Chunk", and initializes it with some data.
Any other program in the system can read and write this memory chunk if it knows the chunk's name, as shown in the following:
//Process B RChunk chk;
_LIT(KChunkName, "My Global Chunk"); Tint rc=chk.OpenGlobal(KChunkName,0);
/* error occurred, handle here (e.g. KErrNotFound is returned if it cannot open the chunk. */ }
//read from or write some data into chunk using *ptr
Global chunks are created via the RChunk::CreateGlobal() method. The first argument is the name of the chunk. The next two arguments specify the physical RAM assigned to the chunk (known as committed memory) and the amount of virtual memory to reserve for the chunk.
To understand this, let's briefly review the concepts of virtual memory and physical memory.
All addresses used by software are virtual memory addresses. There are 4 GB of virtual memory in the system. Virtual memory is only usable by software when it is mapped to physical memory - that is, actual RAM that resides on the smartphone. Virtual memory is mapped to physical memory by the CPU's MMU, in units of the memory page size (usually 4 KB). When virtual memory has physical memory mapped to it, it is considered as committed. Virtual memory addresses are very plentiful, while physical memory is a scarce resource. Refer to Chapter 3 for more details of memory usage in Symbian OS.
Figure 9.3 shows the chunk memory layout.
The committed size (the second argument of CreateGlobal()) specifies the size of the memory in the chunk that you can actually read and write. You can reserve a larger block of virtual memory (via the third argument) when creating the chunk so that you can expand the chunk's committed memory, while keeping it contiguous.
To expand the chunk's committed memory size, use the RChunk:: Adjust(TInt aNewSize) method, where aNewSize specifies the new size of the committed physical memory to the chunk (starting from its base address). The committed memory can be expanded up to the reserved maximum size specified in the third argument of CreateGlobal().
For example, say you create a chunk that has 0x1000 bytes of RAM committed to it, with a maximum size of 0x5000:
chk.CreateGlobal(KChunkName,0x10 00,0x500 0);
At this point you only have 0x1000 bytes of physical RAM assigned to your chunk to read and write. But you can expand the chunk later, for example by another 0x2000 bytes:
chk.Adjust(0x3000)
Reserved Memory (Virtual Addresses)
- Commited Memory (Physical RAM)
Figure 9.3 Layout of the Memory Chunk
Now your chunk has 0x3000 bytes of memory assigned, and since you had reserved 0x5000 bytes of virtual memory, the chunk memory stays contiguous up to that maximum.
RChunk::Base() is used to get a pointer to the chunk's memory area. This pointer can be used to write and read the chunk directly as needed (note, however, that it is the programmer's responsibility not to go out of bounds).
RChunk::OpenGlobal() is used to open an already created global chunk for access. The first argument to OpenGlobal() is the full chunk name. The second argument is used to indicate if the chunk is read only (1)or writable (0). An Open() method also exists that uses the TFindChunk matching class to open the chunk by a partial name. TFindChunk operates similarly to TFindProcess and TFindThread (in fact you could easily convert the example in section 9.1.6 to output all the global chunk names in the system using TFindChunk).
When a process is finished with the chunk, RChunk::Close() must be called. When the last reference to the global chunk is called, the global chunk itself is automatically deleted.
A more secure way of using global chunks between processes is to create the chunk without a name and reference it by its handle. This is more secure since the chunk cannot be found and used by another process via TFindChunk using this method. You can pass the handle to the chunk to another process either via client-server IPC or setting the handle as a parameter to the other process.
Here is an example of passing the handle as a parameter to a process:
const TInt KChunkIndex=0; const TInt KChunkSize=0x1000; RChunk chk;
chk.CreateGlobal(KNullDesC,KChunkSize,KChunkSize); RProcess proc;
LIT(KProcName,"myproc.exe"); proc.Create(KProcName); proc.SetParameter(KChunkIndex,chk); proc.Resume();
This code creates an anonymous global chunk, and sets the handle for the chunk as a parameter to the myproc.exe process by calling the RProcess::SetParameter() method. The first argument of Set-Parameter() is the index of the parameter (also known as the slot). The second argument is the handle. After setting the parameter, the process is started with RProcess::Resume().
Now let's see myproc.exe retrieve that handle and get access to the chunk:
RChunk chunk;
chunk.Open(KChunkIndex);
// chunk now points to the global chunk...
The version of RChunk::Open() used in this example takes a TInt as an argument, which represents the index of the parameter passed to the process where the RChunk handle was set. Error checking was omitted from these examples for simplicity.
Average user rating: 5 stars out of 3 votes
Post a comment