1 /******************************************************************************
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
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__
41 #include "portable_defns.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
;
66 stm
*memory
; /* read-only */
67 stm_blk
*nullb
; /* read-only */
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
)
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
);
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
)
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
);
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
) )
131 p
= write_stm_blk(ptst
, tx
, pb
);
136 w
= write_stm_blk(ptst
, tx
, wb
);
139 w
->v
= MK_BLACK(w
->v
);
141 left_rotate(ptst
, tx
, pb
, p
);
143 w
= write_stm_blk(ptst
, tx
, wb
);
147 wl
= read_stm_blk(ptst
, tx
, wlb
);
149 wr
= read_stm_blk(ptst
, tx
, wrb
);
150 if ( IS_BLACK(wl
->v
) && IS_BLACK(wr
->v
) )
158 if ( IS_BLACK(wr
->v
) )
160 wl
= write_stm_blk(ptst
, tx
, wlb
);
161 wl
->v
= MK_BLACK(wl
->v
);
163 right_rotate(ptst
, tx
, wb
, w
);
165 w
= write_stm_blk(ptst
, tx
, wb
);
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
);
177 else /* SYMMETRIC CASE */
180 w
= write_stm_blk(ptst
, tx
, wb
);
183 w
->v
= MK_BLACK(w
->v
);
185 right_rotate(ptst
, tx
, pb
, p
);
187 w
= write_stm_blk(ptst
, tx
, wb
);
191 wl
= read_stm_blk(ptst
, tx
, wlb
);
193 wr
= read_stm_blk(ptst
, tx
, wrb
);
194 if ( IS_BLACK(wl
->v
) && IS_BLACK(wr
->v
) )
202 if ( IS_BLACK(wl
->v
) )
204 wr
= write_stm_blk(ptst
, tx
, wrb
);
205 wr
->v
= MK_BLACK(wr
->v
);
207 left_rotate(ptst
, tx
, wb
, w
);
209 w
= write_stm_blk(ptst
, tx
, wb
);
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
);
223 x
->v
= MK_BLACK(x
->v
);
227 set_t
*set_alloc(void)
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
);
250 setval_t
set_update(set_t
*s
, setkey_t k
, setval_t v
, int overwrite
)
254 stm_blk
*xb
, *b
, *pb
, *gb
, *yb
, *newb
;
255 node_t
*x
, *p
, *g
, *y
, *new;
258 k
= CALLER_TO_INTERNAL_KEY(k
);
262 ptst
= critical_enter();
265 new_stm_tx(tx
, ptst
, MEMORY
);
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
);
281 if ( overwrite
) x
->v
= SET_COLOUR(v
, GET_COLOUR(ov
));
289 newb
= new_stm_blk(ptst
, MEMORY
);
290 new = init_stm_blk(ptst
, MEMORY
, newb
);
299 if ( k
< x
->k
) x
->l
= newb
; else x
->r
= newb
;
306 if ( (pb
= x
->p
) == s
)
308 x
->v
= MK_BLACK(x
->v
);
312 p
= read_stm_blk(ptst
, tx
, pb
);
313 if ( IS_BLACK(p
->v
) ) break;
316 g
= read_stm_blk(ptst
, tx
, gb
);
320 y
= read_stm_blk(ptst
, tx
, yb
);
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
);
337 x
= write_stm_blk(ptst
, tx
, pb
);
338 left_rotate(ptst
, tx
, xb
, x
);
341 p
= write_stm_blk(ptst
, tx
, pb
);
343 g
= write_stm_blk(ptst
, tx
, gb
);
344 p
->v
= MK_BLACK(p
->v
);
346 right_rotate(ptst
, tx
, gb
, g
);
349 else /* SYMMETRIC CASE */
352 y
= read_stm_blk(ptst
, tx
, yb
);
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
);
369 x
= write_stm_blk(ptst
, tx
, pb
);
370 right_rotate(ptst
, tx
, xb
, x
);
373 p
= write_stm_blk(ptst
, tx
, pb
);
375 g
= write_stm_blk(ptst
, tx
, gb
);
376 p
->v
= MK_BLACK(p
->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
);
397 setval_t
set_remove(set_t
*s
, setkey_t k
)
401 stm_blk
*zb
, *b
, *xb
, *yb
;
402 node_t
*z
, *x
, *y
, *yp
;
405 k
= CALLER_TO_INTERNAL_KEY(k
);
407 ptst
= critical_enter();
410 new_stm_tx(tx
, ptst
, MEMORY
);
417 z
= read_stm_blk(ptst
, tx
, zb
);
420 ov
= GET_VALUE(z
->v
);
423 b
= (k
< z
->k
) ? z
->l
: z
->r
;
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). */
434 y
= read_stm_blk(ptst
, tx
, yb
);
436 while ( y
->l
!= NULLB
)
439 y
= read_stm_blk(ptst
, tx
, yb
);
442 y
= write_stm_blk(ptst
, tx
, yb
);
450 xb
= (y
->l
!= NULLB
) ? y
->l
: y
->r
;
451 x
= write_stm_blk(ptst
, tx
, xb
);
454 yp
= write_stm_blk(ptst
, tx
, y
->p
);
455 if ( yb
== yp
->l
) yp
->l
= xb
; else yp
->r
= xb
;
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
);
479 setval_t
set_lookup(set_t
*s
, setkey_t k
)
487 k
= CALLER_TO_INTERNAL_KEY(k
);
489 ptst
= critical_enter();
492 new_stm_tx(tx
, ptst
, MEMORY
);
496 while ( nb
!= NULLB
)
498 n
= read_stm_blk(ptst
, tx
, nb
);
504 nb
= (k
< n
->k
) ? n
->l
: n
->r
;
507 while ( !commit_stm_tx(ptst
, tx
) );
515 void _init_set_subsystem(void)
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
);
529 null
->v
= MK_BLACK(NULL
);