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