1 /*
2 * Copyright (C) 2011 Red Hat, Inc.
3 *
4 * Author: Angus Salkeld <asalkeld@redhat.com>
5 *
6 * This file is part of libqb.
7 *
8 * libqb is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation, either version 2.1 of the License, or
11 * (at your option) any later version.
12 *
13 * libqb is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with libqb. If not, see <http://www.gnu.org/licenses/>.
20 */
21 #include <os_base.h>
22 #include <assert.h>
23
24 #include <qb/qbdefs.h>
25 #include <qb/qbmap.h>
26 #include "map_int.h"
27
28 #define SKIPLIST_LEVEL_MAX 8
29 #define SKIPLIST_LEVEL_MIN 0
30 /* The amount of possible levels */
31 #define SKIPLIST_LEVEL_COUNT (SKIPLIST_LEVEL_MAX - SKIPLIST_LEVEL_MIN + 1)
32
33 struct skiplist_iter {
34 struct qb_map_iter i;
35 struct skiplist_node *n;
36 };
37
38 struct skiplist_node {
39 const char *key;
40 void *value;
41 /* special meaning when lower than SKIPLIST_LEVEL_MIN:
42 indication that @skiplist_node_destroy() needs to skip
43 disposing node->forward (unless it is the termination
44 of the whole list) */
45 int8_t level;
46 uint32_t refcount;
47 struct qb_list_head notifier_head;
48
49 /* An array of @level + 1 node pointers */
50 struct skiplist_node **forward;
51 };
52
53 struct skiplist {
54 struct qb_map map;
55
56 size_t length;
57 /* special meaning when lower than SKIPLIST_LEVEL_MIN:
58 indication that @skiplist_node_destroy() is the terminating
59 one (triggered with @skiplist_destroy()), therefore node->forward
60 needs to be free'd unconditionally */
61 int8_t level;
62 struct skiplist_node *header;
63 };
64
65 /* An array of nodes that need to be updated after an insert or delete operation
66 */
67 typedef struct skiplist_node *skiplist_update_t[SKIPLIST_LEVEL_COUNT];
68
69 static int8_t
70 skiplist_level_generate(void)
71 {
72 /* This constant is found by 1 / P, where P = 0.25. */
73 enum { P_INVERSE = 4 };
74
75 /* The original algorithm's random number is in the range [0, 1), so
76 * max M = 1. Its ceiling C = M * P = 1 * P = P.
77 *
78 * Our random number is in the range [0, UINT16_MAX], so M = UINT16_MAX. Therefore,
79 * C = UINT16_MAX * P = UINT16_MAX / P_INVERSE.
80 */
81 enum { P_CEIL = UINT16_MAX / P_INVERSE };
82 int8_t level = SKIPLIST_LEVEL_MIN;
83
|
(1) Event dont_call: |
"random" should not be used for security-related applications, because linear congruential algorithms are too easy to break. |
|
(2) Event remediation: |
Use a compliant random number generator, such as "/dev/random" or "/dev/urandom" on Unix-like systems, and CNG (Cryptography API: Next Generation) on Windows. |
84 while ((uint16_t) (random()) < P_CEIL)
85 level++;
86
87 if (level < SKIPLIST_LEVEL_MAX)
88 return level;
89
90 return SKIPLIST_LEVEL_MAX;
91 }
92
93 static struct skiplist_node *
94 skiplist_node_next(const struct skiplist_node *node)
95 {
96 const struct skiplist_node *n = node;
97 do {
98 n = n->forward[SKIPLIST_LEVEL_MIN];
99 } while (n && n->refcount == 0);
100 return (struct skiplist_node *)n;
101 }
102
103 /*
104 * Create a new level @level node with value @value. The node should eventually
105 * be destroyed with @skiplist_node_destroy.
106 *
107 * return: a new node on success and NULL otherwise.
108 */
109 static struct skiplist_node *
110 skiplist_node_new(const int8_t level, const char *key, const void *value)
111 {
112 struct skiplist_node *new_node = (struct skiplist_node *)
113 (malloc(sizeof(struct skiplist_node)));
114
115 if (!new_node)
116 return NULL;
117
118 new_node->value = (void *)value;
119 new_node->key = key;
120 new_node->level = level;
121 new_node->refcount = 1;
122 qb_list_init(&new_node->notifier_head);
123
124 /* A level 0 node still needs to hold 1 forward pointer, etc.;
125 instead of "level + 1", we need to capture whole possible
126 width because of forward-member-resilience-upon-entry-removal
127 arrangment based on takeover-and-repoint. */
128 new_node->forward = (struct skiplist_node **)
129 (calloc(SKIPLIST_LEVEL_MAX + 1, sizeof(struct skiplist_node *)));
130
131 if (new_node->forward == NULL) {
132 free(new_node);
133 return NULL;
134 }
135
136 return new_node;
137 }
138
139 static struct skiplist_node *
140 skiplist_header_node_new(void)
141 {
142 return skiplist_node_new(SKIPLIST_LEVEL_MAX, NULL, NULL);
143 }
144
145 /* An operation to perform after comparing a user value or search with a
146 * node's value
147 */
148 typedef enum {
149 OP_GOTO_NEXT_LEVEL,
150 OP_GOTO_NEXT_NODE,
151 OP_FINISH,
152 } op_t;
153
154 static op_t
155 op_search(const struct skiplist *list,
156 const struct skiplist_node *fwd_node, const void *search)
157 {
158 int32_t cmp;
159
160 if (!fwd_node)
161 return OP_GOTO_NEXT_LEVEL;
162
163 cmp = strcmp(fwd_node->key, search);
164 if (cmp < 0) {
165 return OP_GOTO_NEXT_NODE;
166 } else if (cmp == 0) {
167 return OP_FINISH;
168 }
169
170 return OP_GOTO_NEXT_LEVEL;
171 }
172
173 static struct skiplist_node *
174 skiplist_lookup(struct skiplist *list, const char *key)
175 {
176 struct skiplist_node *cur_node = list->header;
177 int8_t level = list->level;
178
179 while (level >= SKIPLIST_LEVEL_MIN) {
180 struct skiplist_node *fwd_node = cur_node->forward[(size_t)level];
181
182 switch (op_search(list, fwd_node, key)) {
183 case OP_FINISH:
184 return fwd_node;
185 case OP_GOTO_NEXT_NODE:
186 cur_node = fwd_node;
187 break;
188 case OP_GOTO_NEXT_LEVEL:
189 level--;
190 }
191 }
192
193 return NULL;
194 }
195
196 static void
197 skiplist_notify(struct skiplist *l, struct skiplist_node *n,
198 uint32_t event, char *key, void *old_value, void *value)
199 {
200 struct qb_list_head *list;
201 struct qb_map_notifier *tn;
202
203 /* node callbacks
204 */
205 qb_list_for_each(list, &n->notifier_head) {
206 tn = qb_list_entry(list, struct qb_map_notifier, list);
207
208 if (tn->events & event) {
209 tn->callback(event, key, old_value, value,
210 tn->user_data);
211 }
212 }
213 /* global callbacks
214 */
215 qb_list_for_each(list, &l->header->notifier_head) {
216 tn = qb_list_entry(list, struct qb_map_notifier, list);
217
218 if (tn->events & event) {
219 tn->callback(event, key, old_value, value,
220 tn->user_data);
221 }
222 if (((event & QB_MAP_NOTIFY_DELETED) ||
223 (event & QB_MAP_NOTIFY_REPLACED)) &&
224 (tn->events & QB_MAP_NOTIFY_FREE)) {
225 tn->callback(QB_MAP_NOTIFY_FREE, (char *)key,
226 old_value, value, tn->user_data);
227 }
228 }
229
230 }
231
232 static void
233 skiplist_node_destroy(struct skiplist_node *node, struct skiplist *list)
234 {
235 struct qb_list_head *pos;
236 struct qb_list_head *next;
237 struct qb_map_notifier *tn;
238
239 skiplist_notify(list, node,
240 QB_MAP_NOTIFY_DELETED,
241 (char *)node->key, node->value, NULL);
242
243 qb_list_for_each_safe(pos, next, &node->notifier_head) {
244 tn = qb_list_entry(pos, struct qb_map_notifier, list);
245 qb_list_del(&tn->list);
246 free(tn);
247 }
248
249 if (node->level >= SKIPLIST_LEVEL_MIN
250 || list->level < SKIPLIST_LEVEL_MIN) {
251 free(node->forward);
252 }
253 free(node);
254 }
255
256 static void
257 skiplist_node_deref(struct skiplist_node *node, struct skiplist *list)
258 {
259 node->refcount--;
260 if (node->refcount == 0) {
261 skiplist_node_destroy(node, list);
262 }
263 }
264
265 static int32_t
266 skiplist_notify_add(qb_map_t * m, const char *key,
267 qb_map_notify_fn fn, int32_t events, void *user_data)
268 {
269 struct skiplist *t = (struct skiplist *)m;
270 struct qb_map_notifier *f;
271 struct skiplist_node *n;
272 struct qb_list_head *list;
273 int add_to_tail = QB_FALSE;
274
275 if (key) {
276 n = skiplist_lookup(t, key);
277 } else {
278 n = t->header;
279 }
280 if (events & QB_MAP_NOTIFY_FREE) {
281 add_to_tail = QB_TRUE;
282 }
283 if (n) {
284 qb_list_for_each(list, &n->notifier_head) {
285 f = qb_list_entry(list, struct qb_map_notifier, list);
286
287 if (events & QB_MAP_NOTIFY_FREE &&
288 f->events == events) {
289 /* only one free notifier */
290 return -EEXIST;
291 }
292 if (f->events == events &&
293 f->callback == fn &&
294 f->user_data == user_data) {
295 return -EEXIST;
296 }
297 }
298
299 f = malloc(sizeof(struct qb_map_notifier));
300 if (f == NULL) {
301 return -errno;
302 }
303 f->events = events;
304 f->user_data = user_data;
305 f->callback = fn;
306 qb_list_init(&f->list);
307 if (add_to_tail) {
308 qb_list_add_tail(&f->list, &n->notifier_head);
309 } else {
310 qb_list_add(&f->list, &n->notifier_head);
311 }
312 return 0;
313 }
314 return -EINVAL;
315 }
316
317 static int32_t
318 skiplist_notify_del(qb_map_t * m, const char *key,
319 qb_map_notify_fn fn, int32_t events,
320 int32_t cmp_userdata, void *user_data)
321 {
322 struct skiplist *t = (struct skiplist *)m;
323 struct skiplist_node *n;
324 struct qb_map_notifier *f;
325 struct qb_list_head *head = NULL;
326 struct qb_list_head *list;
327 struct qb_list_head *next;
328 int32_t found = QB_FALSE;
329
330 if (key) {
331 n = skiplist_lookup(t, key);
332 if (n) {
333 head = &n->notifier_head;
334 }
335 } else {
336 head = &t->header->notifier_head;
337 }
338 if (head == NULL) {
339 return -ENOENT;
340 }
341 qb_list_for_each_safe(list, next, head) {
342 f = qb_list_entry(list, struct qb_map_notifier, list);
343
344 if (f->events == events && f->callback == fn) {
345 if (cmp_userdata && (f->user_data == user_data)) {
346 found = QB_TRUE;
347 qb_list_del(&f->list);
348 free(f);
349 } else if (!cmp_userdata) {
350 found = QB_TRUE;
351 qb_list_del(&f->list);
352 free(f);
353 }
354 }
355 }
356 if (found) {
357 return 0;
358 } else {
359 return -ENOENT;
360 }
361 }
362
363 static void
364 skiplist_destroy(struct qb_map *map)
365 {
366 struct skiplist *list = (struct skiplist *)map;
367 struct skiplist_node *cur_node;
368 struct skiplist_node *fwd_node;
369
370 list->level = SKIPLIST_LEVEL_MIN - 1; /* indicate teardown */
371 for (cur_node = skiplist_node_next(list->header);
372 cur_node; cur_node = fwd_node) {
373 fwd_node = skiplist_node_next(cur_node);
374 skiplist_node_destroy(cur_node, list);
375 }
376 skiplist_node_destroy(list->header, list);
377 free(list);
378 }
379
380 static void
381 skiplist_put(struct qb_map *map, const char *key, const void *value)
382 {
383 struct skiplist *list = (struct skiplist *)map;
384 struct skiplist_node *new_node;
385 int8_t level = list->level;
386 skiplist_update_t update;
387 int8_t update_level;
388 int8_t new_node_level;
389 struct skiplist_node *cur_node = list->header;
390 char *old_k;
391 char *old_v;
392
393 while ((update_level = level) >= SKIPLIST_LEVEL_MIN) {
394 struct skiplist_node *fwd_node = cur_node->forward[(size_t)level];
395
396 switch (op_search(list, fwd_node, key)) {
397 case OP_FINISH:
398 old_k = (char *)fwd_node->key;
399 old_v = (char *)fwd_node->value;
400 fwd_node->value = (void *)value;
401 fwd_node->key = (void *)key;
402 skiplist_notify(list, fwd_node,
403 QB_MAP_NOTIFY_REPLACED,
404 old_k, old_v, fwd_node->value);
405 return;
406
407 case OP_GOTO_NEXT_NODE:
408 cur_node = fwd_node;
409 break;
410 case OP_GOTO_NEXT_LEVEL:
411 level--;
412 }
413
414 update[(size_t)update_level] = cur_node;
415 }
416
417 new_node_level = skiplist_level_generate();
418
419 if (new_node_level > list->level) {
420 for (level = list->level + 1; level <= new_node_level; level++)
421 update[(size_t)level] = list->header;
422
423 list->level = new_node_level;
424 }
425
426 new_node = skiplist_node_new(new_node_level, key, value);
427
428 assert(new_node != NULL);
429 skiplist_notify(list, new_node,
430 QB_MAP_NOTIFY_INSERTED,
431 (char*)new_node->key, NULL, new_node->value);
432
433 /* Drop @new_node into @list. */
434 for (level = SKIPLIST_LEVEL_MIN; level <= new_node_level; level++) {
435 new_node->forward[(size_t)level] = update[(size_t)level]->forward[(size_t)level];
436 update[(size_t)level]->forward[(size_t)level] = new_node;
437 }
438
439 list->length++;
440 }
441
442 static int32_t
443 skiplist_rm(struct qb_map *map, const char *key)
444 {
445 struct skiplist *list = (struct skiplist *)map;
446 struct skiplist_node *found_node;
447 struct skiplist_node *cur_node = list->header;
448 int8_t level = list->level;
449 int8_t update_level;
450 skiplist_update_t update;
451
452 while ((update_level = level) >= SKIPLIST_LEVEL_MIN) {
453 struct skiplist_node *fwd_node = cur_node->forward[(size_t)level];
454
455 switch (op_search(list, fwd_node, key)) {
456 case OP_GOTO_NEXT_NODE:
457 cur_node = fwd_node;
458 break;
459 case OP_GOTO_NEXT_LEVEL:
460 default:
461 level--;
462 break;
463 }
464
465 update[(size_t)update_level] = cur_node;
466 }
467
468 /* The immediate forward node should be the matching node... */
469 found_node = skiplist_node_next(cur_node);
470
471 /* ...unless we're at the end of the list or the value doesn't exist. */
472 if (!found_node || strcmp(found_node->key, key) != 0) {
473 return QB_FALSE;
474 }
475
476 /* Splice found_node out of list. */
477 for (level = SKIPLIST_LEVEL_MIN; level <= list->level; level++) {
478 if (update[level]->forward[level] == found_node) {
479 update[(size_t)level]->forward[(size_t)level] =
480 found_node->forward[(size_t)level];
481 }
482 }
483
484 /* If @found_node is referenced more than once, it means that it is
485 currently positioned with one or more iterators, therefore it's
486 likely that @qb_map_iter_next() will be called at least once so
487 as to progress pass this @found_node. The problem is, original
488 @found_node->forward may have become referencing successfully
489 destroyed original successor by the time the progress of such
490 iterator(s) resumes, possibly causing use-after-free in
491 @skiplist_node_next().
492
493 To solve this, we will grab @cur_node->forward, which has just
494 been updated accordingly in the above statement, copying it
495 to @found_node->forward, and repointing @cur_node->forward to
496 point to @found_node's copy (freeing its original list first).
497 To prevent freeing the pointed memory behind @cur_node's
498 back from the @found_node's context, we use the fact that the
499 iterator can only advance to the next node, without re-examination
500 of the current one, hence we can afford to abuse @found_node->value
501 as a flag field when set to our private "special" value that under
502 no normal circumstance can appear (for being link-time singleton).
503
504 In addition, we have to special-case the beginning of the list
505 (header) preceding @found_node, which can be distinguished with
506 NULL being used as a key (second allowing condition below). */
507 if (found_node->refcount > 1 || cur_node->key == NULL) {
508 for (level = SKIPLIST_LEVEL_MIN; level <= found_node->level; level++) {
509 found_node->forward[level] = cur_node->forward[level];
510 }
511 found_node->level = SKIPLIST_LEVEL_MIN - 1; /* no "forward" drop */
512 free(cur_node->forward);
513 cur_node->forward = found_node->forward;
514 }
515 skiplist_node_deref(found_node, list);
516
517 /* Remove unused levels from @list -- stop removing levels as soon as a
518 * used level is found. Unused levels can occur if @found_node had the
519 * highest level.
520 */
521 for (level = list->level; level >= SKIPLIST_LEVEL_MIN; level--) {
522 if (list->header->forward[(size_t)level])
523 break;
524
525 list->level--;
526 }
527
528 list->length--;
529
530 return QB_TRUE;
531 }
532
533 static void *
534 skiplist_get(struct qb_map *map, const char *key)
535 {
536 struct skiplist *list = (struct skiplist *)map;
537 struct skiplist_node *n = skiplist_lookup(list, key);
538 if (n) {
539 return n->value;
540 }
541
542 return NULL;
543 }
544
545 static qb_map_iter_t *
546 skiplist_iter_create(struct qb_map *map, const char *prefix)
547 {
548 struct skiplist_iter *i = malloc(sizeof(struct skiplist_iter));
549 struct skiplist *list = (struct skiplist *)map;
550 if (i == NULL) {
551 return NULL;
552 }
553 i->i.m = map;
554 i->n = list->header;
555 i->n->refcount++;
556 return (qb_map_iter_t *) i;
557 }
558
559 static const char *
560 skiplist_iter_next(qb_map_iter_t * i, void **value)
561 {
562 struct skiplist_iter *si = (struct skiplist_iter *)i;
563 struct skiplist_node *p = si->n;
564
565 if (p == NULL) {
566 return NULL;
567 }
568 si->n = skiplist_node_next(p);
569 if (si->n == NULL) {
570 skiplist_node_deref(p, (struct skiplist *)i->m);
571 return NULL;
572 }
573 si->n->refcount++;
574 skiplist_node_deref(p, (struct skiplist *)i->m);
575 *value = si->n->value;
576 return si->n->key;
577 }
578
579 static void
580 skiplist_iter_free(qb_map_iter_t * i)
581 {
582 free(i);
583 }
584
585 static size_t
586 skiplist_count_get(struct qb_map *map)
587 {
588 struct skiplist *list = (struct skiplist *)map;
589 return list->length;
590 }
591
592 qb_map_t *
593 qb_skiplist_create(void)
594 {
595 struct skiplist *sl = malloc(sizeof(struct skiplist));
596 if (sl == NULL) {
597 return NULL;
598 }
599
600 srand(time(NULL));
601
602 sl->map.put = skiplist_put;
603 sl->map.get = skiplist_get;
604 sl->map.rm = skiplist_rm;
605 sl->map.count_get = skiplist_count_get;
606 sl->map.iter_create = skiplist_iter_create;
607 sl->map.iter_next = skiplist_iter_next;
608 sl->map.iter_free = skiplist_iter_free;
609 sl->map.destroy = skiplist_destroy;
610 sl->map.notify_add = skiplist_notify_add;
611 sl->map.notify_del = skiplist_notify_del;
612 sl->level = SKIPLIST_LEVEL_MIN;
613 sl->length = 0;
614 sl->header = skiplist_header_node_new();
615
616 return (qb_map_t *) sl;
617 }
618