|
||
Chunks map RAM or memory-mapped I/O devices into contiguous virtual addresses.
A chunk consists of a reserved region and a committed region. The reserved region is the contiguous set of virtual addresses accessible to running code. The committed region is the region in which RAM (or memory-mapped I/O) is actually mapped. The size of a chunk is dynamically alterable, allowing the committed region to vary in size from zero up to the reserved region size, in integer multiples of the processor page size. This allows processes to obtain more memory on demand. Generally the committed region starts at the bottom of the reserved region.
A chunk also has a maximum size, which is defined when the chunk is created. The reserved region can be smaller than this maximum size, but it can also be made bigger by reallocating it. The reserved region cannot be made bigger than the maximum size.
The size of the reserved region of a chunk is always an integer multiple of the virtual address range of a single entry in the processor page directory (PDE size). This means that the reserved region of a chunk is mapped by a number of consecutive page directory entries (PDEs). Any given PDE maps part of the reserved region of at most one chunk.
Symbian OS has a number of chunk types, but for user side code, the chunks of interest are User chunks and Shared chunks.
A chunk is a kernel side entity, and like all other kernel side entities,
it is accessed from the user side using a handle, an instance of the
RChunk
class. The concept of local and
global also applies to chunks.
On systems with an MMU, Symbian OS provides three types of user chunks. Each type is characterised by having a different subset of the reserved address range containing committed memory:
These chunks have a committed region consisting of a single contiguous range starting at the chunk's base address and a size that is a multiple of the MMU page size. The following diagram is an example of this kind of chunk:
These chunks have a committed region consisting of a single contiguous range starting at arbitrary lower and upper endpoints within the reserved region. The only condition is that the lower and upper endpoints must be a multiple of the MMU page size. Both the bottom and top of the committed region can be altered dynamically. The following diagram shows an example of this kind of chunk:
These chunks have a committed region consisting of an arbitrary set of MMU pages within the reserved region. Each page-sized address range within the reserved region starting on a page boundary can be committed independently. The following diagram shows an example of this kind of chunk:
A shared chunk is a mechanism that allows kernel-side code to share memory buffers safely with user-side code. By kernel-side code, we usually mean device driver code.
The main points to note about shared chunks are:
They can only be created and destroyed by device drivers. It is typical behaviour for user-side code, which in this context we refer to as the client of the device driver, to pass a request to the device driver to open a handle to a shared chunk. This causes the device driver to open a handle to the chunk and return the handle value to the client. Successful handle creation also causes the chunk's memory to be mapped into the address space of the process to which the client's thread belongs. Note, however, that it is the the driver that dictates exactly when the chunk itself is created, and when memory is committed. The precise protocol depends on the design of the driver; you need to refer to that driver's documentation for programming guidance.
Like all kernel side objects, a shared chunk is reference counted. This means that it remains in existence for as long as the reference count is greater than zero. Once all opened references to the shared chunk have been closed, regardless of whether the references are user-side, or kernel-side, then it is destroyed.
User-side code that has gained access to a shared chunk from one device driver can pass this to a second device driver. The second device driver must open the chunk before it can be used.
More than one user side application can access the data in a shared chunk. A handle to a shared chunk can be passed from one process to another process using standard handle passing mechanisms. In practice, handles would be passed in a client-server context, either from client to server or from server to client using inter process communication (IPC).
Processes that share data inside a chunk should communicate the location of that data as an offset from the start of the chunk, and not as an absolute address. The shared chunk may appear at different addresses within the address spaces of different user processes.
A chunk is local when it is private to the process creating it and is not intended for access by other user processes.
A local chunk cannot be mapped into any other process and is, therefore, used for memory that does not need to be shared.
A local chunk does not have a name.
A chunk is global if it is intended to be accessed by other processes.
Global chunks have names that can be used to identify the chunk to another process wishing to access it. A process can open a global chunk by name; this maps the chunk into that process's address space, allowing direct access and enabling the sharing of data between processes.
If the name of the global chunk to be opened is known, use
RChunk::OpenGlobal()
. If a part of the name is known, use
the RChunk::Open()
variant that takes a
TFindChunk
.
A process can only access an unnamed global chunk if it is passed a
handle to that chunk from another process. See
RChunk::Open()
.