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
next_prime(int x)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
string_hash(hash_table * ht,char * key)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 
ll_init(llist * q)107 static void ll_init(llist *q)
108 
109 {
110     q->head = NULL;
111     q->count = 0;
112 }
113 
ll_newitem(int size)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 
ll_freeitem(llistitem * li)124 static void ll_freeitem(llistitem *li)
125 
126 {
127     free(li);
128 }
129 
ll_add(llist * q,llistitem * new)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 
ll_extract(llist * q,llistitem * qi,llistitem * last)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 *
ll_first(llist * q)159 ll_first(llist *q)
160 
161 {
162     return q->head;
163 }
164 
165 static llistitem *
ll_next(llist * q,llistitem * qi)166 ll_next(llist *q, llistitem *qi)
167 
168 {
169     return (qi != NULL ? qi->next : NULL);
170 }
171 
172 static int
ll_isempty(llist * ll)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 *
hash_create(int num)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
hash_count(hash_table * ht)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
hash_sizeinfo(unsigned int * sizes,int max,hash_table * ht)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 *
hash_add_uint(hash_table * ht,unsigned int key,void * value)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 *
hash_replace_uint(hash_table * ht,unsigned int key,void * value)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 *
hash_lookup_uint(hash_table * ht,unsigned int key)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 *
hash_remove_uint(hash_table * ht,unsigned int key)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 *
hash_first_uint(hash_table * ht,hash_pos * pos)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 *
hash_next_uint(hash_pos * pos)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 *
hash_remove_pos_uint(hash_pos * pos)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 *
hash_add_pid(hash_table * ht,pid_t key,void * value)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 *
hash_replace_pid(hash_table * ht,pid_t key,void * value)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 *
hash_lookup_pid(hash_table * ht,pid_t key)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 *
hash_remove_pid(hash_table * ht,pid_t key)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 *
hash_first_pid(hash_table * ht,hash_pos * pos)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 *
hash_next_pid(hash_pos * pos)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 *
hash_remove_pos_pid(hash_pos * pos)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 *
hash_add_string(hash_table * ht,char * key,void * value)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 *
hash_replace_string(hash_table * ht,char * key,void * value)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 *
hash_lookup_string(hash_table * ht,char * key)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 *
hash_remove_string(hash_table * ht,char * key)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 *
hash_first_string(hash_table * ht,hash_pos * pos)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 *
hash_next_string(hash_pos * pos)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 *
hash_remove_pos_string(hash_pos * pos)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 *
hash_add_pidthr(hash_table * ht,pidthr_t key,void * value)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 *
hash_replace_pidthr(hash_table * ht,pidthr_t key,void * value)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 *
hash_lookup_pidthr(hash_table * ht,pidthr_t key)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 *
hash_remove_pidthr(hash_table * ht,pidthr_t key)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 *
hash_first_pidthr(hash_table * ht,hash_pos * pos)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 *
hash_next_pidthr(hash_pos * pos)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 *
hash_remove_pos_pidthr(hash_pos * pos)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 *
hash_add_lwpid(hash_table * ht,lwpid_t key,void * value)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 *
hash_replace_lwpid(hash_table * ht,lwpid_t key,void * value)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 *
hash_lookup_lwpid(hash_table * ht,lwpid_t key)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 *
hash_remove_lwpid(hash_table * ht,lwpid_t key)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 *
hash_first_lwpid(hash_table * ht,hash_pos * pos)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 *
hash_next_lwpid(hash_pos * pos)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 *
hash_remove_pos_lwpid(hash_pos * pos)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