avl.h
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 
29 /* returns a pointer to the users shared memory or NULL if name
30  * is not found. */
31 static inline
32 void *find_segment_name(const struct shm_arena *a,
33  const char *name, size_t *user_size)
34 {
35  struct arena_header *a_hdr;
36  struct seg_header *seg;
37  int map_num;
38  offset_t offset;
39 
40  a_hdr = ((struct arena_header *)(a->mapping[0].start));
41  map_num = a_hdr->alloc_mapnum;
42  offset = a_hdr->alloc_offset;
43  seg = get_seg_header(a, map_num, offset);
44 
45  while(seg)
46  {
47  char *seg_name;
48  int cmp;
49  seg_name = get_seg_name(seg);
50  cmp = strcmp(name, seg_name);
51  if(cmp < 0) /* smaller are to the left */
52  seg = get_seg_header(a, seg->left_mapnum, seg->left_offset);
53  else if(cmp > 0) /* larger to the right */
54  seg = get_seg_header(a, seg->right_mapnum, seg->right_offset);
55  else /* cmp == 0 We have a match! */
56  {
57  if(user_size)
58  *user_size = seg->user_length;
59  return get_seg_ptr(seg);
60  }
61  }
62  return NULL;
63 }
64 
65 /* returns a pointer to the segment header. */
66 static inline
67 struct seg_header *find_segment(const struct shm_arena *a,
68  const char *name, mapnum_t *mapnum)
69 {
70  struct arena_header *a_hdr;
71  struct seg_header *seg;
72  int map_num;
73  offset_t offset;
74 
75  ASSERT(mapnum);
76 
77  a_hdr = ((struct arena_header *)(a->mapping[0].start));
78  map_num = a_hdr->alloc_mapnum;
79  offset = a_hdr->alloc_offset;
80  seg = get_seg_header(a, map_num, offset);
81 
82  while(seg)
83  {
84  char *seg_name;
85  int cmp;
86  seg_name = get_seg_name(seg);
87  cmp = strcmp(name, seg_name);
88  if(cmp < 0) /* smaller are to the left */
89  seg = get_seg_header(a, map_num=seg->left_mapnum, seg->left_offset);
90  else if(cmp > 0) /* larger to the right */
91  seg = get_seg_header(a, map_num=seg->right_mapnum, seg->right_offset);
92  else /* cmp == 0 We have a match! */
93  {
94  *mapnum = map_num;
95  return seg;
96  }
97  }
98  return NULL;
99 }
100 
101 /* returns a pointer to the struct seg_header of the smallest free
102  * segment that has a total size of at least size size.
103  *
104  * mapnum is a pointer to the mapnum, that is returned, which is the
105  * mapnum associated with the seg_header that is returned.
106  */
107 static inline
108 struct seg_header *find_free_segment(const struct shm_arena *a,
109  size_t size, mapnum_t *ret_mapnum)
110 {
111  struct arena_header *a_hdr;
112  struct seg_header *seg, *prev_seg = NULL;
113  int prev_mapnum = -1, mapnum;
114 
115  a_hdr = ((struct arena_header *)(a->mapping[0].start));
116 
117  ASSERT(a_hdr);
118 
119  mapnum = a_hdr->free_mapnum;
120  seg = get_seg_header(a, mapnum, a_hdr->free_offset);
121 
122  while(seg)
123  {
124  size_t len;
125 
126  len = seg->length * CHUNK;
127 
128  if(len >= size) /* smaller are to the left */
129  {
130  prev_seg = seg;
131  prev_mapnum = mapnum;
132 
133  mapnum = seg->left_mapnum;
134  seg = get_seg_header(a, mapnum, seg->left_offset);
135  }
136  else /* if(len < size) *//* larger to the right */
137  {
138  mapnum = seg->right_mapnum;
139  seg = get_seg_header(a, mapnum, seg->right_offset);
140  }
141  }
142 
143 
144  if(!seg)
145  {
146  *ret_mapnum = prev_mapnum;
147  return prev_seg;
148  }
149  else
150  {
151  *ret_mapnum = mapnum;
152  return seg;
153  }
154 }
155 
156 static inline int
157 difference(const struct shm_arena *a, struct seg_header *p_hdr)
158 /* returns the difference between the height of the left and right
159  * child nodes of p_hdr. */
160 {
161  height_t left_ht, right_ht;
162  struct seg_header *seg;
163 
164  if(!p_hdr) return 0;
165 
166  seg = get_seg_header(a, p_hdr->left_mapnum, p_hdr->left_offset);
167  left_ht = seg ? seg->height : -1;
168 
169  seg = get_seg_header(a, p_hdr->right_mapnum, p_hdr->right_offset);
170  right_ht = seg ? seg->height : -1;
171 
172  return (left_ht - right_ht);
173 }
174 
175 /* This is FOR TESTING/DEBUGING */
176 extern
177 struct seg_header
178 *_shm_check_free_segment(const struct shm_arena *a,
179  mapnum_t mapnum, offset_t offset);
180 
181 typedef int (*compare_func_t)(const struct seg_header *, mapnum_t, offset_t,
182  const struct seg_header *, mapnum_t, offset_t);
183 
184 extern
185 int _shm_compare_free(const struct seg_header *hdr1, mapnum_t mapnum1, offset_t top1,
186  const struct seg_header *hdr0, mapnum_t mapnum0, offset_t top0);
187 extern
188 int _shm_compare_allocated(const struct seg_header *hdr1,
189  mapnum_t mapnum1,
190  offset_t top1,
191  const struct seg_header *hdr0,
192  mapnum_t mapnum0,
193  offset_t top0);
194 
195 extern
196 void _shm_insert_node(const struct shm_arena *a,
197  struct seg_header *seg, mapnum_t seg_mapnum,
198  mapnum_t *parent_mapnum, offset_t *parent_offset,
199  compare_func_t compare_func);
200 
201 /* returns 0 on success, 1 if not found */
202 extern
203 int _shm_detach_free_segment(const struct shm_arena *a, struct seg_header *seg,
204  mapnum_t mapnum);
205 
206 static inline
207 void insert_free_segment(const struct shm_arena *a, struct seg_header *seg,
208  mapnum_t mapnum)
209 {
210  struct arena_header *a_hdr;
211 
212  ASSERT(a);
213  ASSERT(seg);
214  ASSERT(get_seg_footer(seg)->flags & IS_FREE);
215 
216  a_hdr = a->header;
217 
218  ASSERT(a_hdr);
219 
220  if(!(a_hdr->free_offset))
221  {
222  /* We've got no root node to put this segment node onto, so we
223  * will make this seg be the top root node segment. */
224  a_hdr->free_offset = get_offset(a, seg, mapnum);
225  a_hdr->free_mapnum = mapnum;
226  seg->height = 0;
227  return;
228  }
229 
230  _shm_insert_node(a, seg, mapnum,
231  &a_hdr->free_mapnum, &a_hdr->free_offset,
232  _shm_compare_free);
233 }
234 
235 /* returns 0 on success, 1 if not found */
236 extern
237 int _shm_detach_alloc_segment(const struct shm_arena *a, struct seg_header *seg,
238  mapnum_t mapnum);
239 
240 static inline
241 void insert_alloc_segment(const struct shm_arena *a, struct seg_header *seg,
242  mapnum_t mapnum)
243 {
244  struct arena_header *a_hdr;
245 
246  ASSERT(a);
247  ASSERT(seg);
248  ASSERT(!(get_seg_footer(seg)->flags & IS_FREE));
249 
250  a_hdr = a->header;
251 
252  ASSERT(a_hdr);
253 
254  if(!(a_hdr->alloc_offset))
255  {
256  /* We've got no root node to put this segment node onto, so we
257  * will make this seg be the top root node segment. */
258  a_hdr->alloc_offset = get_offset(a, seg, mapnum);
259  a_hdr->alloc_mapnum = mapnum;
260  seg->height = 0;
261  return;
262  }
263 
264  ASSERT(&a_hdr->alloc_mapnum);
265  ASSERT(&a_hdr->alloc_offset);
266 
267  _shm_insert_node(a, seg, mapnum,
268  &a_hdr->alloc_mapnum, &a_hdr->alloc_offset,
269  _shm_compare_allocated);
270 }
struct arena_header * header
Definition: arena.h:446
uint32_t flags
Definition: arena.h:367
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
size_t user_length
Definition: arena.h:156
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