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