Fix: take RCU read-side lock within hash table functions
[lttng-tools.git] / src / common / hashtable / hashtable.c
... / ...
CommitLineData
1/*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2 only,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18#define _GNU_SOURCE
19#define _LGPL_SOURCE
20#include <assert.h>
21#include <string.h>
22#include <urcu.h>
23#include <urcu/compiler.h>
24
25#include <common/common.h>
26#include <common/defaults.h>
27
28#include "hashtable.h"
29#include "utils.h"
30
31unsigned long lttng_ht_seed;
32
33static unsigned long min_hash_alloc_size = 1;
34static unsigned long max_hash_buckets_size = 0;
35
36/*
37 * Getter/lookup functions need to be called with RCU read-side lock
38 * held. However, modification functions (add, add_unique, replace, del)
39 * take the RCU lock internally, so it does not matter whether the
40 * caller hold the RCU lock or not.
41 */
42
43/*
44 * Match function for string node.
45 */
46static int match_str(struct cds_lfht_node *node, const void *key)
47{
48 struct lttng_ht_node_str *match_node =
49 caa_container_of(node, struct lttng_ht_node_str, node);
50
51 return hash_match_key_str(match_node->key, (void *) key);
52}
53
54/*
55 * Match function for ulong node.
56 */
57static int match_ulong(struct cds_lfht_node *node, const void *key)
58{
59 struct lttng_ht_node_ulong *match_node =
60 caa_container_of(node, struct lttng_ht_node_ulong, node);
61
62 return hash_match_key_ulong((void *) match_node->key, (void *) key);
63}
64
65/*
66 * Match function for u64 node.
67 */
68static int match_u64(struct cds_lfht_node *node, const void *key)
69{
70 struct lttng_ht_node_u64 *match_node =
71 caa_container_of(node, struct lttng_ht_node_u64, node);
72
73 return hash_match_key_u64(&match_node->key, (void *) key);
74}
75
76/*
77 * Match function for two uint64_t node.
78 */
79static int match_two_u64(struct cds_lfht_node *node, const void *key)
80{
81 struct lttng_ht_node_two_u64 *match_node =
82 caa_container_of(node, struct lttng_ht_node_two_u64, node);
83
84 return hash_match_key_two_u64((void *) &match_node->key, (void *) key);
85}
86
87/*
88 * Return an allocated lttng hashtable.
89 */
90struct lttng_ht *lttng_ht_new(unsigned long size, int type)
91{
92 struct lttng_ht *ht;
93
94 /* Test size */
95 if (!size)
96 size = DEFAULT_HT_SIZE;
97
98 ht = zmalloc(sizeof(*ht));
99 if (ht == NULL) {
100 PERROR("zmalloc lttng_ht");
101 goto error;
102 }
103
104 ht->ht = cds_lfht_new(size, min_hash_alloc_size, max_hash_buckets_size,
105 CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL);
106 /*
107 * There is already an assert in the RCU hashtable code so if the ht is
108 * NULL here there is a *huge* problem.
109 */
110 assert(ht->ht);
111
112 switch (type) {
113 case LTTNG_HT_TYPE_STRING:
114 ht->match_fct = match_str;
115 ht->hash_fct = hash_key_str;
116 break;
117 case LTTNG_HT_TYPE_ULONG:
118 ht->match_fct = match_ulong;
119 ht->hash_fct = hash_key_ulong;
120 break;
121 case LTTNG_HT_TYPE_U64:
122 ht->match_fct = match_u64;
123 ht->hash_fct = hash_key_u64;
124 break;
125 case LTTNG_HT_TYPE_TWO_U64:
126 ht->match_fct = match_two_u64;
127 ht->hash_fct = hash_key_two_u64;
128 break;
129 default:
130 ERR("Unknown lttng hashtable type %d", type);
131 lttng_ht_destroy(ht);
132 goto error;
133 }
134
135 DBG3("Created hashtable size %lu at %p of type %d", size, ht->ht, type);
136
137 return ht;
138
139error:
140 return NULL;
141}
142
143/*
144 * Free a lttng hashtable.
145 */
146void lttng_ht_destroy(struct lttng_ht *ht)
147{
148 int ret;
149
150 ret = cds_lfht_destroy(ht->ht, NULL);
151 assert(!ret);
152 free(ht);
153}
154
155/*
156 * Init lttng ht node string.
157 */
158void lttng_ht_node_init_str(struct lttng_ht_node_str *node, char *key)
159{
160 assert(node);
161
162 node->key = key;
163 cds_lfht_node_init(&node->node);
164}
165
166/*
167 * Init lttng ht node unsigned long.
168 */
169void lttng_ht_node_init_ulong(struct lttng_ht_node_ulong *node,
170 unsigned long key)
171{
172 assert(node);
173
174 node->key = key;
175 cds_lfht_node_init(&node->node);
176}
177
178/*
179 * Init lttng ht node uint64_t.
180 */
181void lttng_ht_node_init_u64(struct lttng_ht_node_u64 *node,
182 uint64_t key)
183{
184 assert(node);
185
186 node->key = key;
187 cds_lfht_node_init(&node->node);
188}
189
190/*
191 * Init lttng ht node with two uint64_t.
192 */
193void lttng_ht_node_init_two_u64(struct lttng_ht_node_two_u64 *node,
194 uint64_t key1, uint64_t key2)
195{
196 assert(node);
197
198 node->key.key1 = key1;
199 node->key.key2 = key2;
200 cds_lfht_node_init(&node->node);
201}
202
203/*
204 * Free lttng ht node string.
205 */
206void lttng_ht_node_free_str(struct lttng_ht_node_str *node)
207{
208 assert(node);
209 free(node);
210}
211
212/*
213 * Free lttng ht node unsigned long.
214 */
215void lttng_ht_node_free_ulong(struct lttng_ht_node_ulong *node)
216{
217 assert(node);
218 free(node);
219}
220
221/*
222 * Free lttng ht node uint64_t.
223 */
224void lttng_ht_node_free_u64(struct lttng_ht_node_u64 *node)
225{
226 assert(node);
227 free(node);
228}
229
230/*
231 * Free lttng ht node two uint64_t.
232 */
233void lttng_ht_node_free_two_u64(struct lttng_ht_node_two_u64 *node)
234{
235 assert(node);
236 free(node);
237}
238
239/*
240 * Lookup function in hashtable.
241 */
242void lttng_ht_lookup(struct lttng_ht *ht, void *key,
243 struct lttng_ht_iter *iter)
244{
245 assert(ht);
246 assert(ht->ht);
247
248 cds_lfht_lookup(ht->ht, ht->hash_fct(key, lttng_ht_seed),
249 ht->match_fct, key, &iter->iter);
250}
251
252/*
253 * Add unique string node to hashtable.
254 */
255void lttng_ht_add_unique_str(struct lttng_ht *ht,
256 struct lttng_ht_node_str *node)
257{
258 struct cds_lfht_node *node_ptr;
259 assert(ht);
260 assert(ht->ht);
261 assert(node);
262
263 /* RCU read lock protects from ABA. */
264 rcu_read_lock();
265 node_ptr = cds_lfht_add_unique(ht->ht, ht->hash_fct(node->key, lttng_ht_seed),
266 ht->match_fct, node->key, &node->node);
267 rcu_read_unlock();
268 assert(node_ptr == &node->node);
269}
270
271/*
272 * Add string node to hashtable.
273 */
274void lttng_ht_add_str(struct lttng_ht *ht,
275 struct lttng_ht_node_str *node)
276{
277 assert(ht);
278 assert(ht->ht);
279 assert(node);
280
281 /* RCU read lock protects from ABA. */
282 rcu_read_lock();
283 cds_lfht_add(ht->ht, ht->hash_fct(node->key, lttng_ht_seed),
284 &node->node);
285 rcu_read_unlock();
286}
287
288/*
289 * Add unsigned long node to hashtable.
290 */
291void lttng_ht_add_ulong(struct lttng_ht *ht, struct lttng_ht_node_ulong *node)
292{
293 assert(ht);
294 assert(ht->ht);
295 assert(node);
296
297 /* RCU read lock protects from ABA. */
298 rcu_read_lock();
299 cds_lfht_add(ht->ht, ht->hash_fct((void *) node->key, lttng_ht_seed),
300 &node->node);
301 rcu_read_unlock();
302}
303
304/*
305 * Add uint64_t node to hashtable.
306
307 */
308void lttng_ht_add_u64(struct lttng_ht *ht, struct lttng_ht_node_u64 *node)
309{
310 assert(ht);
311 assert(ht->ht);
312 assert(node);
313
314 /* RCU read lock protects from ABA. */
315 rcu_read_lock();
316 cds_lfht_add(ht->ht, ht->hash_fct(&node->key, lttng_ht_seed),
317 &node->node);
318 rcu_read_unlock();
319}
320
321/*
322 * Add unique unsigned long node to hashtable.
323 */
324void lttng_ht_add_unique_ulong(struct lttng_ht *ht,
325 struct lttng_ht_node_ulong *node)
326{
327 struct cds_lfht_node *node_ptr;
328 assert(ht);
329 assert(ht->ht);
330 assert(node);
331
332 /* RCU read lock protects from ABA. */
333 rcu_read_lock();
334 node_ptr = cds_lfht_add_unique(ht->ht,
335 ht->hash_fct((void *) node->key, lttng_ht_seed), ht->match_fct,
336 (void *) node->key, &node->node);
337 rcu_read_unlock();
338 assert(node_ptr == &node->node);
339}
340
341/*
342 * Add unique uint64_t node to hashtable.
343 */
344void lttng_ht_add_unique_u64(struct lttng_ht *ht,
345 struct lttng_ht_node_u64 *node)
346{
347 struct cds_lfht_node *node_ptr;
348 assert(ht);
349 assert(ht->ht);
350 assert(node);
351
352 /* RCU read lock protects from ABA. */
353 rcu_read_lock();
354 node_ptr = cds_lfht_add_unique(ht->ht,
355 ht->hash_fct(&node->key, lttng_ht_seed), ht->match_fct,
356 &node->key, &node->node);
357 rcu_read_unlock();
358 assert(node_ptr == &node->node);
359}
360
361/*
362 * Add unique two uint64_t node to hashtable.
363 */
364void lttng_ht_add_unique_two_u64(struct lttng_ht *ht,
365 struct lttng_ht_node_two_u64 *node)
366{
367 struct cds_lfht_node *node_ptr;
368 assert(ht);
369 assert(ht->ht);
370 assert(node);
371
372 /* RCU read lock protects from ABA. */
373 rcu_read_lock();
374 node_ptr = cds_lfht_add_unique(ht->ht,
375 ht->hash_fct((void *) &node->key, lttng_ht_seed), ht->match_fct,
376 (void *) &node->key, &node->node);
377 rcu_read_unlock();
378 assert(node_ptr == &node->node);
379}
380
381/*
382 * Add replace unsigned long node to hashtable.
383 */
384struct lttng_ht_node_ulong *lttng_ht_add_replace_ulong(struct lttng_ht *ht,
385 struct lttng_ht_node_ulong *node)
386{
387 struct cds_lfht_node *node_ptr;
388 assert(ht);
389 assert(ht->ht);
390 assert(node);
391
392 /* RCU read lock protects from ABA. */
393 rcu_read_lock();
394 node_ptr = cds_lfht_add_replace(ht->ht,
395 ht->hash_fct((void *) node->key, lttng_ht_seed), ht->match_fct,
396 (void *) node->key, &node->node);
397 rcu_read_unlock();
398 if (!node_ptr) {
399 return NULL;
400 } else {
401 return caa_container_of(node_ptr, struct lttng_ht_node_ulong, node);
402 }
403 assert(node_ptr == &node->node);
404}
405
406/*
407 * Add replace unsigned long node to hashtable.
408 */
409struct lttng_ht_node_u64 *lttng_ht_add_replace_u64(struct lttng_ht *ht,
410 struct lttng_ht_node_u64 *node)
411{
412 struct cds_lfht_node *node_ptr;
413 assert(ht);
414 assert(ht->ht);
415 assert(node);
416
417 /* RCU read lock protects from ABA. */
418 rcu_read_lock();
419 node_ptr = cds_lfht_add_replace(ht->ht,
420 ht->hash_fct(&node->key, lttng_ht_seed), ht->match_fct,
421 &node->key, &node->node);
422 rcu_read_unlock();
423 if (!node_ptr) {
424 return NULL;
425 } else {
426 return caa_container_of(node_ptr, struct lttng_ht_node_u64, node);
427 }
428 assert(node_ptr == &node->node);
429}
430
431/*
432 * Delete node from hashtable.
433 */
434int lttng_ht_del(struct lttng_ht *ht, struct lttng_ht_iter *iter)
435{
436 int ret;
437
438 assert(ht);
439 assert(ht->ht);
440 assert(iter);
441
442 /* RCU read lock protects from ABA. */
443 rcu_read_lock();
444 ret = cds_lfht_del(ht->ht, iter->iter.node);
445 rcu_read_unlock();
446 return ret;
447}
448
449/*
450 * Get first node in the hashtable.
451 */
452void lttng_ht_get_first(struct lttng_ht *ht, struct lttng_ht_iter *iter)
453{
454 assert(ht);
455 assert(ht->ht);
456 assert(iter);
457
458 cds_lfht_first(ht->ht, &iter->iter);
459}
460
461/*
462 * Get next node in the hashtable.
463 */
464void lttng_ht_get_next(struct lttng_ht *ht, struct lttng_ht_iter *iter)
465{
466 assert(ht);
467 assert(ht->ht);
468 assert(iter);
469
470 cds_lfht_next(ht->ht, &iter->iter);
471}
472
473/*
474 * Return the number of nodes in the hashtable.
475 */
476unsigned long lttng_ht_get_count(struct lttng_ht *ht)
477{
478 long scb, sca;
479 unsigned long count;
480
481 assert(ht);
482 assert(ht->ht);
483
484 /* RCU read lock protects from ABA and allows RCU traversal. */
485 rcu_read_lock();
486 cds_lfht_count_nodes(ht->ht, &scb, &count, &sca);
487 rcu_read_unlock();
488
489 return count;
490}
491
492/*
493 * Return lttng ht string node from iterator.
494 */
495struct lttng_ht_node_str *lttng_ht_iter_get_node_str(
496 struct lttng_ht_iter *iter)
497{
498 struct cds_lfht_node *node;
499
500 assert(iter);
501 node = cds_lfht_iter_get_node(&iter->iter);
502 if (!node) {
503 return NULL;
504 }
505 return caa_container_of(node, struct lttng_ht_node_str, node);
506}
507
508/*
509 * Return lttng ht unsigned long node from iterator.
510 */
511struct lttng_ht_node_ulong *lttng_ht_iter_get_node_ulong(
512 struct lttng_ht_iter *iter)
513{
514 struct cds_lfht_node *node;
515
516 assert(iter);
517 node = cds_lfht_iter_get_node(&iter->iter);
518 if (!node) {
519 return NULL;
520 }
521 return caa_container_of(node, struct lttng_ht_node_ulong, node);
522}
523
524/*
525 * Return lttng ht unsigned long node from iterator.
526 */
527struct lttng_ht_node_u64 *lttng_ht_iter_get_node_u64(
528 struct lttng_ht_iter *iter)
529{
530 struct cds_lfht_node *node;
531
532 assert(iter);
533 node = cds_lfht_iter_get_node(&iter->iter);
534 if (!node) {
535 return NULL;
536 }
537 return caa_container_of(node, struct lttng_ht_node_u64, node);
538}
539
540/*
541 * Return lttng ht stream and index id node from iterator.
542 */
543struct lttng_ht_node_two_u64 *lttng_ht_iter_get_node_two_u64(
544 struct lttng_ht_iter *iter)
545{
546 struct cds_lfht_node *node;
547
548 assert(iter);
549 node = cds_lfht_iter_get_node(&iter->iter);
550 if (!node) {
551 return NULL;
552 }
553 return caa_container_of(node, struct lttng_ht_node_two_u64, node);
554}
555
556/*
557 * lib constructor
558 */
559static void __attribute__((constructor)) _init(void)
560{
561 /* Init hash table seed */
562 lttng_ht_seed = (unsigned long) time(NULL);
563}
This page took 0.024375 seconds and 4 git commands to generate.