Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / mcas / rb_stm.c
blob02b7b1208874f488c8019742af9b93936593946b
1 /******************************************************************************
2 * rb_stm.c
4 * Lock-free red-black trees, based on STM.
6 * Copyright (c) 2002-2003, K A Fraser
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are
10 met:
12 * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution. Neither the name of the Keir Fraser
18 * nor the names of its contributors may be used to endorse or
19 * promote products derived from this software without specific
20 * prior written permission.
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #define __SET_IMPLEMENTATION__
37 #include <stdio.h>
38 #include <assert.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include "portable_defns.h"
42 #include "gc.h"
43 #include "stm.h"
44 #include "set.h"
46 #define IS_BLACK(_v) ((int_addr_t)(_v)&1)
47 #define IS_RED(_v) (!IS_BLACK(_v))
48 #define MK_BLACK(_v) ((setval_t)((int_addr_t)(_v)|1))
49 #define MK_RED(_v) ((setval_t)((int_addr_t)(_v)&~1))
50 #define GET_VALUE(_v) (MK_RED(_v))
51 #define GET_COLOUR(_v) (IS_BLACK(_v))
52 #define SET_COLOUR(_v,_c) ((setval_t)((unsigned long)(_v)|(unsigned long)(_c)))
54 typedef struct node_st node_t;
55 typedef stm_blk set_t;
57 struct node_st
59 setkey_t k;
60 setval_t v;
61 stm_blk *l, *r, *p;
64 static struct {
65 CACHE_PAD(0);
66 stm *memory; /* read-only */
67 stm_blk *nullb; /* read-only */
68 CACHE_PAD(2);
69 } shared;
71 #define MEMORY (shared.memory)
72 #define NULLB (shared.nullb)
74 static void left_rotate(ptst_t *ptst, stm_tx *tx, stm_blk *xb, node_t *x)
76 stm_blk *yb, *pb;
77 node_t *y, *p;
79 yb = x->r;
80 pb = x->p;
82 y = write_stm_blk(ptst, tx, yb);
83 p = write_stm_blk(ptst, tx, pb);
85 if ( (x->r = y->l) != NULLB )
87 node_t *xr = write_stm_blk(ptst, tx, x->r);
88 xr->p = xb;
91 x->p = yb;
92 y->l = xb;
93 y->p = pb;
94 if ( xb == p->l ) p->l = yb; else p->r = yb;
98 static void right_rotate(ptst_t *ptst, stm_tx *tx, stm_blk *xb, node_t *x)
100 stm_blk *yb, *pb;
101 node_t *y, *p;
103 yb = x->l;
104 pb = x->p;
106 y = write_stm_blk(ptst, tx, yb);
107 p = write_stm_blk(ptst, tx, pb);
109 if ( (x->l = y->r) != NULLB )
111 node_t *xl = write_stm_blk(ptst, tx, x->l);
112 xl->p = xb;
115 x->p = yb;
116 y->r = xb;
117 y->p = pb;
118 if ( xb == p->l ) p->l = yb; else p->r = yb;
122 static void delete_fixup(ptst_t *ptst, stm_tx *tx, set_t *s,
123 stm_blk *xb, node_t *x)
125 stm_blk *pb, *wb, *wlb, *wrb;
126 node_t *p, *w, *wl, *wr;
128 while ( (x->p != s) && IS_BLACK(x->v) )
130 pb = x->p;
131 p = write_stm_blk(ptst, tx, pb);
133 if ( xb == p->l )
135 wb = p->r;
136 w = write_stm_blk(ptst, tx, wb);
137 if ( IS_RED(w->v) )
139 w->v = MK_BLACK(w->v);
140 p->v = MK_RED(p->v);
141 left_rotate(ptst, tx, pb, p);
142 wb = p->r;
143 w = write_stm_blk(ptst, tx, wb);
146 wlb = w->l;
147 wl = read_stm_blk(ptst, tx, wlb);
148 wrb = w->r;
149 wr = read_stm_blk(ptst, tx, wrb);
150 if ( IS_BLACK(wl->v) && IS_BLACK(wr->v) )
152 w->v = MK_RED(w->v);
153 xb = pb;
154 x = p;
156 else
158 if ( IS_BLACK(wr->v) )
160 wl = write_stm_blk(ptst, tx, wlb);
161 wl->v = MK_BLACK(wl->v);
162 w->v = MK_RED(w->v);
163 right_rotate(ptst, tx, wb, w);
164 wb = p->r;
165 w = write_stm_blk(ptst, tx, wb);
168 wrb = w->r;
169 wr = write_stm_blk(ptst, tx, wrb);
170 w->v = SET_COLOUR(GET_VALUE(w->v), GET_COLOUR(p->v));
171 p->v = MK_BLACK(p->v);
172 wr->v = MK_BLACK(wr->v);
173 left_rotate(ptst, tx, pb, p);
174 break;
177 else /* SYMMETRIC CASE */
179 wb = p->l;
180 w = write_stm_blk(ptst, tx, wb);
181 if ( IS_RED(w->v) )
183 w->v = MK_BLACK(w->v);
184 p->v = MK_RED(p->v);
185 right_rotate(ptst, tx, pb, p);
186 wb = p->l;
187 w = write_stm_blk(ptst, tx, wb);
190 wlb = w->l;
191 wl = read_stm_blk(ptst, tx, wlb);
192 wrb = w->r;
193 wr = read_stm_blk(ptst, tx, wrb);
194 if ( IS_BLACK(wl->v) && IS_BLACK(wr->v) )
196 w->v = MK_RED(w->v);
197 xb = pb;
198 x = p;
200 else
202 if ( IS_BLACK(wl->v) )
204 wr = write_stm_blk(ptst, tx, wrb);
205 wr->v = MK_BLACK(wr->v);
206 w->v = MK_RED(w->v);
207 left_rotate(ptst, tx, wb, w);
208 wb = p->l;
209 w = write_stm_blk(ptst, tx, wb);
212 wlb = w->l;
213 wl = write_stm_blk(ptst, tx, wlb);
214 w->v = SET_COLOUR(GET_VALUE(w->v), GET_COLOUR(p->v));
215 p->v = MK_BLACK(p->v);
216 wl->v = MK_BLACK(wl->v);
217 right_rotate(ptst, tx, pb, p);
218 break;
223 x->v = MK_BLACK(x->v);
227 set_t *set_alloc(void)
229 ptst_t *ptst;
230 set_t *set;
231 node_t *root;
233 ptst = critical_enter();
235 set = new_stm_blk(ptst, MEMORY);
237 root = init_stm_blk(ptst, MEMORY, set);
238 root->k = SENTINEL_KEYMIN;
239 root->v = MK_RED(NULL);
240 root->l = NULLB;
241 root->r = NULLB;
242 root->p = NULL;
244 critical_exit(ptst);
246 return set;
250 setval_t set_update(set_t *s, setkey_t k, setval_t v, int overwrite)
252 ptst_t *ptst;
253 stm_tx *tx;
254 stm_blk *xb, *b, *pb, *gb, *yb, *newb;
255 node_t *x, *p, *g, *y, *new;
256 setval_t ov;
258 k = CALLER_TO_INTERNAL_KEY(k);
260 newb = NULL;
262 ptst = critical_enter();
264 do {
265 new_stm_tx(tx, ptst, MEMORY);
267 b = s;
268 while ( b != NULLB )
270 xb = b;
271 x = read_stm_blk(ptst, tx, xb);
272 if ( k == x->k ) break;
273 b = (k < x->k) ? x->l : x->r;
276 x = write_stm_blk(ptst, tx, xb);
278 if ( k == x->k )
280 ov = x->v;
281 if ( overwrite ) x->v = SET_COLOUR(v, GET_COLOUR(ov));
282 ov = GET_VALUE(ov);
284 else
286 ov = NULL;
287 if ( newb == NULL )
289 newb = new_stm_blk(ptst, MEMORY);
290 new = init_stm_blk(ptst, MEMORY, newb);
291 new->k = k;
294 new->v = MK_RED(v);
295 new->l = NULLB;
296 new->r = NULLB;
297 new->p = xb;
299 if ( k < x->k ) x->l = newb; else x->r = newb;
301 xb = newb;
302 x = new;
304 for ( ; ; )
306 if ( (pb = x->p) == s )
308 x->v = MK_BLACK(x->v);
309 break;
312 p = read_stm_blk(ptst, tx, pb);
313 if ( IS_BLACK(p->v) ) break;
315 gb = p->p;
316 g = read_stm_blk(ptst, tx, gb);
317 if ( pb == g->l )
319 yb = g->r;
320 y = read_stm_blk(ptst, tx, yb);
321 if ( IS_RED(y->v) )
323 p = write_stm_blk(ptst, tx, pb);
324 y = write_stm_blk(ptst, tx, yb);
325 g = write_stm_blk(ptst, tx, gb);
326 p->v = MK_BLACK(p->v);
327 y->v = MK_BLACK(y->v);
328 g->v = MK_RED(g->v);
329 xb = gb;
330 x = g;
332 else
334 if ( xb == p->r )
336 xb = pb;
337 x = write_stm_blk(ptst, tx, pb);
338 left_rotate(ptst, tx, xb, x);
340 pb = x->p;
341 p = write_stm_blk(ptst, tx, pb);
342 gb = p->p;
343 g = write_stm_blk(ptst, tx, gb);
344 p->v = MK_BLACK(p->v);
345 g->v = MK_RED(g->v);
346 right_rotate(ptst, tx, gb, g);
349 else /* SYMMETRIC CASE */
351 yb = g->l;
352 y = read_stm_blk(ptst, tx, yb);
353 if ( IS_RED(y->v) )
355 p = write_stm_blk(ptst, tx, pb);
356 y = write_stm_blk(ptst, tx, yb);
357 g = write_stm_blk(ptst, tx, gb);
358 p->v = MK_BLACK(p->v);
359 y->v = MK_BLACK(y->v);
360 g->v = MK_RED(g->v);
361 xb = gb;
362 x = g;
364 else
366 if ( xb == p->l )
368 xb = pb;
369 x = write_stm_blk(ptst, tx, pb);
370 right_rotate(ptst, tx, xb, x);
372 pb = x->p;
373 p = write_stm_blk(ptst, tx, pb);
374 gb = p->p;
375 g = write_stm_blk(ptst, tx, gb);
376 p->v = MK_BLACK(p->v);
377 g->v = MK_RED(g->v);
378 left_rotate(ptst, tx, gb, g);
384 remove_from_tx(ptst, tx, NULLB);
386 while ( !commit_stm_tx(ptst, tx) );
388 /* Free unused new block. */
389 if ( (ov != NULL) && (newb != NULL) ) free_stm_blk(ptst, MEMORY, newb);
391 critical_exit(ptst);
393 return ov;
397 setval_t set_remove(set_t *s, setkey_t k)
399 ptst_t *ptst;
400 stm_tx *tx;
401 stm_blk *zb, *b, *xb, *yb;
402 node_t *z, *x, *y, *yp;
403 setval_t ov;
405 k = CALLER_TO_INTERNAL_KEY(k);
407 ptst = critical_enter();
409 do {
410 new_stm_tx(tx, ptst, MEMORY);
411 ov = NULL;
412 b = s;
414 while ( b != NULLB )
416 zb = b;
417 z = read_stm_blk(ptst, tx, zb);
418 if ( k == z->k )
420 ov = GET_VALUE(z->v);
421 break;
423 b = (k < z->k) ? z->l : z->r;
426 if ( ov != NULL )
428 z = write_stm_blk(ptst, tx, zb);
430 if ( (z->l != NULLB) && (z->r != NULLB) )
432 /* Find successor of node z, and place in (yb,y). */
433 yb = z->r;
434 y = read_stm_blk(ptst, tx, yb);
436 while ( y->l != NULLB )
438 yb = y->l;
439 y = read_stm_blk(ptst, tx, yb);
442 y = write_stm_blk(ptst, tx, yb);
444 else
446 yb = zb;
447 y = z;
450 xb = (y->l != NULLB) ? y->l : y->r;
451 x = write_stm_blk(ptst, tx, xb);
452 x->p = y->p;
454 yp = write_stm_blk(ptst, tx, y->p);
455 if ( yb == yp->l ) yp->l = xb; else yp->r = xb;
457 if ( y != z )
459 z->k = y->k;
460 z->v = SET_COLOUR(GET_VALUE(y->v), GET_COLOUR(z->v));
463 if ( IS_BLACK(y->v) ) delete_fixup(ptst, tx, s, xb, x);
466 remove_from_tx(ptst, tx, NULLB);
468 while ( !commit_stm_tx(ptst, tx) );
470 /* Free a deleted block. */
471 if ( ov != NULL ) free_stm_blk(ptst, MEMORY, yb);
473 critical_exit(ptst);
475 return ov;
479 setval_t set_lookup(set_t *s, setkey_t k)
481 ptst_t *ptst;
482 stm_tx *tx;
483 stm_blk *nb;
484 node_t *n;
485 setval_t v;
487 k = CALLER_TO_INTERNAL_KEY(k);
489 ptst = critical_enter();
491 do {
492 new_stm_tx(tx, ptst, MEMORY);
493 v = NULL;
494 nb = s;
496 while ( nb != NULLB )
498 n = read_stm_blk(ptst, tx, nb);
499 if ( k == n->k )
501 v = GET_VALUE(n->v);
502 break;
504 nb = (k < n->k) ? n->l : n->r;
507 while ( !commit_stm_tx(ptst, tx) );
509 critical_exit(ptst);
511 return v;
515 void _init_set_subsystem(void)
517 node_t *null;
518 ptst_t *ptst;
520 ptst = critical_enter();
522 _init_stm_subsystem(0);
524 MEMORY = new_stm(ptst, sizeof(node_t));
526 NULLB = new_stm_blk(ptst, MEMORY);
527 null = init_stm_blk(ptst, MEMORY, NULLB);
528 null->k = 0;
529 null->v = MK_BLACK(NULL);
530 null->l = NULL;
531 null->r = NULL;
532 null->p = NULL;
534 critical_exit(ptst);