Commit Be Inc. sample code string atomizer module, as we need it in userland
(add-on) version too. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4190 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
aec1a1ebb1
commit
6e520af3a1
445
src/tests/kits/net/new_stack/atomizer/atomizer.c
Normal file
445
src/tests/kits/net/new_stack/atomizer/atomizer.c
Normal file
@ -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 <Drivers.h>
|
||||
#include <KernelExport.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <atomizer.h>
|
||||
|
||||
|
||||
#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
|
||||
};
|
||||
|
BIN
src/tests/kits/net/new_stack/atomizer/atomizer_module_x86.proj
Normal file
BIN
src/tests/kits/net/new_stack/atomizer/atomizer_module_x86.proj
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user