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