A memory region is allocated through the following call:
#include <chorus.h> int rgnAllocate(KnCap* actorCap, KnRgnDesc* rgnDesc);
This call creates a memory region as described by the rgnDesc parameter within the address space of the actor defined by the actorCap parameter. Most applications set actorCap to K_MYACTOR to manage their own address space.
An unused part of an address space may be freed by the following call:
#include <chorus.h> int rgnFree(KnCap* actorCap, KnRgnDesc* rgnDesc);
This call frees a memory region as described by the rgnDesc parameter within the address space of the actor defined by the actorCap parameter.
Example 7-1 does the following:
Allocates a memory region with the K_ANYWHERE
option.
Retrieves the address of the allocated region and prints it.
Copies a string to the beginning of the region.
Creates a second region immediately preceding the first.
Copies the string from the beginning of the first region to the beginning of the second region.
Frees an area of memory spanning the junction between the two regions.
Copies the string from the beginning of the second region to the lowest memory address still accessible outside the freed memory area.
Ensures that the program is able to run in a user or supervisor actor.
The main steps of the example are illustrated in Figure 7-1. Refer to the rgnAllocate(2K) and rgnFree(2K) man pages.
(file: progov/rgnAlloc.c) #include <stdio.h> #include <stdlib.h> #include <string.h> #include <chorus.h> #define RGN_SIZE_1 (6 * vmPageSize()) #define RGN_SIZE_2 (3 * vmPageSize()) #define FREE_START (2 * vmPageSize()) #define FREE_SIZE (4 * vmPageSize()) #define STILL_ALLOC_START (FREE_SIZE - (RGN_SIZE_2 - FREE_START)) int main(int argc, char** argv, char**envp) { KnRgnDesc rgnDesc; KnActorPrivilege actorP; int res; VmFlags rgnOpt = 0; char* ptr1 = NULL; /* Avoids "uninited" warning */ char* ptr2 = NULL; /* Avoids "uninited" warning */ printf("Starting rgnAllocate example\n"); res = actorPrivilege(K_MYACTOR, &actorP, NULL); if (res != K_OK) { printf("Cannot get actor privilege, error %d\n", res); exit(1); } if (actorP == K_SUPACTOR) { rgnOpt = K_SUPERVISOR; } rgnDesc.size = RGN_SIZE_1; rgnDesc.options = rgnOpt | K_WRITABLE | K_FILLZERO | K_ANYWHERE; rgnDesc.opaque1 = NULL; rgnDesc.opaque2 = NULL; /* * No need to set rgnDesc.startAddr * since we set the K_ANYWHERE flag */ res = rgnAllocate(K_MYACTOR, &rgnDesc); if (res == K_OK) { printf("Successfully allocated memory starting at 0x%x\n", rgnDesc.startAddr); ptr1 = (char*) rgnDesc.startAddr; } else { printf("First rgnAllocate failed with error %d\n", res); exit(1); } strcpy(ptr1, "Fill the allocated memory with this string\n"); /* * Second allocate has a fixed address, such that * both memory areas will be contiguous. Hence * we do not want the K_ANYWHERE flag any more. */ rgnDesc.size = RGN_SIZE_2; rgnDesc.options &= ~K_ANYWHERE; rgnDesc.startAddr -= RGN_SIZE_2; res = rgnAllocate(K_MYACTOR, &rgnDesc); if (res == K_OK) { printf("Successfully allocated memory starting at 0x%x)\n", rgnDesc.startAddr); ptr2 = (char*) rgnDesc.startAddr; } else { printf("Second rgnAllocate failed with error %d\n", res); exit(1); } /* Copy from first allocated area to second one */ strcpy(ptr2, ptr1); /* * Free a memory area spanning both areas * previously created */ rgnDesc.options = NULL; rgnDesc.startAddr = (VmAddr) (ptr2 + FREE_START); rgnDesc.size = FREE_SIZE; res = rgnFree(K_MYACTOR, &rgnDesc); if (res != K_OK) { printf("Cannot free memory, error %d\n", res); exit(1); } /* * Access to ptr2: beginning of secondly allocated area * is still valid. * Access to ptr1 is now invalid: memory has been freed. */ printf("%s", ptr2); /* * Access to "end" of first allocated area * is still valid */ ptr1 += STILL_ALLOC_START; strcpy(ptr1, ptr2); /* * Remaining memory areas not yet freed will * effectively be freed at actor termination time. */ return 0; }
Region descriptors are uniquely used to describe a creation or deletion operation on the system. They are not kept by the system in the way they are given to the rgnAllocate() call. As an example, allocation of two contiguous areas with the same attributes (writable, fill zero) and the same opaque fields will result in the system recognizing a single region, the size of which is the sum of the sizes passed as part of the two region descriptors.
You cannot allocate a region on a range of addresses which are not free. No implicit deallocation of the address space is undertaken by the system, instead an error code K_EOVERLAP is returned to the caller.
A call to rgnFree() does not need to reuse a region descriptor that was used to allocate a memory area. A free operation may freely span over several regions which were allocated by separate operations. Similarly, a free operation may only free a chunk of memory in the middle of a large memory area which was allocated in a single operation. See Figure 7-1.
Only the precise region described in the region descriptor will be freed. The free operation is not extended to match the address range which was allocated at rgnAllocate() time.
The options field of the region descriptor must be set to 0 for a free operation. Otherwise, you may set it to K_FREEALL, in which case all memory regions of the actor will be freed: the code, the data, the stacks. The K_FREEALL option should therefore be used with care.
All memory areas which have been dynamically allocated are freed when the actor terminates.