diff --git a/src/tests/kits/net/new_stack/atomizer/atomizer.c b/src/tests/kits/net/new_stack/atomizer/atomizer.c new file mode 100644 index 0000000000..40cb3609b8 --- /dev/null +++ b/src/tests/kits/net/new_stack/atomizer/atomizer.c @@ -0,0 +1,445 @@ +/******************************************************************************* +/ +/ File: atomizer.c +/ +/ Description: Kernel module implementing kernel-space atomizer API +/ +/ Copyright 1999, Be Incorporated, All Rights Reserved. +/ This file may be used under the terms of the Be Sample Code License. +/ +*******************************************************************************/ + +#include +#include +#include +#include + +#include + + +#if DEBUG > 0 +#define ddprintf(x) dprintf x +#else +#define ddprintf(x) +#endif + +typedef struct { + sem_id sem; + int32 ben; +} benaphore; + +#define INIT_BEN(x) x.sem = create_sem(0, "an atomizer benaphore"); x.ben = 0; +#define ACQUIRE_BEN(x) if((atomic_add(&(x.ben), 1)) >= 1) acquire_sem(x.sem); +#define ACQUIRE_BEN_ON_ERROR(x, y) if((atomic_add(&(x.ben), 1)) >= 1) if (acquire_sem(x.sem) != B_OK) y; +#define RELEASE_BEN(x) if((atomic_add(&(x.ben), -1)) > 1) release_sem(x.sem); +#define DELETE_BEN(x) delete_sem(x.sem); x.sem = -1; x.ben = 1; + +#define MIN_BLOCK_SIZE B_PAGE_SIZE + +typedef struct block_list block_list; + +struct block_list{ + block_list *next; + uint8 *free_space; + uint32 free_bytes; +}; + +typedef struct { + benaphore lock; /* serializes access to this atomizer */ + block_list *blocks; /* list of blocks holding atomized strings */ + uint32 count; /* number of atoms in this list */ + uint32 slots; /* total number of spaces in the allocated vector */ + uint8 **vector; /* sorted vector of pointers to atomized strings */ +} atomizer_data; + +typedef struct atomizer_data_list atomizer_data_list; + +struct atomizer_data_list { + char *name; /* the atomizer's name */ + atomizer_data *the_atomizer; /* the atomizer data */ + atomizer_data_list *next; /* the next atomizer in the list */ +}; + + +/* Module static data */ +const char atomizer_module_name[] = B_ATOMIZER_MODULE_NAME; +const char system_atomizer_name[] = B_SYSTEM_ATOMIZER_NAME; + +static benaphore module_lock; +static atomizer_data_list *atomizer_list; + +static atomizer_data * +make_atomizer(void) { + atomizer_data *ad; + + /* get space for atomizer data */ + ad = (atomizer_data *)malloc(sizeof(atomizer_data)); + if (ad) { + /* init locks */ + INIT_BEN(ad->lock); + if (ad->lock.sem >= 0) { + /* get first block for atomized strings */ + ad->blocks = (block_list *)malloc(MIN_BLOCK_SIZE); + if (ad->blocks) { + /* get vector for pointers to strings */ + ad->vector = (uint8 **)malloc(MIN_BLOCK_SIZE); + if (ad->vector) { + /* fill in the details */ + ad->blocks->next = 0; + ad->blocks->free_space = ((uint8 *)ad->blocks)+sizeof(block_list); + ad->blocks->free_bytes = MIN_BLOCK_SIZE - sizeof(block_list); + ad->count = 0; + ad->slots = MIN_BLOCK_SIZE / sizeof(uint8 *); + goto exit0; + } + /* oops, vector allocation failed */ + free(ad->blocks); + } + /* oops, block list allocation failed */ + DELETE_BEN(ad->lock); + } + /* oops, sem creation failed */ + free(ad); + ad = 0; + } +exit0: + ddprintf(("make_atomizer() returns %p\n", ad)); + return ad; +} + +static void +free_atomizer(atomizer_data *ad) { + block_list *bl, *blnext; + + /* Acquire the lock or fail trying. Better to not free + the data than corrupt the kernel heap */ + ACQUIRE_BEN_ON_ERROR(ad->lock, return); + /* walk the block_list, freeing them up */ + bl = ad->blocks; + while (bl) { + blnext = bl->next; + free(bl); + bl = blnext; + } + /* release vector of pointers to atomized strings */ + free(ad->vector); + /* delete the benaphore */ + DELETE_BEN(ad->lock); + /* finaly, release the atomizer data */ + free(ad); +} + +static const void * +find_or_make_atomizer(const char *string) { + atomizer_data_list *adl = atomizer_list; + atomizer_data_list *last = 0; + void * at = (void *)0; + + /* null or zero-length string means system atomizer */ + if (!string || (strlen(string) == 0)) string = system_atomizer_name; + + /* lock the atomizer list or fail returning a bogus atomizer */ + ACQUIRE_BEN_ON_ERROR(module_lock, return at); + ddprintf(("success locking module\n")); + while (adl && strcmp(adl->name, string)) { + last = adl; + adl = adl->next; + } + if (adl) { + at = (void *)adl->the_atomizer; + ddprintf(("asked for %s, returning %p\n", string, at)); + goto exit0; + } + ddprintf(("didn't find atomizer %s, making it\n", string)); + + adl = (atomizer_data_list *)malloc(sizeof(atomizer_data_list)); + if (adl) { + adl->the_atomizer = make_atomizer(); + if (adl->the_atomizer) { + adl->name = strdup(string); + if (adl->name) { + /* append to list */ + if (last) last->next = adl; + else atomizer_list = adl; + adl->next = 0; + at = (void *)adl->the_atomizer; + goto exit0; + } + free_atomizer(adl->the_atomizer); + } + free(adl); + } +exit0: + RELEASE_BEN(module_lock); + ddprintf(("find_or_make_atomizer() returning %p\n", at)); + return at; +} + +static status_t +init() +{ + ddprintf((T_ATOMIZER_MODULE_NAME": init()\n")); + /* init the module-wide benaphore */ + INIT_BEN(module_lock); + if (module_lock.sem >= 0) { + /* create list of atomizers */ + atomizer_list = 0; + if (find_or_make_atomizer(0)) + return B_OK; + /* oops, couldn't create system atomizer */ + DELETE_BEN(module_lock); + module_lock.sem = B_ERROR; + } + return module_lock.sem; +} + +static status_t +uninit() +{ + atomizer_data_list *adl; + /* aquire the module-wide lock. This is pure paranoia. + If it fails, all hell as broken loose, but we won't contribute + by corrupting the heap. */ + ddprintf((T_ATOMIZER_MODULE_NAME": uninit()\n")); + ACQUIRE_BEN_ON_ERROR(module_lock, return B_ERROR); + if (atomizer_list->next) { + ddprintf((T_ATOMIZER_MODULE_NAME": uninit called with non-system atomizers still active!\n")); + } + /* delete all of the atomizers. Ideally, there should only + be the system atomizer left */ + adl = atomizer_list; + while (adl) { + free_atomizer(adl->the_atomizer); + free(adl->name); + adl = adl->next; + } + /* free up the module-wide benaphore */ + DELETE_BEN(module_lock); + return B_OK; +} + +static status_t +std_ops(int32 op, ...) +{ + switch(op) { + case B_MODULE_INIT: + return init(); + case B_MODULE_UNINIT: + return uninit(); + default: + /* do nothing */ + ; + } + return -1; +} + +static status_t +delete_atomizer(const void * at) { + atomizer_data_list *adl; + atomizer_data_list *last = 0; + status_t result = B_ERROR; + + ACQUIRE_BEN_ON_ERROR(module_lock, return B_ERROR); + adl = atomizer_list; + while (adl && (adl->the_atomizer != (atomizer_data *)at)) { + last = adl; + adl = adl->next; + } + + if (adl) { + /* don't let clients delete the system atomizer */ + if (strcmp(adl->name, system_atomizer_name) != 0) { + free_atomizer(adl->the_atomizer); + free(adl->name); + /* the system atomizer is always first, so last will be non-zero */ + last->next = adl->next; + free(adl); + result = B_OK; + } + } + RELEASE_BEN(module_lock); + return result; +} + +static const void * +atomize(const void * at, const char *string, int create) { + atomizer_data_list *adl; + void *result = 0; + uint32 len; + + /* NULL and zero length strings aren't interned */ + if (!string || !(len = strlen(string))) return 0; + /* include the null terminator */ + len++; + /* own the list or fail trying */ + ACQUIRE_BEN_ON_ERROR(module_lock, return 0); + + /* use the system atomizer if none specified */ + if (at == ((void *)(-1))) at = atomizer_list->the_atomizer; + + /* walk the list of known atomizers, looking for a match */ + adl = atomizer_list; + while (adl && (adl->the_atomizer != (atomizer_data *)at)) { + adl = adl->next; + } + /* lock the atomizer *before* we give up control over the list */ + if (adl) ACQUIRE_BEN(adl->the_atomizer->lock); + /* allow list manipulations */ + RELEASE_BEN(module_lock); + /* did we find the one we wanted? */ + if (adl) { + atomizer_data *ad = adl->the_atomizer; + uint8 **vector = ad->vector; + uint32 count = ad->count; + uint32 low = 0; + uint32 high = count; + uint32 index = 0; + int test = -1; + /* do a binary search on the vector for a match */ + while (low < high) { + index = (low + high) / 2; + test = strcmp(string, (const char *)vector[index]); + if (test < 0) + high = index; + else if (test > 0) + low = index + 1; + else + break; + } + /* if match found, note result and return it */ + if (test == 0) { + result = vector[index]; + } else { + /* if we're not "just checking" */ + if (create) { + /* no match, so add to list */ + /* find first block with enough room */ + block_list *bl = ad->blocks; + while (bl->next) { + if (bl->free_bytes >= len) break; + bl = bl->next; + } + if (bl->free_bytes < len) { + /* allocate a block big enough to handle the string */ + size_t block_size = ((sizeof(block_list)+len+(MIN_BLOCK_SIZE-1)) & ~(MIN_BLOCK_SIZE-1)); + bl->next = (block_list *)malloc(block_size); + if (!bl->next) { + RELEASE_BEN(ad->lock); + return 0; + } + bl = bl->next; + bl->free_space = (uint8 *)(bl+1); + bl->free_bytes = block_size - sizeof(block_list); + } + /* actually intern an atom */ + result = bl->free_space; + memcpy(result, string, len); + bl->free_space += len; + bl->free_bytes -= len; + + /* insert the pointer in the vector */ + /* if the vector isn't big enough, realloc it */ + if (ad->count == ad->slots) { + size_t newslots = ad->slots + (MIN_BLOCK_SIZE / sizeof(uint8 *)); + uint8 **newvec = realloc(vector, newslots * sizeof(uint8 *)); + if (!newvec) { + /* bail, leaving the atom un-interned */ + RELEASE_BEN(ad->lock); + return 0; + } + ad->slots = newslots; + vector = ad->vector = newvec; + } + /* move all of the entries starting at index down one slot */ + memmove(vector + index + 1, vector + index, (count - index) * sizeof(uint8 *)); + /* insert the new pointer in the vector */ + vector[index] = result; + /* note new count */ + ad->count++; + } + } + RELEASE_BEN(ad->lock); + } + return result; +} + +const char * +string_for_token(const void *atomizer, const void *atom) { + /* someday, check for validity */ + return atom; +} + +status_t +get_next_atomizer_info(void **cookie, atomizer_info *info) { + atomizer_data_list *adl; + atomizer_data_list *atomizer = (atomizer_data_list *)*cookie; + status_t result = B_ERROR; + + ddprintf(("get_next_atomizer_info(cookie: %p, info: %p)\n", *cookie, info)); + /* a NULL info pointer? */ + if (!info) return result; + + ACQUIRE_BEN_ON_ERROR(module_lock, return result); + /* null? start over */ + if (!atomizer) atomizer = atomizer_list; + adl = atomizer_list; + while (adl && (adl != atomizer)) + adl = adl->next; + if (adl) { + *cookie = atomizer->next; + /* use a bogus cookie if no more left */ + if (!*cookie) *cookie = (void *)-1; + info->atomizer = atomizer->the_atomizer; + strncpy(info->name, adl->name, B_OS_NAME_LENGTH); + info->name[B_OS_NAME_LENGTH - 1] = '\0'; + info->atom_count = atomizer->the_atomizer->count; + result = B_OK; + } + RELEASE_BEN(module_lock); + return result; +} + +const void * +get_next_atom(const void *_atomizer, uint32 *cookie) { + atomizer_data_list *adl; + atomizer_data *atomizer = (atomizer_data *)_atomizer; + void *result = 0; + + /* validate the atomizer */ + ACQUIRE_BEN_ON_ERROR(module_lock, return 0); + adl = atomizer_list; + while (adl && (adl->the_atomizer != atomizer)) + adl = adl->next; + /* lock the atomizer *before* we give up control over the list */ + if (adl) ACQUIRE_BEN(atomizer->lock); + /* allow list manipulations */ + RELEASE_BEN(module_lock); + if (adl) { + if (*cookie < atomizer->count) { + result = atomizer->vector[*cookie]; + (*cookie)++; + } + RELEASE_BEN(atomizer->lock); + } + return result; +} + +static atomizer_module_info atomizer = { + { + atomizer_module_name, + 0, + std_ops + }, + find_or_make_atomizer, + delete_atomizer, + atomize, + string_for_token, + get_next_atomizer_info, + get_next_atom +}; + +_EXPORT atomizer_module_info *modules[] = { + &atomizer, + NULL +}; + diff --git a/src/tests/kits/net/new_stack/atomizer/atomizer_module_x86.proj b/src/tests/kits/net/new_stack/atomizer/atomizer_module_x86.proj new file mode 100644 index 0000000000..db0f56a897 Binary files /dev/null and b/src/tests/kits/net/new_stack/atomizer/atomizer_module_x86.proj differ