// L4/L4Env includes #include <l4/slab/slab.h> #include <l4/dm_mem/dm_mem.h> #include <l4/env/errno.h> #define OBJ_SIZE 64 // grow callback static void * __grow_simple(l4slab_cache_t * cache, void ** data) { void * page; // allocate and map page page = l4dm_mem_allocate(L4_PAGESIZE,L4RM_MAP | L4RM_LOG2_ALIGNED); if (page == NULL) Error("__grow_simple: page allocation failed!\n"); return page; } // release callback static void __release_simple(l4slab_cache_t * cache, void * page, void * data) { // free page l4dm_mem_release(page); } // Main int main(void) { l4slab_cache_t slab; int ret; void * objp; // initialize slab ret = l4slab_cache_init(&slab,OBJ_SIZE,0,__grow_simple,__release_simple); if (ret < 0) { Error("slab cache initializstion failed: %s (%d)\n", l4env_errstr(ret),ret); return -1; } // allocate object objp = l4slab_alloc(&slab); // do something // release object l4slab_free(&slab,objp); // destroy slab l4slab_destroy(&slab); // done return 0; }
This is an a bit more advanced example of how to build a grow-only heap for a slab cache. It avoids to create a new dataspace / vm-region for each page added to the slab cache, instead it resizes the heap dataspace to add a new page to the slab cache.
// L4/L4Env includes #include <l4/slab/slab.h> #include <l4/dm_mem/dm_mem.h> #include <l4/l4rm/l4rm.h> #include <l4/env/errno.h> #include <l4/util/macros.h> #define MAX_HEAP_SIZE (64 * 1024) #define INIT_HEAP_SIZE (16 * 1024) l4dm_dataspace_t heap_ds; l4_addr_t heap_addr; l4_size_t heap_cur_size; // grow callback static void * __grow(l4slab_cache_t * cache, void ** data) { l4_addr_t addr; l4_size_t new_size; int ret; if ((heap_cur_size + L4_PAGESIZE) > MAX_HEAP_SIZE) { printf("__grow: heap overflow!\n"); return NULL; } // resize dataspace addr = heap_addr + heap_cur_size; new_size = heap_cur_size + L4_PAGESIZE; ret = l4dm_mem_resize(&heap_ds,new_size); if (ret < 0) { printf("__grow: resize heap dataspace failed: %s (%d)\n", l4env_errstr(ret),ret); return NULL; } heap_cur_size = new_size; // done return (void *)addr; } // Main int main(void) { int ret; void * heap, * page; l4slab_cache_t slab; void * objp; // allocate heap dataspace ret = l4dm_mem_open(L4DM_DEFAULT_DSM, INIT_HEAP_SIZE, L4_PAGESIZE, 0, "Heap", &heap_ds); if (ret < 0) { Error("heap allocation failed: %s (%d)\n",l4env_errstr(ret),ret); return -1; } // attach heap dataspace, already reserve the whole vm area ret = l4rm_attach(&heap_ds, MAX_HEAP_SIZE, 0, L4DM_RW, &heap); if (ret < 0) { Error("attach heap dataspace failed: %s (%d)\n",l4env_errstr(ret),ret); l4dm_close(&heap_ds); return -1; } heap_addr = (l4_addr_t)heap; heap_cur_size = INIT_HEAP_SIZE; // setup slab cache, no release callback ret = l4slab_cache_init(&slab,OBJ_SIZE,0,__grow,NULL); if (ret < 0) { Error("slab cache initialization failed: %s (%d)\n", l4env_errstr(ret),ret); return -1; } // add initial pages to the slab cache page = heap; while (page < (heap + INIT_HEAP_SIZE)) { l4slab_add_page(&slab,page,NULL); page += L4_PAGESIZE; } // allocate objects objp = l4slab_alloc(&slab); // do something // release object l4slab_free(&slab,objp); // destroy slab l4slab_destroy(&slab); // release heap memory l4rm_detach((void *)heap_addr); l4dm_close(&heap_ds); }