bwatch.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  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 "stdinc.h"
  10. #include "dat.h"
  11. #include "fns.h"
  12. #include "error.h"
  13. /*
  14. * Lock watcher. Check that locking of blocks is always down.
  15. *
  16. * This is REALLY slow, and it won't work when the blocks aren't
  17. * arranged in a tree (e.g., after the first snapshot). But it's great
  18. * for debugging.
  19. */
  20. enum
  21. {
  22. MaxLock = 16,
  23. HashSize = 1009,
  24. };
  25. /*
  26. * Thread-specific watch state.
  27. */
  28. typedef struct WThread WThread;
  29. struct WThread
  30. {
  31. Block *b[MaxLock]; /* blocks currently held */
  32. uint nb;
  33. uint pid;
  34. };
  35. typedef struct WMap WMap;
  36. typedef struct WEntry WEntry;
  37. struct WEntry
  38. {
  39. uint8_t c[VtScoreSize];
  40. uint8_t p[VtScoreSize];
  41. int off;
  42. WEntry *cprev;
  43. WEntry *cnext;
  44. WEntry *pprev;
  45. WEntry *pnext;
  46. };
  47. struct WMap
  48. {
  49. VtLock *lk;
  50. WEntry *hchild[HashSize];
  51. WEntry *hparent[HashSize];
  52. };
  53. static WMap map;
  54. static void **wp;
  55. static uint blockSize;
  56. static WEntry *pool;
  57. uint bwatchDisabled;
  58. static uint
  59. hash(uint8_t score[VtScoreSize])
  60. {
  61. uint i, h;
  62. h = 0;
  63. for(i=0; i<VtScoreSize; i++)
  64. h = h*37 + score[i];
  65. return h%HashSize;
  66. }
  67. #include <pool.h>
  68. static void
  69. freeWEntry(WEntry *e)
  70. {
  71. memset(e, 0, sizeof(WEntry));
  72. e->pnext = pool;
  73. pool = e;
  74. }
  75. static WEntry*
  76. allocWEntry(void)
  77. {
  78. int i;
  79. WEntry *w;
  80. w = pool;
  81. if(w == nil){
  82. w = vtMemAllocZ(1024*sizeof(WEntry));
  83. for(i=0; i<1024; i++)
  84. freeWEntry(&w[i]);
  85. w = pool;
  86. }
  87. pool = w->pnext;
  88. memset(w, 0, sizeof(WEntry));
  89. return w;
  90. }
  91. /*
  92. * remove all dependencies with score as a parent
  93. */
  94. static void
  95. _bwatchResetParent(uint8_t *score)
  96. {
  97. WEntry *w, *next;
  98. uint h;
  99. h = hash(score);
  100. for(w=map.hparent[h]; w; w=next){
  101. next = w->pnext;
  102. if(memcmp(w->p, score, VtScoreSize) == 0){
  103. if(w->pnext)
  104. w->pnext->pprev = w->pprev;
  105. if(w->pprev)
  106. w->pprev->pnext = w->pnext;
  107. else
  108. map.hparent[h] = w->pnext;
  109. if(w->cnext)
  110. w->cnext->cprev = w->cprev;
  111. if(w->cprev)
  112. w->cprev->cnext = w->cnext;
  113. else
  114. map.hchild[hash(w->c)] = w->cnext;
  115. freeWEntry(w);
  116. }
  117. }
  118. }
  119. /*
  120. * and child
  121. */
  122. static void
  123. _bwatchResetChild(uint8_t *score)
  124. {
  125. WEntry *w, *next;
  126. uint h;
  127. h = hash(score);
  128. for(w=map.hchild[h]; w; w=next){
  129. next = w->cnext;
  130. if(memcmp(w->c, score, VtScoreSize) == 0){
  131. if(w->pnext)
  132. w->pnext->pprev = w->pprev;
  133. if(w->pprev)
  134. w->pprev->pnext = w->pnext;
  135. else
  136. map.hparent[hash(w->p)] = w->pnext;
  137. if(w->cnext)
  138. w->cnext->cprev = w->cprev;
  139. if(w->cprev)
  140. w->cprev->cnext = w->cnext;
  141. else
  142. map.hchild[h] = w->cnext;
  143. freeWEntry(w);
  144. }
  145. }
  146. }
  147. static uint8_t*
  148. parent(uint8_t c[VtScoreSize], int *off)
  149. {
  150. WEntry *w;
  151. uint h;
  152. h = hash(c);
  153. for(w=map.hchild[h]; w; w=w->cnext)
  154. if(memcmp(w->c, c, VtScoreSize) == 0){
  155. *off = w->off;
  156. return w->p;
  157. }
  158. return nil;
  159. }
  160. static void
  161. addChild(uint8_t p[VtEntrySize], uint8_t c[VtEntrySize], int off)
  162. {
  163. uint h;
  164. WEntry *w;
  165. w = allocWEntry();
  166. memmove(w->p, p, VtScoreSize);
  167. memmove(w->c, c, VtScoreSize);
  168. w->off = off;
  169. h = hash(p);
  170. w->pnext = map.hparent[h];
  171. if(w->pnext)
  172. w->pnext->pprev = w;
  173. map.hparent[h] = w;
  174. h = hash(c);
  175. w->cnext = map.hchild[h];
  176. if(w->cnext)
  177. w->cnext->cprev = w;
  178. map.hchild[h] = w;
  179. }
  180. void
  181. bwatchReset(uint8_t score[VtScoreSize])
  182. {
  183. vtLock(map.lk);
  184. _bwatchResetParent(score);
  185. _bwatchResetChild(score);
  186. vtUnlock(map.lk);
  187. }
  188. void
  189. bwatchInit(void)
  190. {
  191. map.lk = vtLockAlloc();
  192. wp = privalloc();
  193. *wp = nil;
  194. }
  195. void
  196. bwatchSetBlockSize(uint bs)
  197. {
  198. blockSize = bs;
  199. }
  200. static WThread*
  201. getWThread(void)
  202. {
  203. WThread *w;
  204. w = *wp;
  205. if(w == nil || w->pid != getpid()){
  206. w = vtMemAllocZ(sizeof(WThread));
  207. *wp = w;
  208. w->pid = getpid();
  209. }
  210. return w;
  211. }
  212. /*
  213. * Derive dependencies from the contents of b.
  214. */
  215. void
  216. bwatchDependency(Block *b)
  217. {
  218. int i, epb, ppb;
  219. Entry e;
  220. if(bwatchDisabled)
  221. return;
  222. vtLock(map.lk);
  223. _bwatchResetParent(b->score);
  224. switch(b->l.type){
  225. case BtData:
  226. break;
  227. case BtDir:
  228. epb = blockSize / VtEntrySize;
  229. for(i=0; i<epb; i++){
  230. entryUnpack(&e, b->data, i);
  231. if(!(e.flags & VtEntryActive))
  232. continue;
  233. addChild(b->score, e.score, i);
  234. }
  235. break;
  236. default:
  237. ppb = blockSize / VtScoreSize;
  238. for(i=0; i<ppb; i++)
  239. addChild(b->score, b->data+i*VtScoreSize, i);
  240. break;
  241. }
  242. vtUnlock(map.lk);
  243. }
  244. static int
  245. depth(uint8_t *s)
  246. {
  247. int d, x;
  248. d = -1;
  249. while(s){
  250. d++;
  251. s = parent(s, &x);
  252. }
  253. return d;
  254. }
  255. static int
  256. lockConflicts(uint8_t xhave[VtScoreSize], uint8_t xwant[VtScoreSize])
  257. {
  258. uint8_t *have, *want;
  259. int havedepth, wantdepth, havepos, wantpos;
  260. have = xhave;
  261. want = xwant;
  262. havedepth = depth(have);
  263. wantdepth = depth(want);
  264. /*
  265. * walk one or the other up until they're both
  266. * at the same level.
  267. */
  268. havepos = -1;
  269. wantpos = -1;
  270. have = xhave;
  271. want = xwant;
  272. while(wantdepth > havedepth){
  273. wantdepth--;
  274. want = parent(want, &wantpos);
  275. }
  276. while(havedepth > wantdepth){
  277. havedepth--;
  278. have = parent(have, &havepos);
  279. }
  280. /*
  281. * walk them up simultaneously until we reach
  282. * a common ancestor.
  283. */
  284. while(have && want && memcmp(have, want, VtScoreSize) != 0){
  285. have = parent(have, &havepos);
  286. want = parent(want, &wantpos);
  287. }
  288. /*
  289. * not part of same tree. happens mainly with
  290. * newly allocated blocks.
  291. */
  292. if(!have || !want)
  293. return 0;
  294. /*
  295. * never walked want: means we want to lock
  296. * an ancestor of have. no no.
  297. */
  298. if(wantpos == -1)
  299. return 1;
  300. /*
  301. * never walked have: means we want to lock a
  302. * child of have. that's okay.
  303. */
  304. if(havepos == -1)
  305. return 0;
  306. /*
  307. * walked both: they're from different places in the tree.
  308. * require that the left one be locked before the right one.
  309. * (this is questionable, but it puts a total order on the block tree).
  310. */
  311. return havepos < wantpos;
  312. }
  313. static void
  314. stop(void)
  315. {
  316. int fd;
  317. char buf[32];
  318. snprint(buf, sizeof buf, "#p/%d/ctl", getpid());
  319. fd = open(buf, OWRITE);
  320. write(fd, "stop", 4);
  321. close(fd);
  322. }
  323. /*
  324. * Check whether the calling thread can validly lock b.
  325. * That is, check that the calling thread doesn't hold
  326. * locks for any of b's children.
  327. */
  328. void
  329. bwatchLock(Block *b)
  330. {
  331. int i;
  332. WThread *w;
  333. if(bwatchDisabled)
  334. return;
  335. if(b->part != PartData)
  336. return;
  337. vtLock(map.lk);
  338. w = getWThread();
  339. for(i=0; i<w->nb; i++){
  340. if(lockConflicts(w->b[i]->score, b->score)){
  341. fprint(2, "%d: have block %V; shouldn't lock %V\n",
  342. w->pid, w->b[i]->score, b->score);
  343. stop();
  344. }
  345. }
  346. vtUnlock(map.lk);
  347. if(w->nb >= MaxLock){
  348. fprint(2, "%d: too many blocks held\n", w->pid);
  349. stop();
  350. }else
  351. w->b[w->nb++] = b;
  352. }
  353. /*
  354. * Note that the calling thread is about to unlock b.
  355. */
  356. void
  357. bwatchUnlock(Block *b)
  358. {
  359. int i;
  360. WThread *w;
  361. if(bwatchDisabled)
  362. return;
  363. if(b->part != PartData)
  364. return;
  365. w = getWThread();
  366. for(i=0; i<w->nb; i++)
  367. if(w->b[i] == b)
  368. break;
  369. if(i>=w->nb){
  370. fprint(2, "%d: unlock of unlocked block %V\n", w->pid, b->score);
  371. stop();
  372. }else
  373. w->b[i] = w->b[--w->nb];
  374. }