avl.c
1 /*
2  shm-arena shared memory arena
3  Copyright (C) 2006-2008 Lance Arsenault (LGPL v3)
4 
5 
6  This file is part of shm-arena.
7 
8  shm-arena is free software; you can redistribute it and/or modify
9  it under the terms of the GNU Lesser General Public License as
10  published by the Free Software Foundation; either version 3 of the
11  License, or (at your option) any later version.
12 
13  shm-arena is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  Lesser General Public License for more details.
17 
18  You should have received a copy of the GNU Lesser General Public
19  License along with this program. If not, see
20  <http://www.gnu.org/licenses/>.
21 */
22 
28 #include "config.h"
29 #include <stdio.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <sys/mman.h>
38 #include <pthread.h>
39 #include <stdint.h>
40 
41 #include <pthread.h>
42 #include "spew.h"
43 #include "assert.h"
44 #include "debug_lock.h"
45 #include "shm_arena.h"
46 #include "arena.h"
47 #include "avl.h"
48 
49 
50 /***********************************************************************
51  Common AVL tree functions. Text book stuff except we can't use
52  pointers in shared memory, so we have an address offset and mapping
53  number (mapnum), instead of a single pointer. See arena.h for more
54  comments on the stucture of the shared memory.
55 ***********************************************************************/
56 
66 /* CAUTION: The AVL tree functions in this file do not merge free
67  * adjacent nodes that is done outside this file, in get.c for
68  * example. That makes this a little more straight forward, but it
69  * could be a little more optimized. The code in this file only knows
70  * about the struct seg_header in the segments and don't not know
71  * about any other data in the segments. */
72 
73 
74 static inline void
75 fix_height(const struct shm_arena *a, struct seg_header *p_hdr)
76 /* AVL function. Fixes the height of a node after a node is inserted
77  * to or detached from this parent node (p_hdr). I think that ternary
78  * conditionals rock! */
79 {
80  height_t left_ht, right_ht;
81  struct seg_header *seg;
82 
83  seg = get_seg_header(a, p_hdr->left_mapnum, p_hdr->left_offset);
84  left_ht = seg ? seg->height : -1;
85 
86  seg = get_seg_header(a, p_hdr->right_mapnum, p_hdr->right_offset);
87  right_ht = seg ? seg->height : -1;
88 
89  p_hdr->height = (left_ht > right_ht) ? left_ht+1 : right_ht+1;
90 }
91 
92 static inline void
93 rotate_left(const struct shm_arena *a, struct seg_header *x,
94  mapnum_t x_mapnum, offset_t x_offset,
95  mapnum_t *top_mapnum, offset_t *top_offset)
96 /* x y
97  / \ / \
98  y ----> x
99  / \ / \
100  z z
101 */
102 {
103  struct seg_header *y;
104  mapnum_t y_mapnum;
105  offset_t y_offset;
106 
107  ASSERT(x && x->right_mapnum > -1 && x->right_offset);
108 
109  /* save the mapnum and offset of y (right child of x) */
110  y_mapnum = x->right_mapnum;
111  y_offset = x->right_offset;
112 
113  /* get node struct pointer to y (right child of x) */
114  y = get_seg_header(a, y_mapnum, y_offset);
115 
116  /* change the right child of x to z (left child of y) */
117  x->right_mapnum = y->left_mapnum;
118  x->right_offset = y->left_offset;
119 
120  /* make x a child of y */
121  y->left_mapnum = x_mapnum;
122  y->left_offset = x_offset;
123 
124  if(top_offset)
125  {
126  /* make y a child of what was x's parent */
127  *top_mapnum = y_mapnum;
128  *top_offset = y_offset;
129  }
130 }
131 
132 static inline void
133 rotate_right(const struct shm_arena *a, struct seg_header *x,
134  mapnum_t x_mapnum, offset_t x_offset,
135  mapnum_t *top_mapnum, offset_t *top_offset)
136 /* x y
137  / \ / \
138  y ---> x
139  / \ / \
140  z z
141 */
142 {
143  struct seg_header *y;
144  mapnum_t y_mapnum;
145  offset_t y_offset;
146 
147  ASSERT(x && x->left_mapnum > -1 && x->left_offset);
148 
149  /* save the mapnum and offset of y (left child of x) */
150  y_mapnum = x->left_mapnum;
151  y_offset = x->left_offset;
152 
153  /* get node struct pointer to y (left child of x) */
154  y = get_seg_header(a, y_mapnum, y_offset);
155 
156  /* change the right child of x to z (right child of y) */
157  x->left_mapnum = y->right_mapnum;
158  x->left_offset = y->right_offset;
159 
160  /* make x a child of y */
161  y->right_mapnum = x_mapnum;
162  y->right_offset = x_offset;
163 
164  if(top_offset)
165  {
166  /* make y a child of what was x's parent */
167  *top_mapnum = y_mapnum;
168  *top_offset = y_offset;
169  }
170 }
171 
172 static inline void
173 balance_right(const struct shm_arena *a, struct seg_header *x,
174  mapnum_t x_mapnum, offset_t x_offset,
175  mapnum_t *top_mapnum, offset_t *top_offset)
176 /* Restores balance at x when the right child of x is too high. */
177 {
178  int right_difference;
179  struct seg_header *y;
180 
181  ASSERT(x && x->right_mapnum > -1 && x->right_offset);
182 
183  y = get_seg_header(a, x->right_mapnum, x->right_offset);
184 
185  right_difference = difference(a, y);
186 
187  if(right_difference == 0)
188  {
189  /* Case 1a: both subtrees of right child of x have the same
190  * height.
191 
192  Let h be a height of a node in the tree, given nodes x,y,z
193  for the rest of the nodes we just denote the height. We
194  rotate_left(about x):
195 
196 
197  x(h+2) y(h+2)
198  / \ / \
199  / \ / \
200  balance off --> (h-1) y(h+1) -----> x(h+1) (h)
201  / \ / \
202  / \ / \
203  z(h) (h) (h-1) z(h)
204 
205 
206  So we see that x decreases height 1 and y increases height
207  by 1.
208  */
209  rotate_left(a, x, x_mapnum, x_offset, top_mapnum, top_offset);
210  x->height--;
211  y->height++;
212  return;
213  }
214  if(right_difference < 0) /* flip the < to > for balance_left() */
215  {
216  /* Case 1b: right subtree of right child of x is higher.
217 
218  Let h be a height of a node in the tree, given nodes x,y,z
219  for the rest of the nodes we just denote the height. We
220  rotate_left(about x):
221 
222 
223  x(h+3) y(h+2)
224  / \ / \
225  / \ / \
226  balance off --> (h) y(h+2) -----> x(h+1) (h+1)
227  / \ / \
228  / \ / \
229  z(h) (h+1) (h) z(h)
230 
231 
232  So we see that x decreases height 2 and y height is
233  unchanged.
234  */
235  rotate_left(a, x, x_mapnum, x_offset, top_mapnum, top_offset);
236  x->height -= 2;
237  return;
238  }
239 
240  /* right_diffence > 0 */
241  {
242  /* Case 2: left subtree (z) of right child of x is higher.
243 
244  We rotate_right(about y) and than rotate_left(about x) like so:
245 
246 
247  x(h+3) x
248  / \ / \
249  / \ / \
250  / \ / \
251  balance off --> (h) y(h+2) (h) z
252  / \ / \
253  / \ -----> / \
254  / \ / \
255  z(h+1) yr(h) zl y
256  / \ / \
257  / \ / \
258  / \ / \
259  zl(h|h-1) zr(h-1|h) zr yr
260 
261 
262 
263  z(h+2)
264  / \
265  / \
266  / \
267  / \
268  -----> x(h+1) y(h+1)
269  / \ / \
270  / \ / \
271  / \ / \
272  / zl zr yr
273  (h) (h|h-1) (h-1|h) (h)
274 
275 
276  After the two rotations we compute the new heights. So x
277  decrease height by 2, y decreases height by 1, and z increases
278  height by 1.
279  */
280  struct seg_header *z;
281 
282  /* z = x right left child */
283  z = get_seg_header(a, y->left_mapnum, y->left_offset);
284 
285  ASSERT(z);
286 
287  rotate_right(a, y, x->right_mapnum, x->right_offset,
288  &(x->right_mapnum), &(x->right_offset));
289  rotate_left(a, x, x_mapnum, x_offset, top_mapnum, top_offset);
290  x->height -= 2;
291  y->height -= 1;
292  z->height += 1;
293  }
294 }
295 
296 static inline void
297 balance_left(const struct shm_arena *a, struct seg_header *x,
298  mapnum_t x_mapnum, offset_t x_offset,
299  mapnum_t *top_mapnum, offset_t *top_offset)
300 /* Restores balance at x when the left child of x is too high. We get
301  * this function by changing right to left and left to right, and < to
302  * > in balance_right() above. */
303 {
304  int left_difference;
305  struct seg_header *y;
306 
307  ASSERT(x && x->left_mapnum > -1 && x->left_offset);
308 
309  y = get_seg_header(a, x->left_mapnum, x->left_offset);
310 
311  left_difference = difference(a, y);
312 
313  if(left_difference == 0)
314  {
315  /* Case 1a: both subtrees of left child of x have the same
316  * height. */
317  rotate_right(a, x, x_mapnum, x_offset, top_mapnum, top_offset);
318  x->height--;
319  y->height++;
320  return;
321  }
322  if(left_difference > 0)
323  {
324  /* Case 1b: left subtree of left child of x is higher. */
325  rotate_right(a, x, x_mapnum, x_offset, top_mapnum, top_offset);
326  x->height -= 2;
327  return;
328  }
329 
330  /* left_diffence < 0 */
331  /* Case 2: right subtree of left child of x is higher. */
332  {
333  struct seg_header *xlr;
334 
335  /* xlr = x left right */
336  xlr = get_seg_header(a, y->right_mapnum, y->right_offset);
337 
338  ASSERT(xlr);
339 
340  rotate_left(a, y, x->left_mapnum, x->left_offset,
341  &(x->left_mapnum), &(x->left_offset));
342  rotate_right(a, x, x_mapnum, x_offset, top_mapnum, top_offset);
343  x->height -= 2;
344  y->height -= 1;
345  xlr->height += 1;
346  }
347 }
348 
349 /* _shm_compare_free() is used to add a free AVL node
350  *
351  * return 1 if free segment 1 is after (to the right) the free segment 0
352  * return -1 if free segment 1 is before (to the left) the free segment 0
353  * return 0 if they are the same
354  */
355 DLL_LOCAL
356 int _shm_compare_free(const struct seg_header *seg1,
357  mapnum_t mapnum1, offset_t top1,
358  const struct seg_header *seg0,
359  mapnum_t mapnum0, offset_t top0)
360 {
361  ASSERT(seg1);
362  ASSERT(seg0);
363 
364  if(seg1->length > seg0->length)
365  return 1;
366  if(seg1->length < seg0->length)
367  return -1;
368  /* hdr1->length == hdr0->length */
369  if(mapnum1 > mapnum0)
370  return 1;
371  if(mapnum1 < mapnum0)
372  return -1;
373  /* hdr1->length == hdr0->length && mapnum1 == mapnum0 */
374  if(top1 > top0)
375  return 1;
376  if(top1 < top0)
377  return -1;
378  return 0; /* They are the same. */
379 }
380 
381 /* We need the prototype of this function to be the same as
382  * _shm_compare_free() so that we may have a common _shm_insert_node() and
383  * detach_node() functions for free and allocated segments. We have
384  * one AVL tree for free shared memory segments and one AVL tree for
385  * allocated shared memory segments, for a given arena file. */
386 DLL_LOCAL
387 int _shm_compare_allocated(const struct seg_header *seg1,
388  mapnum_t mapnum1 __attribute__ ((unused)),
389  offset_t top1 __attribute__ ((unused)),
390  const struct seg_header *seg0,
391  mapnum_t mapnum0 __attribute__ ((unused)),
392  offset_t top0 __attribute__ ((unused)))
393 {
394  int cmp;
395 
396  cmp = strcmp(get_seg_name(seg1), get_seg_name(seg0));
397 
398  return (cmp>0) ? 1 : ((cmp) ? -1 : 0);
399  /* 1 means that seg1 should be to the right of seg0
400  * -1 means that seg1 should be to the left of seg0
401  * 0 means that seg1 has the same string as seg0 */
402 }
403 
404 static
405 struct seg_header *detach_left_most(const struct shm_arena *a,
406  struct seg_header *seg,
407  mapnum_t seg_mapnum,
408  mapnum_t *parent_mapnum,
409  offset_t *parent_offset,
410  mapnum_t *return_mapnum /* The mapnum of the
411  * left most find. */
412  )
413 /* detachs the left most child of seg and returns it. Does remove the
414  * right child of this left most node and attach it to the parent of
415  * the left most node. */
416 {
417  int cmp;
418  struct seg_header *child, *ret;
419 
420  *return_mapnum = seg_mapnum;
421  ret = seg;
422 
423  child = get_seg_header(a, seg->left_mapnum, seg->left_offset);
424 
425  if(child)
426  {
427  ret = detach_left_most(a, child, seg->left_mapnum,
428  &seg->left_mapnum, &seg->left_offset,
429  return_mapnum);
430  }
431  else
432  {
433  /* seg is the left_most node */
434  /* attach parent to right child of left_most node */
435  *parent_mapnum = seg->right_mapnum;
436  *parent_offset = seg->right_offset;
437 
438  /* detach right child */
439  seg->right_mapnum = -1;
440  seg->right_offset = 0;
441 
442  return ret;
443  }
444 
445 
446  /* now fix balance */
447 
448  fix_height(a, seg);
449 
450  cmp = difference(a, seg);
451 
452  if(cmp > 1)
453  /* left is too high */
454  balance_left(a, seg, *parent_mapnum, *parent_offset,
455  parent_mapnum, parent_offset);
456  else if(cmp < -1)
457  /* right is too high */
458  balance_right(a, seg, *parent_mapnum, *parent_offset,
459  parent_mapnum, parent_offset);
460 
461  /* else *//* They are balanced already. */
462 
463  return ret;
464 }
465 
466 static inline void
467 detach_from_parent(const struct shm_arena *a,
468  struct seg_header *seg,
469  mapnum_t *parent_mapnum,
470  offset_t *parent_offset)
471 {
472  ASSERT(seg);
473 
474  if(seg->left_offset && seg->right_offset)
475  {
476  int cmp;
477 
478  /* We must get tricky here since there are child
479  * nodes to the left and right of seg. */
480  struct seg_header *left_most_seg;
481  mapnum_t left_most_mapnum;
482  struct seg_header *r_seg, *l_seg;
483 
484  r_seg = get_seg_header(a, seg->right_mapnum, seg->right_offset);
485  l_seg = get_seg_header(a, seg->left_mapnum, seg->left_offset);
486 
487  /* detach the left most segment from the right child of seg.
488  * This will also keep the tree connected except for the node we
489  * are detaching, left_most_seg. */
490  left_most_seg =
491  detach_left_most(a, r_seg, seg->right_mapnum,
492  &seg->right_mapnum, &seg->right_offset,
493  &left_most_mapnum);
494 
495  /* have left_most_seg replace seg */
496 
497  *parent_mapnum = left_most_mapnum;
498  *parent_offset = get_offset(a, left_most_seg, left_most_mapnum);
499 
500  left_most_seg->left_mapnum = seg->left_mapnum;
501  left_most_seg->left_offset = seg->left_offset;
502 
503  left_most_seg->right_mapnum = seg->right_mapnum;
504  left_most_seg->right_offset = seg->right_offset;
505 
506  /* If left_most_seg == r_seg we must balance it after we balance
507  * l_seg. */
508  if(left_most_seg != r_seg)
509  {
510  /* now fix the balance what was the right child of seg */
511  fix_height(a, r_seg);
512  cmp = difference(a, r_seg);
513 
514  if(cmp > 1)
515  /* left is too high */
516  balance_left(a, r_seg,
517  left_most_seg->right_mapnum, left_most_seg->right_offset,
518  &left_most_seg->right_mapnum, &left_most_seg->right_offset);
519  else if(cmp < -1)
520  /* right is too high */
521  balance_right(a, r_seg,
522  left_most_seg->right_mapnum, left_most_seg->right_offset,
523  &left_most_seg->right_mapnum, &left_most_seg->right_offset);
524  }
525 
526  /* now fix the balance what was the left child of seg */
527 
528  fix_height(a, l_seg);
529  cmp = difference(a, l_seg);
530 
531  if(cmp > 1)
532  /* left is too high */
533  balance_left(a, r_seg,
534  left_most_seg->left_mapnum, left_most_seg->left_offset,
535  &left_most_seg->left_mapnum, &left_most_seg->left_offset);
536  else if(cmp < -1)
537  /* right is too high */
538  balance_right(a, r_seg,
539  left_most_seg->left_mapnum, left_most_seg->left_offset,
540  &left_most_seg->left_mapnum, &left_most_seg->left_offset);
541 
542  /* now fix the balance what was seg, but is now left_most_seg */
543 
544  fix_height(a, left_most_seg);
545  cmp = difference(a, left_most_seg);
546 
547  if(cmp > 1)
548  /* left is too high */
549  balance_left(a, left_most_seg,
550  *parent_mapnum, *parent_offset,
551  parent_mapnum, parent_offset);
552  else if(cmp < -1)
553  /* right is too high */
554  balance_right(a, left_most_seg,
555  *parent_mapnum, *parent_offset,
556  parent_mapnum, parent_offset);
557 
558  }
559  else if(seg->left_offset)
560  {
561  /* there is no right child to seg */
562  *parent_mapnum = seg->left_mapnum;
563  *parent_offset = seg->left_offset;
564  /* The parent height will be fixed later. */
565  }
566  else
567  {
568  /* there is no left child to seg */
569  *parent_mapnum = seg->right_mapnum;
570  *parent_offset = seg->right_offset;
571  /* The parent height will be fixed later. */
572  }
573  /* no more children for seg */
574  seg->left_mapnum = -1;
575  seg->left_offset = 0;
576  seg->right_mapnum = -1;
577  seg->right_offset = 0;
578 }
579 
580 /***********************************************************************
581  * PARAMETERS
582  *
583  * a is the local arena object
584  *
585  * seg is the segment (node) we are putting in the tree.
586  *
587  * seg_mapnum is the memory mapping that the segment seg is in.
588  *
589  * parent_mapnum is a pointer to the mapping number to the (segment)
590  * root node of the sub-tree that we are currently traversing.
591  *
592  * parent_offset is a pointer to the offset to the (segment) root node
593  * of the sub-tree that we are currently traversing.
594  ***********************************************************************
595  */
596 
597 static
598 int detach_node(const struct shm_arena *a,
599  struct seg_header *seg,
600  mapnum_t seg_mapnum,
601  mapnum_t *parent_mapnum,
602  offset_t *parent_offset,
603  compare_func_t compare_func)
604 /* return:
605  * 0 if it will not be found.
606  * 1 if it was just found
607  * -1 if it was found in a past call.
608  */
609 {
610  int cmp;
611  struct seg_header *parent;
612 
613  parent = get_seg_header(a, *parent_mapnum, *parent_offset);
614  cmp = compare_func(seg, seg_mapnum, get_offset(a, seg, seg_mapnum),
615  parent, *parent_mapnum, *parent_offset);
616 
617  if(cmp > 0)
618  {
619  /* seg may belong to the right child node of parent */
620 
621  if(parent->right_offset)
622  {
623  int ret;
624  ret = detach_node(a, seg, seg_mapnum,
625  &parent->right_mapnum,
626  &parent->right_offset,
627  compare_func);
628  if(ret == 1)
629  {
630  /* it was found in this last call so we detach seg
631  * from parent and then continue balancing. */
632  detach_from_parent(a, seg,
633  &parent->right_mapnum,
634  &parent->right_offset);
635  }
636  else if(ret == 0)
637  return 0; /* it was not found. */
638 
639  /* else *//* ret == -1 */
640  /* it was found in a past call so we continue with the
641  * balancing. */
642  }
643  else
644  {
645  SPEW(_INFO, "Segment node was not found");
646  return 0;
647  }
648  }
649  else if(cmp < 0)
650  {
651  /* seg may belong to the left child node of parent */
652 
653  if(parent->left_offset)
654  {
655  int ret;
656  ret = detach_node(a, seg, seg_mapnum,
657  &parent->left_mapnum,
658  &parent->left_offset,
659  compare_func);
660  if(ret == 1)
661  {
662  /* it was found in this last call so we detach seg
663  * from parent and then continue balancing. */
664  detach_from_parent(a, seg,
665  &parent->left_mapnum,
666  &parent->left_offset);
667  }
668  else if(ret == 0)
669  return 0; /* it was not found. */
670 
671  /* else *//* ret == -1 */
672  /* it was found in a past call so we continue with the
673  * balancing. */
674  }
675  else
676  {
677  SPEW(_INFO, "Segment node was not found");
678  return 0;
679  }
680  }
681  else /* cmp == 0 */
682  {
683  /* We found it. */
684  ASSERT(seg == parent);
685  return 1; /* just found it. */
686  }
687 
688  fix_height(a, parent);
689 
690  cmp = difference(a, parent);
691 
692  if(cmp > 1)
693  /* left is too high */
694  balance_left(a, parent, *parent_mapnum, *parent_offset,
695  parent_mapnum, parent_offset);
696  else if(cmp < -1)
697  /* right is too high */
698  balance_right(a, parent, *parent_mapnum, *parent_offset,
699  parent_mapnum, parent_offset);
700 
701  /* else *//* They are balanced already. */
702 
703  return -1;
704 }
705 
706 
707 DLL_LOCAL
708 void _shm_insert_node(const struct shm_arena *a,
709  struct seg_header *seg,
710  mapnum_t seg_mapnum,
711  mapnum_t *parent_mapnum,
712  offset_t *parent_offset,
713  compare_func_t compare_func)
714 {
715  int cmp;
716  struct seg_header *parent;
717 
718  parent = get_seg_header(a, *parent_mapnum, *parent_offset);
719  cmp = compare_func(seg, seg_mapnum, get_offset(a, seg, seg_mapnum),
720  parent, *parent_mapnum, *parent_offset);
721 
722  ASSERT(cmp != 0); /* The seg should not be the same as a segment in
723  * the tree already. */
724 
725  if(cmp > 0)
726  {
727  /* seg belongs to the right child node of parent */
728 
729  if(parent->right_offset)
730  {
731  _shm_insert_node(a, seg, seg_mapnum,
732  &parent->right_mapnum,
733  &parent->right_offset,
734  compare_func);
735  }
736  else
737  {
738  /* seg will be the right child node. */
739  parent->right_mapnum = seg_mapnum;
740  parent->right_offset = get_offset(a, seg, seg_mapnum);
741  seg->height = 0;
742  }
743  }
744  else
745  {
746  /* seg belongs to the left child node of parent */
747 
748  if(parent->left_offset)
749  {
750  _shm_insert_node(a, seg, seg_mapnum,
751  &parent->left_mapnum,
752  &parent->left_offset,
753  compare_func);
754  }
755  else
756  {
757  /* seg will be the left child node. */
758  parent->left_mapnum = seg_mapnum;
759  parent->left_offset = get_offset(a, seg, seg_mapnum);
760  seg->height = 0;
761  }
762  }
763 
764  fix_height(a, parent);
765 
766  cmp = difference(a, parent);
767 
768  ASSERT(cmp <= 2 && cmp >= -2);
769 
770  if(cmp > 1)
771  /* left is too high */
772  balance_left(a, parent, *parent_mapnum, *parent_offset,
773  parent_mapnum, parent_offset);
774  else if(cmp < -1)
775  /* right is too high */
776  balance_right(a, parent, *parent_mapnum, *parent_offset,
777  parent_mapnum, parent_offset);
778 
779  /* else *//* They are balanced already. */
780 }
781 
782 
783 DLL_LOCAL
784 int
785 _shm_detach_free_segment(const struct shm_arena *a,
786  struct seg_header *seg,
787  mapnum_t mapnum)
788 /* returns 0 on success, 1 if not found */
789 {
790  struct arena_header *a_hdr;
791 
792  ASSERT(a);
793  ASSERT(seg);
794 
795  a_hdr = a->header;
796 
797  ASSERT(a_hdr);
798 
799  if(a_hdr->free_offset == get_offset(a, seg, mapnum) &&
800  a_hdr->free_mapnum == mapnum)
801  {
802  /* Found seg is the root node. */
803  detach_from_parent(a, seg, &a_hdr->free_mapnum, &a_hdr->free_offset);
804 
805  /* Get the new root node and balance. */
806  seg = get_seg_header(a, a_hdr->free_mapnum, a_hdr->free_offset);
807 
808  if(seg)
809  {
810  int cmp;
811 
812  /* balance it */
813  cmp = difference(a, seg);
814 
815  if(cmp > 1)
816  /* left is too high */
817  balance_left(a, seg, a_hdr->free_mapnum, a_hdr->free_offset,
818  &a_hdr->free_mapnum, &a_hdr->free_offset);
819  else if(cmp < -1)
820  /* right is too high */
821  balance_right(a, seg, a_hdr->free_mapnum, a_hdr->free_offset,
822  &a_hdr->free_mapnum, &a_hdr->free_offset);
823  }
824 
825 
826  return 0;
827  }
828 
829  return (detach_node(a, seg, mapnum,
830  &a_hdr->free_mapnum, &a_hdr->free_offset,
831  _shm_compare_free))?0:1;
832 }
833 
834 DLL_LOCAL
835 int
836 _shm_detach_alloc_segment(const struct shm_arena *a,
837  struct seg_header *seg,
838  mapnum_t mapnum)
839 /* returns 0 on success, 1 if not found */
840 {
841  struct arena_header *a_hdr;
842 
843  ASSERT(a);
844  ASSERT(seg);
845 
846  a_hdr = a->header;
847 
848  ASSERT(a_hdr);
849 
850  if(a_hdr->alloc_offset == get_offset(a, seg, mapnum) &&
851  a_hdr->alloc_mapnum == mapnum)
852  {
853  /* Found seg is the root node. */
854  detach_from_parent(a, seg, &a_hdr->alloc_mapnum, &a_hdr->alloc_offset);
855 
856  /* Get the new root node and balance. */
857  seg = get_seg_header(a, a_hdr->alloc_mapnum, a_hdr->alloc_offset);
858 
859  if(seg)
860  {
861  int cmp;
862 
863  /* balance it */
864  cmp = difference(a, seg);
865 
866  if(cmp > 1)
867  /* left is too high */
868  balance_left(a, seg, a_hdr->alloc_mapnum, a_hdr->alloc_offset,
869  &a_hdr->alloc_mapnum, &a_hdr->alloc_offset);
870  else if(cmp < -1)
871  /* right is too high */
872  balance_right(a, seg, a_hdr->alloc_mapnum, a_hdr->alloc_offset,
873  &a_hdr->alloc_mapnum, &a_hdr->alloc_offset);
874  }
875  return 0;
876  }
877 
878  return (detach_node(a, seg, mapnum,
879  &a_hdr->alloc_mapnum, &a_hdr->alloc_offset,
880  _shm_compare_allocated))?0:1;
881 }
882 
883 
884 /* This is FOR TESTING/DEBUGING
885  *
886  * Check to see that a segment is in the free AVL tree.
887  *
888  * size is the length of the segment.
889  * mapnum is the mapnum of the segment.
890  * offset in CHUNKs to the segment from the top of the mapping.
891  *
892  * returns a pointer to the struct seg_header in the free AVL tree.
893  */
894 DLL_LOCAL
895 struct seg_header *_shm_check_free_segment(const struct shm_arena *a,
896  mapnum_t mapnum, offset_t offset)
897 {
898  struct arena_header *a_hdr;
899  struct seg_header *seg, *p;
900  mapnum_t p_mapnum;
901  offset_t p_offset;
902  int cmp;
903 
904  ASSERT(mapnum >= 0 && mapnum < a->num_mappings);
905  ASSERT(offset);
906 
907  a_hdr = ((struct arena_header *)(a->mapping[0].start));
908 
909  ASSERT(a_hdr);
910 
911  seg = get_seg_header(a, mapnum, offset);
912 
913  p = get_seg_header(a, p_mapnum = a_hdr->free_mapnum,
914  p_offset = a_hdr->free_offset);
915 
916  while(p_offset)
917  {
918  cmp = _shm_compare_free(seg, mapnum, offset, p, p_mapnum, p_offset);
919 
920  if(cmp > 0)
921  /* seg may belong to the right child node of parent */
922  p = get_seg_header(a, p_mapnum = p->right_mapnum,
923  p_offset = p->right_offset);
924  else if(cmp < 0)
925  /* seg may belong to the left child node of parent */
926  p = get_seg_header(a, p_mapnum = p->left_mapnum,
927  p_offset = p->left_offset);
928  else
929  /* We found it. */
930  return seg;
931  }
932 
933  return NULL;
934 }
struct arena_header * header
Definition: arena.h:446
struct shm_mapping * mapping
Definition: arena.h:454
offset_t free_offset
Definition: arena.h:394
mapnum_t right_mapnum
Definition: arena.h:142
offset_t right_offset
Definition: arena.h:147
mapnum_t left_mapnum
Definition: arena.h:142
mapnum_t alloc_mapnum
Definition: arena.h:392
offset_t length
Definition: arena.h:153
offset_t left_offset
Definition: arena.h:147
mapnum_t free_mapnum
Definition: arena.h:390
offset_t alloc_offset
Definition: arena.h:396
uint8_t * start
Definition: arena.h:405
height_t height
Definition: arena.h:150

Shared Memory Arena version RC-0.0.25