atomic locks on dictionary_set(), dictionary_del(), dictionary_destroy()
Costa Tsaousis (ktsaou) committed
May 9, 2016 at 16:35 UTC
c9035e21e75c72c6db44617086da6dd288a40f7b
2 files changed
+71
-28
src/dictionary.c
+70
-28
@@ -13,52 +13,71 @@
13
#include "dictionary.h"
14
15
// ----------------------------------------------------------------------------
16
-// name_value index
16
+// dictionary locks
17
18
-static int name_value_iterator(avl *a) { if(a) {}; return 0; }
19
-
20
-static int name_value_compare(void* a, void* b) {
21
- if(((NAME_VALUE *)a)->hash < ((NAME_VALUE *)b)->hash) return -1;
22
- else if(((NAME_VALUE *)a)->hash > ((NAME_VALUE *)b)->hash) return 1;
23
- else return strcmp(((NAME_VALUE *)a)->name, ((NAME_VALUE *)b)->name);
18
+static inline void dictionary_atomic_updates_lock(DICTIONARY *dict) {
19
+ if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
20
+ // debug(D_DICTIONARY, "Dictionary ATOMIC lock");
21
+ pthread_mutex_lock(&dict->atomic_mutex);
22
+ }
23
}
24
26
-#define dictionary_name_value_index_add_nolock(dict, nv) do { (dict)->inserts++; avl_insert(&((dict)->values_index), (avl *)(nv)); } while(0)
27
-#define dictionary_name_value_index_del_nolock(dict, nv) do { (dict)->deletes++; avl_remove(&(dict->values_index), (avl *)(nv)); } while(0)
28
-
29
-static inline NAME_VALUE *dictionary_name_value_index_find_nolock(DICTIONARY *dict, const char *name, uint32_t hash) {
30
- NAME_VALUE *result = NULL, tmp;
31
- tmp.hash = (hash)?hash:simple_hash(name);
32
- tmp.name = (char *)name;
33
-
34
- dict->searches++;
35
- avl_search(&(dict->values_index), (avl *)&tmp, name_value_iterator, (avl **)&result);
36
-
37
- return result;
25
+static inline void dictionary_atomic_updates_unlock(DICTIONARY *dict) {
26
+ if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
27
+ // debug(D_DICTIONARY, "Dictionary ATOMIC unlock");
28
+ pthread_mutex_unlock(&dict->atomic_mutex);
29
+ }
30
}
31
40
-static void dictionary_read_lock(DICTIONARY *dict) {
32
+static inline void dictionary_read_lock(DICTIONARY *dict) {
33
if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
34
// debug(D_DICTIONARY, "Dictionary READ lock");
35
pthread_rwlock_rdlock(&dict->rwlock);
36
}
37
}
38
47
-static void dictionary_write_lock(DICTIONARY *dict) {
39
+static inline void dictionary_write_lock(DICTIONARY *dict) {
40
if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
41
// debug(D_DICTIONARY, "Dictionary WRITE lock");
42
pthread_rwlock_wrlock(&dict->rwlock);
43
}
44
}
45
54
-static void dictionary_unlock(DICTIONARY *dict) {
46
+static inline void dictionary_unlock(DICTIONARY *dict) {
47
if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
48
// debug(D_DICTIONARY, "Dictionary UNLOCK lock");
49
pthread_rwlock_unlock(&dict->rwlock);
50
}
51
}
52
53
+
54
// ----------------------------------------------------------------------------
55
+// avl index
56
+
57
+static int name_value_iterator(avl *a) { if(a) {}; return 0; }
58
+
59
+static int name_value_compare(void* a, void* b) {
60
+ if(((NAME_VALUE *)a)->hash < ((NAME_VALUE *)b)->hash) return -1;
61
+ else if(((NAME_VALUE *)a)->hash > ((NAME_VALUE *)b)->hash) return 1;
62
+ else return strcmp(((NAME_VALUE *)a)->name, ((NAME_VALUE *)b)->name);
63
+}
64
+
65
+#define dictionary_name_value_index_add_nolock(dict, nv) do { (dict)->inserts++; avl_insert(&((dict)->values_index), (avl *)(nv)); } while(0)
66
+#define dictionary_name_value_index_del_nolock(dict, nv) do { (dict)->deletes++; avl_remove(&(dict->values_index), (avl *)(nv)); } while(0)
67
+
68
+static inline NAME_VALUE *dictionary_name_value_index_find_nolock(DICTIONARY *dict, const char *name, uint32_t hash) {
69
+ NAME_VALUE *result = NULL, tmp;
70
+ tmp.hash = (hash)?hash:simple_hash(name);
71
+ tmp.name = (char *)name;
72
+
73
+ dict->searches++;
74
+ avl_search(&(dict->values_index), (avl *)&tmp, name_value_iterator, (avl **)&result);
75
+
76
+ return result;
77
+}
78
+
79
+// ----------------------------------------------------------------------------
80
+// internal methods
81
82
static NAME_VALUE *dictionary_name_value_create_nolock(DICTIONARY *dict, const char *name, void *value, size_t value_len, uint32_t hash) {
83
debug(D_DICTIONARY, "Creating name value entry for name '%s'.", name);
@@ -114,6 +133,7 @@ static void dictionary_name_value_destroy_nolock(DICTIONARY *dict, NAME_VALUE *n
133
}
134
135
// ----------------------------------------------------------------------------
136
+// API - basic methods
137
138
DICTIONARY *dictionary_create(uint32_t flags) {
139
debug(D_DICTIONARY, "Creating dictionary.");
@@ -123,6 +143,7 @@ DICTIONARY *dictionary_create(uint32_t flags) {
143
144
avl_init(&dict->values_index, name_value_compare);
145
pthread_rwlock_init(&dict->rwlock, NULL);
146
+ pthread_mutex_init(&dict->atomic_mutex, NULL);
147
148
dict->flags = flags;
149
@@ -132,6 +153,8 @@ DICTIONARY *dictionary_create(uint32_t flags) {
153
void dictionary_destroy(DICTIONARY *dict) {
154
debug(D_DICTIONARY, "Destroying dictionary.");
155
156
+ dictionary_atomic_updates_lock(dict);
157
+
158
dictionary_write_lock(dict);
159
160
while(dict->values_index.root)
@@ -139,6 +162,8 @@ void dictionary_destroy(DICTIONARY *dict) {
162
163
dictionary_unlock(dict);
164
165
+ dictionary_atomic_updates_unlock(dict);
166
+
167
free(dict);
168
}
169
@@ -149,6 +174,8 @@ void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t val
174
175
uint32_t hash = simple_hash(name);
176
177
+ dictionary_atomic_updates_lock(dict);
178
+
179
dictionary_read_lock(dict);
180
NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, hash);
181
dictionary_unlock(dict);
@@ -187,6 +214,8 @@ void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t val
214
}
215
}
216
217
+ dictionary_atomic_updates_unlock(dict);
218
+
219
return nv->value;
220
}
221
@@ -207,26 +236,39 @@ void *dictionary_get(DICTIONARY *dict, const char *name) {
236
}
237
238
int dictionary_del(DICTIONARY *dict, const char *name) {
239
+ int ret;
240
+
241
debug(D_DICTIONARY, "DEL dictionary entry with name '%s'.", name);
242
243
+ dictionary_atomic_updates_lock(dict);
244
+
245
dictionary_read_lock(dict);
246
NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
247
dictionary_unlock(dict);
248
249
if(unlikely(!nv)) {
250
debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
218
- return -1;
251
+ ret = -1;
252
+ }
253
+ else {
254
+ debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
255
+ dictionary_write_lock(dict);
256
+ dictionary_name_value_destroy_nolock(dict, nv);
257
+ dictionary_unlock(dict);
258
+ ret = 0;
259
}
260
221
- debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
222
- dictionary_write_lock(dict);
223
- dictionary_name_value_destroy_nolock(dict, nv);
224
- dictionary_unlock(dict);
261
+ dictionary_atomic_updates_unlock(dict);
262
226
- return 0;
263
+ return ret;
264
}
265
266
267
+// ----------------------------------------------------------------------------
268
+// API - walk through the dictionary
269
+// the dictionary is locked for reading while this happens
270
+// do not user other dictionary calls while walking the dictionary - deadlock!
271
+
272
static int dictionary_walker(avl *a, int (*callback)(void *entry, void *data), void *data) {
273
int total = 0, ret = 0;
274
src/dictionary.h
+1
@@ -26,6 +26,7 @@ typedef struct dictionary {
26
27
avl_tree values_index;
28
pthread_rwlock_t rwlock;
29
+ pthread_mutex_t atomic_mutex;
30
} DICTIONARY;
31
32
#define DICTIONARY_FLAG_DEFAULT 0x00000000