Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * Copyright (c) 1984 through 2008, William LeFebvre
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *
     11  *     * Redistributions in binary form must reproduce the above
     12  * copyright notice, this list of conditions and the following disclaimer
     13  * in the documentation and/or other materials provided with the
     14  * distribution.
     15  *
     16  *     * Neither the name of William LeFebvre nor the names of other
     17  * contributors may be used to endorse or promote products derived from
     18  * this software without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 /* hash.m4c */
     34 
     35 /* The file hash.c is generated from hash.m4c via the preprocessor M4 */
     36 
     37 /*
     38  * Hash table functions:  init, add, lookup, first, next, sizeinfo.
     39  * This is a conventional "bucket hash".  The key is hashed in to a number
     40  * less than or equal to the number of buckets and the result is used
     41  * to index in to the array of buckets.  Each bucket is a linked list
     42  * that contains all the key/value pairs which hashed to that index.
     43  */
     44 
     45 #include "os.h"
     46 
     47 #ifdef HAVE_MATH_H
     48 #include <math.h>
     49 #endif
     50 
     51 #include "hash.h"
     52 
     53 static int
     54 next_prime(int x)
     55 
     56 {
     57     double i, j;
     58     int f;
     59 
     60     i = x;
     61     while (i++)
     62     {
     63 	f=1;
     64 	for (j=2; j<i; j++)
     65 	{
     66 	    if ((i/j)==floor(i/j))
     67 	    {
     68 		f=0;
     69 		break;
     70 	    }
     71 	}
     72 	if (f)
     73 	{
     74 	    return (int)i;
     75 	}
     76     }
     77     return 1;
     78 }
     79 
     80 /* string hashes */
     81 
     82 static int
     83 string_hash(hash_table *ht, char *key)
     84 
     85 {
     86     unsigned long s = 0;
     87     unsigned char ch;
     88     int shifting = 24;
     89 
     90     while ((ch = (unsigned char)*key++) != '\0')
     91     {
     92 	if (shifting == 0)
     93 	{
     94 	    s = s + ch;
     95 	    shifting = 24;
     96 	}
     97 	else
     98 	{
     99 	    s = s + (ch << shifting);
    100 	    shifting -= 8;
    101 	}
    102     }
    103 
    104     return (s % ht->num_buckets);
    105 }
    106 
    107 static void ll_init(llist *q)
    108 
    109 {
    110     q->head = NULL;
    111     q->count = 0;
    112 }
    113 
    114 static llistitem *ll_newitem(int size)
    115 
    116 {
    117     llistitem *qi;
    118 
    119     qi = emalloc(sizeof(llistitem) + size);
    120     qi->datum = ((char *)qi + sizeof(llistitem));
    121     return qi;
    122 }
    123 
    124 static void ll_freeitem(llistitem *li)
    125 
    126 {
    127     free(li);
    128 }
    129 
    130 static void ll_add(llist *q, llistitem *new)
    131 
    132 {
    133     new->next = q->head;
    134     q->head = new;
    135     q->count++;
    136 }
    137 
    138 static void ll_extract(llist *q, llistitem *qi, llistitem *last)
    139 
    140 {
    141     if (last == NULL)
    142     {
    143 	q->head = qi->next;
    144     }
    145     else
    146     {
    147 	last->next = qi->next;
    148     }
    149     qi->next = NULL;
    150     q->count--;
    151 }
    152 
    153 #define LL_FIRST(q) ((q)->head)
    154 #define LL_NEXT(q, qi)  ((qi) != NULL ? (qi)->next : NULL)
    155 #define LL_ISEMPTY(ll)  ((ll)->count == 0)
    156 
    157 #ifdef notdef
    158 static llistitem *
    159 ll_first(llist *q)
    160 
    161 {
    162     return q->head;
    163 }
    164 
    165 static llistitem *
    166 ll_next(llist *q, llistitem *qi)
    167 
    168 {
    169     return (qi != NULL ? qi->next : NULL);
    170 }
    171 
    172 static int
    173 ll_isempty(llist *ll)
    174 
    175 {
    176     return (ll->count == 0);
    177 }
    178 #endif
    179 
    180 /*
    181  * hash_table *hash_create(int num)
    182  *
    183  * Creates a hash table structure with at least "num" buckets.
    184  */
    185 
    186 hash_table *
    187 hash_create(int num)
    188 
    189 {
    190     hash_table *result;
    191     bucket_t *b;
    192     int bytes;
    193     int i;
    194 
    195     /* create the resultant structure */
    196     result = emalloc(sizeof(hash_table));
    197 
    198     /* adjust bucket count to be prime */
    199     num = next_prime(num);
    200 
    201     /* create the buckets */
    202     bytes = sizeof(bucket_t) * num;
    203     result->buckets = b = emalloc(bytes);
    204     result->num_buckets = num;
    205 
    206     /* create each bucket as a linked list */
    207     i = num;
    208     while (--i >= 0)
    209     {
    210 	ll_init(&(b->list));
    211 	b++;
    212     }
    213 
    214     return result;
    215 }
    216 
    217 /*
    218  * unsigned int hash_count(hash_table *ht)
    219  *
    220  * Return total number of elements contained in hash table.
    221  */
    222 
    223 #ifdef notdef
    224 static unsigned int
    225 hash_count(hash_table *ht)
    226 
    227 {
    228     register int i = 0;
    229     register int cnt = 0;
    230     register bucket_t *bucket;
    231 
    232     bucket = ht->buckets;
    233     while (i++ < ht->num_buckets)
    234     {
    235 	cnt += bucket->list.count;
    236 	bucket++;
    237     }
    238 
    239     return cnt;
    240 }
    241 #endif
    242 
    243 /*
    244  * void hash_sizeinfo(unsigned int *sizes, int max, hash_table *ht)
    245  *
    246  * Fill in "sizes" with information about bucket lengths in hash
    247  * table "max".
    248  */
    249 
    250 void
    251 hash_sizeinfo(unsigned int *sizes, int max, hash_table *ht)
    252 
    253 {
    254     register int i;
    255     register int idx;
    256     register bucket_t *bucket;
    257 
    258     memzero(sizes, max * sizeof(unsigned int));
    259 
    260     bucket = ht->buckets;
    261     i = 0;
    262     while (i++ < ht->num_buckets)
    263     {
    264 	idx = bucket->list.count;
    265 	sizes[idx >= max ? max-1 : idx]++;
    266 	bucket++;
    267     }
    268 }
    269 
    270 
    271 
    272 
    273 
    274 
    275 
    276 /*
    277  * void hash_add_uint(hash_table *ht, unsigned int key, void *value)
    278  *
    279  * Add an element to table "ht".  The element is described by
    280  * "key" and "value".  Return NULL on success.  If the key
    281  * already exists in the table, then no action is taken and
    282  * the data for the existing element is returned.
    283  * Key type is unsigned int
    284  */
    285 
    286 void *
    287 hash_add_uint(hash_table *ht, unsigned int key, void *value)
    288 
    289 {
    290     bucket_t *bucket;
    291     hash_item_uint *hi;
    292     hash_item_uint *h;
    293     llist *ll;
    294     llistitem *li;
    295     llistitem *newli;
    296     unsigned int k1;
    297 
    298     /* allocate the space we will need */
    299     newli = ll_newitem(sizeof(hash_item_uint));
    300     hi = (hash_item_uint *)newli->datum;
    301 
    302     /* fill in the values */
    303     hi->key = key;
    304     hi->value = value;
    305 
    306     /* hash to the bucket */
    307     bucket = &(ht->buckets[(key % ht->num_buckets)]);
    308 
    309     /* walk the list to make sure we do not have a duplicate */
    310     ll = &(bucket->list);
    311     li = LL_FIRST(ll);
    312     while (li != NULL)
    313     {
    314 	h = (hash_item_uint *)li->datum;
    315 	k1 = h->key;
    316 	if (key == k1)
    317 	{
    318 	    /* found one */
    319 	    break;
    320 	}
    321 	li = LL_NEXT(ll, li);
    322     }
    323     li = NULL;
    324 
    325     /* is there already one there? */
    326     if (li == NULL)
    327     {
    328 	/* add the unique element to the buckets list */
    329 	ll_add(&(bucket->list), newli);
    330 	return NULL;
    331     }
    332     else
    333     {
    334 	/* free the stuff we just allocated */
    335 	ll_freeitem(newli);
    336 	return ((hash_item_uint *)(li->datum))->value;
    337     }
    338 }
    339 
    340 /*
    341  * void *hash_replace_uint(hash_table *ht, unsigned int key, void *value)
    342  *
    343  * Replace an existing value in the hash table with a new one and
    344  * return the old value.  If the key does not already exist in
    345  * the hash table, add a new element and return NULL.
    346  * Key type is unsigned int
    347  */
    348 
    349 void *
    350 hash_replace_uint(hash_table *ht, unsigned int key, void *value)
    351 
    352 {
    353     bucket_t *bucket;
    354     hash_item_uint *hi;
    355     llist *ll;
    356     llistitem *li;
    357     void *result = NULL;
    358     unsigned int k1;
    359 
    360     /* find the bucket */
    361     bucket = &(ht->buckets[(key % ht->num_buckets)]);
    362 
    363     /* walk the list until we find the existing item */
    364     ll = &(bucket->list);
    365     li = LL_FIRST(ll);
    366     while (li != NULL)
    367     {
    368 	hi = (hash_item_uint *)li->datum;
    369 	k1 = hi->key;
    370 	if (key == k1)
    371 	{
    372 	    /* found it: now replace the value with the new one */
    373 	    result = hi->value;
    374 	    hi->value = value;
    375 	    break;
    376 	}
    377 	li = LL_NEXT(ll, li);
    378     }
    379 
    380     /* if the element wasnt found, add it */
    381     if (result == NULL)
    382     {
    383 	li = ll_newitem(sizeof(hash_item_uint));
    384 	hi = (hash_item_uint *)li->datum;
    385 	hi->key = key;
    386 	hi->value = value;
    387 	ll_add(&(bucket->list), li);
    388     }
    389 
    390     /* return the old value (so it can be freed) */
    391     return result;
    392 }
    393 
    394 /*
    395  * void *hash_lookup_uint(hash_table *ht, unsigned int key)
    396  *
    397  * Look up "key" in "ht" and return the associated value.  If "key"
    398  * is not found, return NULL.  Key type is unsigned int
    399  */
    400 
    401 void *
    402 hash_lookup_uint(hash_table *ht, unsigned int key)
    403 
    404 {
    405     bucket_t *bucket;
    406     llist *ll;
    407     llistitem *li;
    408     hash_item_uint *h;
    409     void *result;
    410     unsigned int k1;
    411 
    412     result = NULL;
    413     if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
    414     {
    415 	ll = &(bucket->list);
    416 	li = LL_FIRST(ll);
    417 	while (li != NULL)
    418 	{
    419 	    h = (hash_item_uint *)li->datum;
    420 	    k1 = h->key;
    421 	    if (key == k1)
    422 	    {
    423 		result = h->value;
    424 		break;
    425 	    }
    426 	    li = LL_NEXT(ll, li);
    427 	}
    428     }
    429     return result;
    430 }
    431 
    432 /*
    433  * void *hash_remove_uint(hash_table *ht, unsigned int key)
    434  *
    435  * Remove the element associated with "key" from the hash table
    436  * "ht".  Return the value or NULL if the key was not found.
    437  */
    438 
    439 void *
    440 hash_remove_uint(hash_table *ht, unsigned int key)
    441 
    442 {
    443     bucket_t *bucket;
    444     llist *ll;
    445     llistitem *li;
    446     llistitem *lilast;
    447     hash_item_uint *hi;
    448     void *result;
    449     unsigned int k1;
    450 
    451     result = NULL;
    452     if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
    453     {
    454 	ll = &(bucket->list);
    455 	li = LL_FIRST(ll);
    456 	lilast = NULL;
    457 	while (li != NULL)
    458 	{
    459 	    hi = (hash_item_uint *)li->datum;
    460 	    k1 = hi->key;
    461 	    if (key == k1)
    462 	    {
    463 		ll_extract(ll, li, lilast);
    464 		result = hi->value;
    465 		key = hi->key;
    466 		;
    467 		ll_freeitem(li);
    468 		break;
    469 	    }
    470 	    lilast = li;
    471 	    li = LL_NEXT(ll, li);
    472 	}
    473     }
    474     return result;
    475 }
    476 
    477 /*
    478  * hash_item_uint *hash_first_uint(hash_table *ht, hash_pos *pos)
    479  *
    480  * First function to call when iterating through all items in the hash
    481  * table.  Returns the first item in "ht" and initializes "*pos" to track
    482  * the current position.
    483  */
    484 
    485 hash_item_uint *
    486 hash_first_uint(hash_table *ht, hash_pos *pos)
    487 
    488 {
    489     /* initialize pos for first item in first bucket */
    490     pos->num_buckets = ht->num_buckets;
    491     pos->hash_bucket = ht->buckets;
    492     pos->curr = 0;
    493     pos->ll_last = NULL;
    494 
    495     /* find the first non-empty bucket */
    496     while(pos->hash_bucket->list.count == 0)
    497     {
    498 	pos->hash_bucket++;
    499 	if (++pos->curr >= pos->num_buckets)
    500 	{
    501 	    return NULL;
    502 	}
    503     }
    504 
    505     /* set and return the first item */
    506     pos->ll_item = LL_FIRST(&(pos->hash_bucket->list));
    507     return (hash_item_uint *)pos->ll_item->datum;
    508 }
    509 
    510 
    511 /*
    512  * hash_item_uint *hash_next_uint(hash_pos *pos)
    513  *
    514  * Return the next item in the hash table, using "pos" as a description
    515  * of the present position in the hash table.  "pos" also identifies the
    516  * specific hash table.  Return NULL if there are no more elements.
    517  */
    518 
    519 hash_item_uint *
    520 hash_next_uint(hash_pos *pos)
    521 
    522 {
    523     llistitem *li;
    524 
    525     /* move item to last and check for NULL */
    526     if ((pos->ll_last = pos->ll_item) == NULL)
    527     {
    528 	/* are we really at the end of the hash table? */
    529 	if (pos->curr >= pos->num_buckets)
    530 	{
    531 	    /* yes: return NULL */
    532 	    return NULL;
    533 	}
    534 	/* no: regrab first item in current bucket list (might be NULL) */
    535 	li = LL_FIRST(&(pos->hash_bucket->list));
    536     }
    537     else
    538     {
    539 	/* get the next item in the llist */
    540 	li = LL_NEXT(&(pos->hash_bucket->list), pos->ll_item);
    541     }
    542 
    543     /* if its NULL we have to find another bucket */
    544     while (li == NULL)
    545     {
    546 	/* locate another bucket */
    547 	pos->ll_last = NULL;
    548 
    549 	/* move to the next one */
    550 	pos->hash_bucket++;
    551 	if (++pos->curr >= pos->num_buckets)
    552 	{
    553 	    /* at the end of the hash table */
    554 	    pos->ll_item = NULL;
    555 	    return NULL;
    556 	}
    557 
    558 	/* get the first element (might be NULL) */
    559 	li = LL_FIRST(&(pos->hash_bucket->list));
    560     }
    561 
    562     /* li is the next element to dish out */
    563     pos->ll_item = li;
    564     return (hash_item_uint *)li->datum;
    565 }
    566 
    567 /*
    568  * void *hash_remove_pos_uint(hash_pos *pos)
    569  *
    570  * Remove the hash table entry pointed to by position marker "pos".
    571  * The data from the entry is returned upon success, otherwise NULL.
    572  */
    573 
    574 
    575 void *
    576 hash_remove_pos_uint(hash_pos *pos)
    577 
    578 {
    579     llistitem *li;
    580     void *ans;
    581     hash_item_uint *hi;
    582 
    583     /* sanity checks */
    584     if (pos == NULL || pos->ll_last == pos->ll_item)
    585     {
    586 	return NULL;
    587     }
    588 
    589     /* at this point pos contains the item to remove (ll_item)
    590        and its predecesor (ll_last) */
    591     /* extract the item from the llist */
    592     li = pos->ll_item;
    593     ll_extract(&(pos->hash_bucket->list), li, pos->ll_last);
    594 
    595     /* retain the data */
    596     hi = (hash_item_uint *)li->datum;
    597     ans = hi->value;
    598 
    599     ll_freeitem(li);
    600 
    601     /* back up to previous item */
    602     /* its okay for ll_item to be null: hash_next will detect it */
    603     pos->ll_item = pos->ll_last;
    604 
    605     return ans;
    606 }
    607 
    608 
    609 
    610 /*
    611  * void hash_add_pid(hash_table *ht, pid_t key, void *value)
    612  *
    613  * Add an element to table "ht".  The element is described by
    614  * "key" and "value".  Return NULL on success.  If the key
    615  * already exists in the table, then no action is taken and
    616  * the data for the existing element is returned.
    617  * Key type is pid_t
    618  */
    619 
    620 void *
    621 hash_add_pid(hash_table *ht, pid_t key, void *value)
    622 
    623 {
    624     bucket_t *bucket;
    625     hash_item_pid *hi;
    626     hash_item_pid *h;
    627     llist *ll;
    628     llistitem *li;
    629     llistitem *newli;
    630     pid_t k1;
    631 
    632     /* allocate the space we will need */
    633     newli = ll_newitem(sizeof(hash_item_pid));
    634     hi = (hash_item_pid *)newli->datum;
    635 
    636     /* fill in the values */
    637     hi->key = key;
    638     hi->value = value;
    639 
    640     /* hash to the bucket */
    641     bucket = &(ht->buckets[(key % ht->num_buckets)]);
    642 
    643     /* walk the list to make sure we do not have a duplicate */
    644     ll = &(bucket->list);
    645     li = LL_FIRST(ll);
    646     while (li != NULL)
    647     {
    648 	h = (hash_item_pid *)li->datum;
    649 	k1 = h->key;
    650 	if (key == k1)
    651 	{
    652 	    /* found one */
    653 	    break;
    654 	}
    655 	li = LL_NEXT(ll, li);
    656     }
    657     li = NULL;
    658 
    659     /* is there already one there? */
    660     if (li == NULL)
    661     {
    662 	/* add the unique element to the buckets list */
    663 	ll_add(&(bucket->list), newli);
    664 	return NULL;
    665     }
    666     else
    667     {
    668 	/* free the stuff we just allocated */
    669 	ll_freeitem(newli);
    670 	return ((hash_item_pid *)(li->datum))->value;
    671     }
    672 }
    673 
    674 /*
    675  * void *hash_replace_pid(hash_table *ht, pid_t key, void *value)
    676  *
    677  * Replace an existing value in the hash table with a new one and
    678  * return the old value.  If the key does not already exist in
    679  * the hash table, add a new element and return NULL.
    680  * Key type is pid_t
    681  */
    682 
    683 void *
    684 hash_replace_pid(hash_table *ht, pid_t key, void *value)
    685 
    686 {
    687     bucket_t *bucket;
    688     hash_item_pid *hi;
    689     llist *ll;
    690     llistitem *li;
    691     void *result = NULL;
    692     pid_t k1;
    693 
    694     /* find the bucket */
    695     bucket = &(ht->buckets[(key % ht->num_buckets)]);
    696 
    697     /* walk the list until we find the existing item */
    698     ll = &(bucket->list);
    699     li = LL_FIRST(ll);
    700     while (li != NULL)
    701     {
    702 	hi = (hash_item_pid *)li->datum;
    703 	k1 = hi->key;
    704 	if (key == k1)
    705 	{
    706 	    /* found it: now replace the value with the new one */
    707 	    result = hi->value;
    708 	    hi->value = value;
    709 	    break;
    710 	}
    711 	li = LL_NEXT(ll, li);
    712     }
    713 
    714     /* if the element wasnt found, add it */
    715     if (result == NULL)
    716     {
    717 	li = ll_newitem(sizeof(hash_item_pid));
    718 	hi = (hash_item_pid *)li->datum;
    719 	hi->key = key;
    720 	hi->value = value;
    721 	ll_add(&(bucket->list), li);
    722     }
    723 
    724     /* return the old value (so it can be freed) */
    725     return result;
    726 }
    727 
    728 /*
    729  * void *hash_lookup_pid(hash_table *ht, pid_t key)
    730  *
    731  * Look up "key" in "ht" and return the associated value.  If "key"
    732  * is not found, return NULL.  Key type is pid_t
    733  */
    734 
    735 void *
    736 hash_lookup_pid(hash_table *ht, pid_t key)
    737 
    738 {
    739     bucket_t *bucket;
    740     llist *ll;
    741     llistitem *li;
    742     hash_item_pid *h;
    743     void *result;
    744     pid_t k1;
    745 
    746     result = NULL;
    747     if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
    748     {
    749 	ll = &(bucket->list);
    750 	li = LL_FIRST(ll);
    751 	while (li != NULL)
    752 	{
    753 	    h = (hash_item_pid *)li->datum;
    754 	    k1 = h->key;
    755 	    if (key == k1)
    756 	    {
    757 		result = h->value;
    758 		break;
    759 	    }
    760 	    li = LL_NEXT(ll, li);
    761 	}
    762     }
    763     return result;
    764 }
    765 
    766 /*
    767  * void *hash_remove_pid(hash_table *ht, pid_t key)
    768  *
    769  * Remove the element associated with "key" from the hash table
    770  * "ht".  Return the value or NULL if the key was not found.
    771  */
    772 
    773 void *
    774 hash_remove_pid(hash_table *ht, pid_t key)
    775 
    776 {
    777     bucket_t *bucket;
    778     llist *ll;
    779     llistitem *li;
    780     llistitem *lilast;
    781     hash_item_pid *hi;
    782     void *result;
    783     pid_t k1;
    784 
    785     result = NULL;
    786     if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
    787     {
    788 	ll = &(bucket->list);
    789 	li = LL_FIRST(ll);
    790 	lilast = NULL;
    791 	while (li != NULL)
    792 	{
    793 	    hi = (hash_item_pid *)li->datum;
    794 	    k1 = hi->key;
    795 	    if (key == k1)
    796 	    {
    797 		ll_extract(ll, li, lilast);
    798 		result = hi->value;
    799 		key = hi->key;
    800 		;
    801 		ll_freeitem(li);
    802 		break;
    803 	    }
    804 	    lilast = li;
    805 	    li = LL_NEXT(ll, li);
    806 	}
    807     }
    808     return result;
    809 }
    810 
    811 /*
    812  * hash_item_pid *hash_first_pid(hash_table *ht, hash_pos *pos)
    813  *
    814  * First function to call when iterating through all items in the hash
    815  * table.  Returns the first item in "ht" and initializes "*pos" to track
    816  * the current position.
    817  */
    818 
    819 hash_item_pid *
    820 hash_first_pid(hash_table *ht, hash_pos *pos)
    821 
    822 {
    823     /* initialize pos for first item in first bucket */
    824     pos->num_buckets = ht->num_buckets;
    825     pos->hash_bucket = ht->buckets;
    826     pos->curr = 0;
    827     pos->ll_last = NULL;
    828 
    829     /* find the first non-empty bucket */
    830     while(pos->hash_bucket->list.count == 0)
    831     {
    832 	pos->hash_bucket++;
    833 	if (++pos->curr >= pos->num_buckets)
    834 	{
    835 	    return NULL;
    836 	}
    837     }
    838 
    839     /* set and return the first item */
    840     pos->ll_item = LL_FIRST(&(pos->hash_bucket->list));
    841     return (hash_item_pid *)pos->ll_item->datum;
    842 }
    843 
    844 
    845 /*
    846  * hash_item_pid *hash_next_pid(hash_pos *pos)
    847  *
    848  * Return the next item in the hash table, using "pos" as a description
    849  * of the present position in the hash table.  "pos" also identifies the
    850  * specific hash table.  Return NULL if there are no more elements.
    851  */
    852 
    853 hash_item_pid *
    854 hash_next_pid(hash_pos *pos)
    855 
    856 {
    857     llistitem *li;
    858 
    859     /* move item to last and check for NULL */
    860     if ((pos->ll_last = pos->ll_item) == NULL)
    861     {
    862 	/* are we really at the end of the hash table? */
    863 	if (pos->curr >= pos->num_buckets)
    864 	{
    865 	    /* yes: return NULL */
    866 	    return NULL;
    867 	}
    868 	/* no: regrab first item in current bucket list (might be NULL) */
    869 	li = LL_FIRST(&(pos->hash_bucket->list));
    870     }
    871     else
    872     {
    873 	/* get the next item in the llist */
    874 	li = LL_NEXT(&(pos->hash_bucket->list), pos->ll_item);
    875     }
    876 
    877     /* if its NULL we have to find another bucket */
    878     while (li == NULL)
    879     {
    880 	/* locate another bucket */
    881 	pos->ll_last = NULL;
    882 
    883 	/* move to the next one */
    884 	pos->hash_bucket++;
    885 	if (++pos->curr >= pos->num_buckets)
    886 	{
    887 	    /* at the end of the hash table */
    888 	    pos->ll_item = NULL;
    889 	    return NULL;
    890 	}
    891 
    892 	/* get the first element (might be NULL) */
    893 	li = LL_FIRST(&(pos->hash_bucket->list));
    894     }
    895 
    896     /* li is the next element to dish out */
    897     pos->ll_item = li;
    898     return (hash_item_pid *)li->datum;
    899 }
    900 
    901 /*
    902  * void *hash_remove_pos_pid(hash_pos *pos)
    903  *
    904  * Remove the hash table entry pointed to by position marker "pos".
    905  * The data from the entry is returned upon success, otherwise NULL.
    906  */
    907 
    908 
    909 void *
    910 hash_remove_pos_pid(hash_pos *pos)
    911 
    912 {
    913     llistitem *li;
    914     void *ans;
    915     hash_item_pid *hi;
    916 
    917     /* sanity checks */
    918     if (pos == NULL || pos->ll_last == pos->ll_item)
    919     {
    920 	return NULL;
    921     }
    922 
    923     /* at this point pos contains the item to remove (ll_item)
    924        and its predecesor (ll_last) */
    925     /* extract the item from the llist */
    926     li = pos->ll_item;
    927     ll_extract(&(pos->hash_bucket->list), li, pos->ll_last);
    928 
    929     /* retain the data */
    930     hi = (hash_item_pid *)li->datum;
    931     ans = hi->value;
    932 
    933     /* free up the space */
    934     ll_freeitem(li);
    935 
    936     /* back up to previous item */
    937     /* its okay for ll_item to be null: hash_next will detect it */
    938     pos->ll_item = pos->ll_last;
    939 
    940     return ans;
    941 }
    942 
    943 
    944 
    945 /*
    946  * void hash_add_string(hash_table *ht, char * key, void *value)
    947  *
    948  * Add an element to table "ht".  The element is described by
    949  * "key" and "value".  Return NULL on success.  If the key
    950  * already exists in the table, then no action is taken and
    951  * the data for the existing element is returned.
    952  * Key type is char *
    953  */
    954 
    955 void *
    956 hash_add_string(hash_table *ht, char * key, void *value)
    957 
    958 {
    959     bucket_t *bucket;
    960     hash_item_string *hi;
    961     hash_item_string *h;
    962     llist *ll;
    963     llistitem *li;
    964     llistitem *newli;
    965     char * k1;
    966 
    967     /* allocate the space we will need */
    968     newli = ll_newitem(sizeof(hash_item_string));
    969     hi = (hash_item_string *)newli->datum;
    970 
    971     /* fill in the values */
    972     hi->key = estrdup(key);
    973     hi->value = value;
    974 
    975     /* hash to the bucket */
    976     bucket = &(ht->buckets[string_hash(ht, key)]);
    977 
    978     /* walk the list to make sure we do not have a duplicate */
    979     ll = &(bucket->list);
    980     li = LL_FIRST(ll);
    981     while (li != NULL)
    982     {
    983 	h = (hash_item_string *)li->datum;
    984 	k1 = h->key;
    985 	if (strcmp(key, k1) == 0)
    986 	{
    987 	    /* found one */
    988 	    break;
    989 	}
    990 	li = LL_NEXT(ll, li);
    991     }
    992     li = NULL;
    993 
    994     /* is there already one there? */
    995     if (li == NULL)
    996     {
    997 	/* add the unique element to the buckets list */
    998 	ll_add(&(bucket->list), newli);
    999 	return NULL;
   1000     }
   1001     else
   1002     {
   1003 	/* free the stuff we just allocated */
   1004 	ll_freeitem(newli);
   1005 	return ((hash_item_string *)(li->datum))->value;
   1006     }
   1007 }
   1008 
   1009 /*
   1010  * void *hash_replace_string(hash_table *ht, char * key, void *value)
   1011  *
   1012  * Replace an existing value in the hash table with a new one and
   1013  * return the old value.  If the key does not already exist in
   1014  * the hash table, add a new element and return NULL.
   1015  * Key type is char *
   1016  */
   1017 
   1018 void *
   1019 hash_replace_string(hash_table *ht, char * key, void *value)
   1020 
   1021 {
   1022     bucket_t *bucket;
   1023     hash_item_string *hi;
   1024     llist *ll;
   1025     llistitem *li;
   1026     void *result = NULL;
   1027     char * k1;
   1028 
   1029     /* find the bucket */
   1030     bucket = &(ht->buckets[string_hash(ht, key)]);
   1031 
   1032     /* walk the list until we find the existing item */
   1033     ll = &(bucket->list);
   1034     li = LL_FIRST(ll);
   1035     while (li != NULL)
   1036     {
   1037 	hi = (hash_item_string *)li->datum;
   1038 	k1 = hi->key;
   1039 	if (strcmp(key, k1) == 0)
   1040 	{
   1041 	    /* found it: now replace the value with the new one */
   1042 	    result = hi->value;
   1043 	    hi->value = value;
   1044 	    break;
   1045 	}
   1046 	li = LL_NEXT(ll, li);
   1047     }
   1048 
   1049     /* if the element wasnt found, add it */
   1050     if (result == NULL)
   1051     {
   1052 	li = ll_newitem(sizeof(hash_item_string));
   1053 	hi = (hash_item_string *)li->datum;
   1054 	hi->key = estrdup(key);
   1055 	hi->value = value;
   1056 	ll_add(&(bucket->list), li);
   1057     }
   1058 
   1059     /* return the old value (so it can be freed) */
   1060     return result;
   1061 }
   1062 
   1063 /*
   1064  * void *hash_lookup_string(hash_table *ht, char * key)
   1065  *
   1066  * Look up "key" in "ht" and return the associated value.  If "key"
   1067  * is not found, return NULL.  Key type is char *
   1068  */
   1069 
   1070 void *
   1071 hash_lookup_string(hash_table *ht, char * key)
   1072 
   1073 {
   1074     bucket_t *bucket;
   1075     llist *ll;
   1076     llistitem *li;
   1077     hash_item_string *h;
   1078     void *result;
   1079     char * k1;
   1080 
   1081     result = NULL;
   1082     if ((bucket = &(ht->buckets[string_hash(ht, key)])) != NULL)
   1083     {
   1084 	ll = &(bucket->list);
   1085 	li = LL_FIRST(ll);
   1086 	while (li != NULL)
   1087 	{
   1088 	    h = (hash_item_string *)li->datum;
   1089 	    k1 = h->key;
   1090 	    if (strcmp(key, k1) == 0)
   1091 	    {
   1092 		result = h->value;
   1093 		break;
   1094 	    }
   1095 	    li = LL_NEXT(ll, li);
   1096 	}
   1097     }
   1098     return result;
   1099 }
   1100 
   1101 /*
   1102  * void *hash_remove_string(hash_table *ht, char * key)
   1103  *
   1104  * Remove the element associated with "key" from the hash table
   1105  * "ht".  Return the value or NULL if the key was not found.
   1106  */
   1107 
   1108 void *
   1109 hash_remove_string(hash_table *ht, char * key)
   1110 
   1111 {
   1112     bucket_t *bucket;
   1113     llist *ll;
   1114     llistitem *li;
   1115     llistitem *lilast;
   1116     hash_item_string *hi;
   1117     void *result;
   1118     char * k1;
   1119 
   1120     result = NULL;
   1121     if ((bucket = &(ht->buckets[string_hash(ht, key)])) != NULL)
   1122     {
   1123 	ll = &(bucket->list);
   1124 	li = LL_FIRST(ll);
   1125 	lilast = NULL;
   1126 	while (li != NULL)
   1127 	{
   1128 	    hi = (hash_item_string *)li->datum;
   1129 	    k1 = hi->key;
   1130 	    if (strcmp(key, k1) == 0)
   1131 	    {
   1132 		ll_extract(ll, li, lilast);
   1133 		result = hi->value;
   1134 		key = hi->key;
   1135 		free(key);
   1136 		ll_freeitem(li);
   1137 		break;
   1138 	    }
   1139 	    lilast = li;
   1140 	    li = LL_NEXT(ll, li);
   1141 	}
   1142     }
   1143     return result;
   1144 }
   1145 
   1146 /*
   1147  * hash_item_string *hash_first_string(hash_table *ht, hash_pos *pos)
   1148  *
   1149  * First function to call when iterating through all items in the hash
   1150  * table.  Returns the first item in "ht" and initializes "*pos" to track
   1151  * the current position.
   1152  */
   1153 
   1154 hash_item_string *
   1155 hash_first_string(hash_table *ht, hash_pos *pos)
   1156 
   1157 {
   1158     /* initialize pos for first item in first bucket */
   1159     pos->num_buckets = ht->num_buckets;
   1160     pos->hash_bucket = ht->buckets;
   1161     pos->curr = 0;
   1162     pos->ll_last = NULL;
   1163 
   1164     /* find the first non-empty bucket */
   1165     while(pos->hash_bucket->list.count == 0)
   1166     {
   1167 	pos->hash_bucket++;
   1168 	if (++pos->curr >= pos->num_buckets)
   1169 	{
   1170 	    return NULL;
   1171 	}
   1172     }
   1173 
   1174     /* set and return the first item */
   1175     pos->ll_item = LL_FIRST(&(pos->hash_bucket->list));
   1176     return (hash_item_string *)pos->ll_item->datum;
   1177 }
   1178 
   1179 
   1180 /*
   1181  * hash_item_string *hash_next_string(hash_pos *pos)
   1182  *
   1183  * Return the next item in the hash table, using "pos" as a description
   1184  * of the present position in the hash table.  "pos" also identifies the
   1185  * specific hash table.  Return NULL if there are no more elements.
   1186  */
   1187 
   1188 hash_item_string *
   1189 hash_next_string(hash_pos *pos)
   1190 
   1191 {
   1192     llistitem *li;
   1193 
   1194     /* move item to last and check for NULL */
   1195     if ((pos->ll_last = pos->ll_item) == NULL)
   1196     {
   1197 	/* are we really at the end of the hash table? */
   1198 	if (pos->curr >= pos->num_buckets)
   1199 	{
   1200 	    /* yes: return NULL */
   1201 	    return NULL;
   1202 	}
   1203 	/* no: regrab first item in current bucket list (might be NULL) */
   1204 	li = LL_FIRST(&(pos->hash_bucket->list));
   1205     }
   1206     else
   1207     {
   1208 	/* get the next item in the llist */
   1209 	li = LL_NEXT(&(pos->hash_bucket->list), pos->ll_item);
   1210     }
   1211 
   1212     /* if its NULL we have to find another bucket */
   1213     while (li == NULL)
   1214     {
   1215 	/* locate another bucket */
   1216 	pos->ll_last = NULL;
   1217 
   1218 	/* move to the next one */
   1219 	pos->hash_bucket++;
   1220 	if (++pos->curr >= pos->num_buckets)
   1221 	{
   1222 	    /* at the end of the hash table */
   1223 	    pos->ll_item = NULL;
   1224 	    return NULL;
   1225 	}
   1226 
   1227 	/* get the first element (might be NULL) */
   1228 	li = LL_FIRST(&(pos->hash_bucket->list));
   1229     }
   1230 
   1231     /* li is the next element to dish out */
   1232     pos->ll_item = li;
   1233     return (hash_item_string *)li->datum;
   1234 }
   1235 
   1236 /*
   1237  * void *hash_remove_pos_string(hash_pos *pos)
   1238  *
   1239  * Remove the hash table entry pointed to by position marker "pos".
   1240  * The data from the entry is returned upon success, otherwise NULL.
   1241  */
   1242 
   1243 
   1244 void *
   1245 hash_remove_pos_string(hash_pos *pos)
   1246 
   1247 {
   1248     llistitem *li;
   1249     void *ans;
   1250     hash_item_string *hi;
   1251     char * key;
   1252 
   1253     /* sanity checks */
   1254     if (pos == NULL || pos->ll_last == pos->ll_item)
   1255     {
   1256 	return NULL;
   1257     }
   1258 
   1259     /* at this point pos contains the item to remove (ll_item)
   1260        and its predecesor (ll_last) */
   1261     /* extract the item from the llist */
   1262     li = pos->ll_item;
   1263     ll_extract(&(pos->hash_bucket->list), li, pos->ll_last);
   1264 
   1265     /* retain the data */
   1266     hi = (hash_item_string *)li->datum;
   1267     ans = hi->value;
   1268 
   1269     /* free up the space */
   1270     key = hi->key;
   1271     free(key);
   1272     ll_freeitem(li);
   1273 
   1274     /* back up to previous item */
   1275     /* its okay for ll_item to be null: hash_next will detect it */
   1276     pos->ll_item = pos->ll_last;
   1277 
   1278     return ans;
   1279 }
   1280 
   1281 
   1282 
   1283 /*
   1284  * void hash_add_pidthr(hash_table *ht, pidthr_t key, void *value)
   1285  *
   1286  * Add an element to table "ht".  The element is described by
   1287  * "key" and "value".  Return NULL on success.  If the key
   1288  * already exists in the table, then no action is taken and
   1289  * the data for the existing element is returned.
   1290  * Key type is pidthr_t
   1291  */
   1292 
   1293 void *
   1294 hash_add_pidthr(hash_table *ht, pidthr_t key, void *value)
   1295 
   1296 {
   1297     bucket_t *bucket;
   1298     hash_item_pidthr *hi;
   1299     hash_item_pidthr *h;
   1300     llist *ll;
   1301     llistitem *li;
   1302     llistitem *newli;
   1303     pidthr_t k1;
   1304 
   1305     /* allocate the space we will need */
   1306     newli = ll_newitem(sizeof(hash_item_pidthr));
   1307     hi = (hash_item_pidthr *)newli->datum;
   1308 
   1309     /* fill in the values */
   1310     hi->key = key;
   1311     hi->value = value;
   1312 
   1313     /* hash to the bucket */
   1314     bucket = &(ht->buckets[((key.k_thr * 10000 + key.k_pid) % ht->num_buckets)]);
   1315 
   1316     /* walk the list to make sure we do not have a duplicate */
   1317     ll = &(bucket->list);
   1318     li = LL_FIRST(ll);
   1319     while (li != NULL)
   1320     {
   1321 	h = (hash_item_pidthr *)li->datum;
   1322 	k1 = h->key;
   1323 	if ((key.k_pid == k1.k_pid && key.k_thr == k1.k_thr))
   1324 	{
   1325 	    /* found one */
   1326 	    break;
   1327 	}
   1328 	li = LL_NEXT(ll, li);
   1329     }
   1330     li = NULL;
   1331 
   1332     /* is there already one there? */
   1333     if (li == NULL)
   1334     {
   1335 	/* add the unique element to the buckets list */
   1336 	ll_add(&(bucket->list), newli);
   1337 	return NULL;
   1338     }
   1339     else
   1340     {
   1341 	/* free the stuff we just allocated */
   1342 	ll_freeitem(newli);
   1343 	return ((hash_item_pidthr *)(li->datum))->value;
   1344     }
   1345 }
   1346 
   1347 /*
   1348  * void *hash_replace_pidthr(hash_table *ht, pidthr_t key, void *value)
   1349  *
   1350  * Replace an existing value in the hash table with a new one and
   1351  * return the old value.  If the key does not already exist in
   1352  * the hash table, add a new element and return NULL.
   1353  * Key type is pidthr_t
   1354  */
   1355 
   1356 void *
   1357 hash_replace_pidthr(hash_table *ht, pidthr_t key, void *value)
   1358 
   1359 {
   1360     bucket_t *bucket;
   1361     hash_item_pidthr *hi;
   1362     llist *ll;
   1363     llistitem *li;
   1364     void *result = NULL;
   1365     pidthr_t k1;
   1366 
   1367     /* find the bucket */
   1368     bucket = &(ht->buckets[((key.k_thr * 10000 + key.k_pid) % ht->num_buckets)]);
   1369 
   1370     /* walk the list until we find the existing item */
   1371     ll = &(bucket->list);
   1372     li = LL_FIRST(ll);
   1373     while (li != NULL)
   1374     {
   1375 	hi = (hash_item_pidthr *)li->datum;
   1376 	k1 = hi->key;
   1377 	if ((key.k_pid == k1.k_pid && key.k_thr == k1.k_thr))
   1378 	{
   1379 	    /* found it: now replace the value with the new one */
   1380 	    result = hi->value;
   1381 	    hi->value = value;
   1382 	    break;
   1383 	}
   1384 	li = LL_NEXT(ll, li);
   1385     }
   1386 
   1387     /* if the element wasnt found, add it */
   1388     if (result == NULL)
   1389     {
   1390 	li = ll_newitem(sizeof(hash_item_pidthr));
   1391 	hi = (hash_item_pidthr *)li->datum;
   1392 	hi->key = key;
   1393 	hi->value = value;
   1394 	ll_add(&(bucket->list), li);
   1395     }
   1396 
   1397     /* return the old value (so it can be freed) */
   1398     return result;
   1399 }
   1400 
   1401 /*
   1402  * void *hash_lookup_pidthr(hash_table *ht, pidthr_t key)
   1403  *
   1404  * Look up "key" in "ht" and return the associated value.  If "key"
   1405  * is not found, return NULL.  Key type is pidthr_t
   1406  */
   1407 
   1408 void *
   1409 hash_lookup_pidthr(hash_table *ht, pidthr_t key)
   1410 
   1411 {
   1412     bucket_t *bucket;
   1413     llist *ll;
   1414     llistitem *li;
   1415     hash_item_pidthr *h;
   1416     void *result;
   1417     pidthr_t k1;
   1418 
   1419     result = NULL;
   1420     if ((bucket = &(ht->buckets[((key.k_thr * 10000 + key.k_pid) % ht->num_buckets)])) != NULL)
   1421     {
   1422 	ll = &(bucket->list);
   1423 	li = LL_FIRST(ll);
   1424 	while (li != NULL)
   1425 	{
   1426 	    h = (hash_item_pidthr *)li->datum;
   1427 	    k1 = h->key;
   1428 	    if ((key.k_pid == k1.k_pid && key.k_thr == k1.k_thr))
   1429 	    {
   1430 		result = h->value;
   1431 		break;
   1432 	    }
   1433 	    li = LL_NEXT(ll, li);
   1434 	}
   1435     }
   1436     return result;
   1437 }
   1438 
   1439 /*
   1440  * void *hash_remove_pidthr(hash_table *ht, pidthr_t key)
   1441  *
   1442  * Remove the element associated with "key" from the hash table
   1443  * "ht".  Return the value or NULL if the key was not found.
   1444  */
   1445 
   1446 void *
   1447 hash_remove_pidthr(hash_table *ht, pidthr_t key)
   1448 
   1449 {
   1450     bucket_t *bucket;
   1451     llist *ll;
   1452     llistitem *li;
   1453     llistitem *lilast;
   1454     hash_item_pidthr *hi;
   1455     void *result;
   1456     pidthr_t k1;
   1457 
   1458     result = NULL;
   1459     if ((bucket = &(ht->buckets[((key.k_thr * 10000 + key.k_pid) % ht->num_buckets)])) != NULL)
   1460     {
   1461 	ll = &(bucket->list);
   1462 	li = LL_FIRST(ll);
   1463 	lilast = NULL;
   1464 	while (li != NULL)
   1465 	{
   1466 	    hi = (hash_item_pidthr *)li->datum;
   1467 	    k1 = hi->key;
   1468 	    if ((key.k_pid == k1.k_pid && key.k_thr == k1.k_thr))
   1469 	    {
   1470 		ll_extract(ll, li, lilast);
   1471 		result = hi->value;
   1472 		key = hi->key;
   1473 		;
   1474 		ll_freeitem(li);
   1475 		break;
   1476 	    }
   1477 	    lilast = li;
   1478 	    li = LL_NEXT(ll, li);
   1479 	}
   1480     }
   1481     return result;
   1482 }
   1483 
   1484 /*
   1485  * hash_item_pidthr *hash_first_pidthr(hash_table *ht, hash_pos *pos)
   1486  *
   1487  * First function to call when iterating through all items in the hash
   1488  * table.  Returns the first item in "ht" and initializes "*pos" to track
   1489  * the current position.
   1490  */
   1491 
   1492 hash_item_pidthr *
   1493 hash_first_pidthr(hash_table *ht, hash_pos *pos)
   1494 
   1495 {
   1496     /* initialize pos for first item in first bucket */
   1497     pos->num_buckets = ht->num_buckets;
   1498     pos->hash_bucket = ht->buckets;
   1499     pos->curr = 0;
   1500     pos->ll_last = NULL;
   1501 
   1502     /* find the first non-empty bucket */
   1503     while(pos->hash_bucket->list.count == 0)
   1504     {
   1505 	pos->hash_bucket++;
   1506 	if (++pos->curr >= pos->num_buckets)
   1507 	{
   1508 	    return NULL;
   1509 	}
   1510     }
   1511 
   1512     /* set and return the first item */
   1513     pos->ll_item = LL_FIRST(&(pos->hash_bucket->list));
   1514     return (hash_item_pidthr *)pos->ll_item->datum;
   1515 }
   1516 
   1517 
   1518 /*
   1519  * hash_item_pidthr *hash_next_pidthr(hash_pos *pos)
   1520  *
   1521  * Return the next item in the hash table, using "pos" as a description
   1522  * of the present position in the hash table.  "pos" also identifies the
   1523  * specific hash table.  Return NULL if there are no more elements.
   1524  */
   1525 
   1526 hash_item_pidthr *
   1527 hash_next_pidthr(hash_pos *pos)
   1528 
   1529 {
   1530     llistitem *li;
   1531 
   1532     /* move item to last and check for NULL */
   1533     if ((pos->ll_last = pos->ll_item) == NULL)
   1534     {
   1535 	/* are we really at the end of the hash table? */
   1536 	if (pos->curr >= pos->num_buckets)
   1537 	{
   1538 	    /* yes: return NULL */
   1539 	    return NULL;
   1540 	}
   1541 	/* no: regrab first item in current bucket list (might be NULL) */
   1542 	li = LL_FIRST(&(pos->hash_bucket->list));
   1543     }
   1544     else
   1545     {
   1546 	/* get the next item in the llist */
   1547 	li = LL_NEXT(&(pos->hash_bucket->list), pos->ll_item);
   1548     }
   1549 
   1550     /* if its NULL we have to find another bucket */
   1551     while (li == NULL)
   1552     {
   1553 	/* locate another bucket */
   1554 	pos->ll_last = NULL;
   1555 
   1556 	/* move to the next one */
   1557 	pos->hash_bucket++;
   1558 	if (++pos->curr >= pos->num_buckets)
   1559 	{
   1560 	    /* at the end of the hash table */
   1561 	    pos->ll_item = NULL;
   1562 	    return NULL;
   1563 	}
   1564 
   1565 	/* get the first element (might be NULL) */
   1566 	li = LL_FIRST(&(pos->hash_bucket->list));
   1567     }
   1568 
   1569     /* li is the next element to dish out */
   1570     pos->ll_item = li;
   1571     return (hash_item_pidthr *)li->datum;
   1572 }
   1573 
   1574 /*
   1575  * void *hash_remove_pos_pidthr(hash_pos *pos)
   1576  *
   1577  * Remove the hash table entry pointed to by position marker "pos".
   1578  * The data from the entry is returned upon success, otherwise NULL.
   1579  */
   1580 
   1581 
   1582 void *
   1583 hash_remove_pos_pidthr(hash_pos *pos)
   1584 
   1585 {
   1586     llistitem *li;
   1587     void *ans;
   1588     hash_item_pidthr *hi;
   1589 
   1590     /* sanity checks */
   1591     if (pos == NULL || pos->ll_last == pos->ll_item)
   1592     {
   1593 	return NULL;
   1594     }
   1595 
   1596     /* at this point pos contains the item to remove (ll_item)
   1597        and its predecesor (ll_last) */
   1598     /* extract the item from the llist */
   1599     li = pos->ll_item;
   1600     ll_extract(&(pos->hash_bucket->list), li, pos->ll_last);
   1601 
   1602     /* retain the data */
   1603     hi = (hash_item_pidthr *)li->datum;
   1604     ans = hi->value;
   1605 
   1606     /* free up the space */
   1607     ll_freeitem(li);
   1608 
   1609     /* back up to previous item */
   1610     /* its okay for ll_item to be null: hash_next will detect it */
   1611     pos->ll_item = pos->ll_last;
   1612 
   1613     return ans;
   1614 }
   1615 
   1616 #if HAVE_LWPID_T
   1617 
   1618 
   1619 /*
   1620  * void hash_add_lwpid(hash_table *ht, lwpid_t key, void *value)
   1621  *
   1622  * Add an element to table "ht".  The element is described by
   1623  * "key" and "value".  Return NULL on success.  If the key
   1624  * already exists in the table, then no action is taken and
   1625  * the data for the existing element is returned.
   1626  * Key type is lwpid_t
   1627  */
   1628 
   1629 void *
   1630 hash_add_lwpid(hash_table *ht, lwpid_t key, void *value)
   1631 
   1632 {
   1633     bucket_t *bucket;
   1634     hash_item_lwpid *hi;
   1635     hash_item_lwpid *h;
   1636     llist *ll;
   1637     llistitem *li;
   1638     llistitem *newli;
   1639     lwpid_t k1;
   1640 
   1641     /* allocate the space we will need */
   1642     newli = ll_newitem(sizeof(hash_item_lwpid));
   1643     hi = (hash_item_lwpid *)newli->datum;
   1644 
   1645     /* fill in the values */
   1646     hi->key = key;
   1647     hi->value = value;
   1648 
   1649     /* hash to the bucket */
   1650     bucket = &(ht->buckets[(key % ht->num_buckets)]);
   1651 
   1652     /* walk the list to make sure we do not have a duplicate */
   1653     ll = &(bucket->list);
   1654     li = LL_FIRST(ll);
   1655     while (li != NULL)
   1656     {
   1657 	h = (hash_item_lwpid *)li->datum;
   1658 	k1 = h->key;
   1659 	if (key == k1)
   1660 	{
   1661 	    /* found one */
   1662 	    break;
   1663 	}
   1664 	li = LL_NEXT(ll, li);
   1665     }
   1666     li = NULL;
   1667 
   1668     /* is there already one there? */
   1669     if (li == NULL)
   1670     {
   1671 	/* add the unique element to the buckets list */
   1672 	ll_add(&(bucket->list), newli);
   1673 	return NULL;
   1674     }
   1675     else
   1676     {
   1677 	/* free the stuff we just allocated */
   1678 	ll_freeitem(newli);
   1679 	return ((hash_item_lwpid *)(li->datum))->value;
   1680     }
   1681 }
   1682 
   1683 /*
   1684  * void *hash_replace_lwpid(hash_table *ht, lwpid_t key, void *value)
   1685  *
   1686  * Replace an existing value in the hash table with a new one and
   1687  * return the old value.  If the key does not already exist in
   1688  * the hash table, add a new element and return NULL.
   1689  * Key type is lwpid_t
   1690  */
   1691 
   1692 void *
   1693 hash_replace_lwpid(hash_table *ht, lwpid_t key, void *value)
   1694 
   1695 {
   1696     bucket_t *bucket;
   1697     hash_item_lwpid *hi;
   1698     llist *ll;
   1699     llistitem *li;
   1700     void *result = NULL;
   1701     lwpid_t k1;
   1702 
   1703     /* find the bucket */
   1704     bucket = &(ht->buckets[(key % ht->num_buckets)]);
   1705 
   1706     /* walk the list until we find the existing item */
   1707     ll = &(bucket->list);
   1708     li = LL_FIRST(ll);
   1709     while (li != NULL)
   1710     {
   1711 	hi = (hash_item_lwpid *)li->datum;
   1712 	k1 = hi->key;
   1713 	if (key == k1)
   1714 	{
   1715 	    /* found it: now replace the value with the new one */
   1716 	    result = hi->value;
   1717 	    hi->value = value;
   1718 	    break;
   1719 	}
   1720 	li = LL_NEXT(ll, li);
   1721     }
   1722 
   1723     /* if the element wasnt found, add it */
   1724     if (result == NULL)
   1725     {
   1726 	li = ll_newitem(sizeof(hash_item_lwpid));
   1727 	hi = (hash_item_lwpid *)li->datum;
   1728 	hi->key = key;
   1729 	hi->value = value;
   1730 	ll_add(&(bucket->list), li);
   1731     }
   1732 
   1733     /* return the old value (so it can be freed) */
   1734     return result;
   1735 }
   1736 
   1737 /*
   1738  * void *hash_lookup_lwpid(hash_table *ht, lwpid_t key)
   1739  *
   1740  * Look up "key" in "ht" and return the associated value.  If "key"
   1741  * is not found, return NULL.  Key type is lwpid_t
   1742  */
   1743 
   1744 void *
   1745 hash_lookup_lwpid(hash_table *ht, lwpid_t key)
   1746 
   1747 {
   1748     bucket_t *bucket;
   1749     llist *ll;
   1750     llistitem *li;
   1751     hash_item_lwpid *h;
   1752     void *result;
   1753     lwpid_t k1;
   1754 
   1755     result = NULL;
   1756     if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
   1757     {
   1758 	ll = &(bucket->list);
   1759 	li = LL_FIRST(ll);
   1760 	while (li != NULL)
   1761 	{
   1762 	    h = (hash_item_lwpid *)li->datum;
   1763 	    k1 = h->key;
   1764 	    if (key == k1)
   1765 	    {
   1766 		result = h->value;
   1767 		break;
   1768 	    }
   1769 	    li = LL_NEXT(ll, li);
   1770 	}
   1771     }
   1772     return result;
   1773 }
   1774 
   1775 /*
   1776  * void *hash_remove_lwpid(hash_table *ht, lwpid_t key)
   1777  *
   1778  * Remove the element associated with "key" from the hash table
   1779  * "ht".  Return the value or NULL if the key was not found.
   1780  */
   1781 
   1782 void *
   1783 hash_remove_lwpid(hash_table *ht, lwpid_t key)
   1784 
   1785 {
   1786     bucket_t *bucket;
   1787     llist *ll;
   1788     llistitem *li;
   1789     llistitem *lilast;
   1790     hash_item_lwpid *hi;
   1791     void *result;
   1792     lwpid_t k1;
   1793 
   1794     result = NULL;
   1795     if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
   1796     {
   1797 	ll = &(bucket->list);
   1798 	li = LL_FIRST(ll);
   1799 	lilast = NULL;
   1800 	while (li != NULL)
   1801 	{
   1802 	    hi = (hash_item_lwpid *)li->datum;
   1803 	    k1 = hi->key;
   1804 	    if (key == k1)
   1805 	    {
   1806 		ll_extract(ll, li, lilast);
   1807 		result = hi->value;
   1808 		key = hi->key;
   1809 		;
   1810 		ll_freeitem(li);
   1811 		break;
   1812 	    }
   1813 	    lilast = li;
   1814 	    li = LL_NEXT(ll, li);
   1815 	}
   1816     }
   1817     return result;
   1818 }
   1819 
   1820 /*
   1821  * hash_item_lwpid *hash_first_lwpid(hash_table *ht, hash_pos *pos)
   1822  *
   1823  * First function to call when iterating through all items in the hash
   1824  * table.  Returns the first item in "ht" and initializes "*pos" to track
   1825  * the current position.
   1826  */
   1827 
   1828 hash_item_lwpid *
   1829 hash_first_lwpid(hash_table *ht, hash_pos *pos)
   1830 
   1831 {
   1832     /* initialize pos for first item in first bucket */
   1833     pos->num_buckets = ht->num_buckets;
   1834     pos->hash_bucket = ht->buckets;
   1835     pos->curr = 0;
   1836     pos->ll_last = NULL;
   1837 
   1838     /* find the first non-empty bucket */
   1839     while(pos->hash_bucket->list.count == 0)
   1840     {
   1841 	pos->hash_bucket++;
   1842 	if (++pos->curr >= pos->num_buckets)
   1843 	{
   1844 	    return NULL;
   1845 	}
   1846     }
   1847 
   1848     /* set and return the first item */
   1849     pos->ll_item = LL_FIRST(&(pos->hash_bucket->list));
   1850     return (hash_item_lwpid *)pos->ll_item->datum;
   1851 }
   1852 
   1853 
   1854 /*
   1855  * hash_item_lwpid *hash_next_lwpid(hash_pos *pos)
   1856  *
   1857  * Return the next item in the hash table, using "pos" as a description
   1858  * of the present position in the hash table.  "pos" also identifies the
   1859  * specific hash table.  Return NULL if there are no more elements.
   1860  */
   1861 
   1862 hash_item_lwpid *
   1863 hash_next_lwpid(hash_pos *pos)
   1864 
   1865 {
   1866     llistitem *li;
   1867 
   1868     /* move item to last and check for NULL */
   1869     if ((pos->ll_last = pos->ll_item) == NULL)
   1870     {
   1871 	/* are we really at the end of the hash table? */
   1872 	if (pos->curr >= pos->num_buckets)
   1873 	{
   1874 	    /* yes: return NULL */
   1875 	    return NULL;
   1876 	}
   1877 	/* no: regrab first item in current bucket list (might be NULL) */
   1878 	li = LL_FIRST(&(pos->hash_bucket->list));
   1879     }
   1880     else
   1881     {
   1882 	/* get the next item in the llist */
   1883 	li = LL_NEXT(&(pos->hash_bucket->list), pos->ll_item);
   1884     }
   1885 
   1886     /* if its NULL we have to find another bucket */
   1887     while (li == NULL)
   1888     {
   1889 	/* locate another bucket */
   1890 	pos->ll_last = NULL;
   1891 
   1892 	/* move to the next one */
   1893 	pos->hash_bucket++;
   1894 	if (++pos->curr >= pos->num_buckets)
   1895 	{
   1896 	    /* at the end of the hash table */
   1897 	    pos->ll_item = NULL;
   1898 	    return NULL;
   1899 	}
   1900 
   1901 	/* get the first element (might be NULL) */
   1902 	li = LL_FIRST(&(pos->hash_bucket->list));
   1903     }
   1904 
   1905     /* li is the next element to dish out */
   1906     pos->ll_item = li;
   1907     return (hash_item_lwpid *)li->datum;
   1908 }
   1909 
   1910 /*
   1911  * void *hash_remove_pos_lwpid(hash_pos *pos)
   1912  *
   1913  * Remove the hash table entry pointed to by position marker "pos".
   1914  * The data from the entry is returned upon success, otherwise NULL.
   1915  */
   1916 
   1917 
   1918 void *
   1919 hash_remove_pos_lwpid(hash_pos *pos)
   1920 
   1921 {
   1922     llistitem *li;
   1923     void *ans;
   1924     hash_item_lwpid *hi;
   1925 
   1926     /* sanity checks */
   1927     if (pos == NULL || pos->ll_last == pos->ll_item)
   1928     {
   1929 	return NULL;
   1930     }
   1931 
   1932     /* at this point pos contains the item to remove (ll_item)
   1933        and its predecesor (ll_last) */
   1934     /* extract the item from the llist */
   1935     li = pos->ll_item;
   1936     ll_extract(&(pos->hash_bucket->list), li, pos->ll_last);
   1937 
   1938     /* retain the data */
   1939     hi = (hash_item_lwpid *)li->datum;
   1940     ans = hi->value;
   1941 
   1942     /* free up the space */
   1943     ll_freeitem(li);
   1944 
   1945     /* back up to previous item */
   1946     /* its okay for ll_item to be null: hash_next will detect it */
   1947     pos->ll_item = pos->ll_last;
   1948 
   1949     return ans;
   1950 }
   1951 
   1952 #endif
   1953