intmap.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <auth.h>
  12. #include <fcall.h>
  13. #include <thread.h>
  14. #include <9p.h>
  15. enum {
  16. NHASH = 128
  17. };
  18. typedef struct Intlist Intlist;
  19. struct Intlist
  20. {
  21. uint32_t id;
  22. void* aux;
  23. Intlist* link;
  24. };
  25. struct Intmap
  26. {
  27. RWLock RWLock;
  28. Intlist* hash[NHASH];
  29. void (*inc)(void*);
  30. };
  31. static uint32_t
  32. hashid(uint32_t id)
  33. {
  34. return id%NHASH;
  35. }
  36. static void
  37. nop(void* v)
  38. {
  39. }
  40. Intmap*
  41. allocmap(void (*inc)(void*))
  42. {
  43. Intmap *m;
  44. m = emalloc9p(sizeof(*m));
  45. if(inc == nil)
  46. inc = nop;
  47. m->inc = inc;
  48. return m;
  49. }
  50. void
  51. freemap(Intmap *map, void (*destroy)(void*))
  52. {
  53. int i;
  54. Intlist *p, *nlink;
  55. if(destroy == nil)
  56. destroy = nop;
  57. for(i=0; i<NHASH; i++){
  58. for(p=map->hash[i]; p; p=nlink){
  59. nlink = p->link;
  60. destroy(p->aux);
  61. free(p);
  62. }
  63. }
  64. free(map);
  65. }
  66. static Intlist**
  67. llookup(Intmap *map, uint32_t id)
  68. {
  69. Intlist **lf;
  70. for(lf=&map->hash[hashid(id)]; *lf; lf=&(*lf)->link)
  71. if((*lf)->id == id)
  72. break;
  73. return lf;
  74. }
  75. /*
  76. * The RWlock is used as expected except that we allow
  77. * inc() to be called while holding it. This is because we're
  78. * locking changes to the tree structure, not to the references.
  79. * Inc() is expected to have its own locking.
  80. */
  81. void*
  82. lookupkey(Intmap *map, uint32_t id)
  83. {
  84. Intlist *f;
  85. void *v;
  86. rlock(&map->RWLock);
  87. if((f = *llookup(map, id)) != nil){
  88. v = f->aux;
  89. map->inc(v);
  90. }else
  91. v = nil;
  92. runlock(&map->RWLock);
  93. return v;
  94. }
  95. void*
  96. insertkey(Intmap *map, uint32_t id, void *v)
  97. {
  98. Intlist *f;
  99. void *ov;
  100. uint32_t h;
  101. wlock(&map->RWLock);
  102. if((f = *llookup(map, id)) != nil){
  103. /* no decrement for ov because we're returning it */
  104. ov = f->aux;
  105. f->aux = v;
  106. }else{
  107. f = emalloc9p(sizeof(*f));
  108. f->id = id;
  109. f->aux = v;
  110. h = hashid(id);
  111. f->link = map->hash[h];
  112. map->hash[h] = f;
  113. ov = nil;
  114. }
  115. wunlock(&map->RWLock);
  116. return ov;
  117. }
  118. int
  119. caninsertkey(Intmap *map, uint32_t id, void *v)
  120. {
  121. Intlist *f;
  122. int rv;
  123. uint32_t h;
  124. wlock(&map->RWLock);
  125. if(*llookup(map, id))
  126. rv = 0;
  127. else{
  128. f = emalloc9p(sizeof *f);
  129. f->id = id;
  130. f->aux = v;
  131. h = hashid(id);
  132. f->link = map->hash[h];
  133. map->hash[h] = f;
  134. rv = 1;
  135. }
  136. wunlock(&map->RWLock);
  137. return rv;
  138. }
  139. void*
  140. deletekey(Intmap *map, uint32_t id)
  141. {
  142. Intlist **lf, *f;
  143. void *ov;
  144. wlock(&map->RWLock);
  145. if((f = *(lf = llookup(map, id))) != nil){
  146. ov = f->aux;
  147. *lf = f->link;
  148. free(f);
  149. }else
  150. ov = nil;
  151. wunlock(&map->RWLock);
  152. return ov;
  153. }