2 * shl - Named-Objects Registers
4 * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files
8 * (the "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * Named-Objects Registers
28 * We often have an interface and several different backends that implement the
29 * interface. To allow dynamic loading/unloading of backends, we give each
30 * backend a name and vtable/data-ptr.
31 * Once registered, the backend can be searched for and then used. The
32 * shl_register object manages the backend loading/unloading in a thread-safe
33 * way so we can share the backends between threads. It also manages access to
34 * still used backends while they have been unregistered. Only after the last
35 * record of a backend has been dropped, the backend is fully unused.
38 #ifndef SHL_REGISTER_H
39 #define SHL_REGISTER_H
46 #include "shl_dlist.h"
48 typedef void (*shl_register_destroy_cb) (void *data);
50 struct shl_register_record {
51 struct shl_dlist list;
53 pthread_mutex_t mutex;
57 shl_register_destroy_cb destroy;
61 pthread_mutex_t mutex;
62 struct shl_dlist records;
65 #define SHL_REGISTER_INIT(name) { \
66 .mutex = PTHREAD_MUTEX_INITIALIZER, \
67 .records = SHL_DLIST_INIT((name).records), \
70 static inline void shl_register_record_ref(struct shl_register_record *record)
77 ret = pthread_mutex_lock(&record->mutex);
81 pthread_mutex_unlock(&record->mutex);
84 static inline void shl_register_record_unref(struct shl_register_record *record)
86 unsigned long ref = 1;
92 ret = pthread_mutex_lock(&record->mutex);
96 pthread_mutex_unlock(&record->mutex);
102 record->destroy(record->data);
103 pthread_mutex_destroy(&record->mutex);
108 static inline int shl_register_new(struct shl_register **out)
110 struct shl_register *reg;
116 reg = malloc(sizeof(*reg));
119 memset(reg, 0, sizeof(*reg));
120 shl_dlist_init(®->records);
122 ret = pthread_mutex_init(®->mutex, NULL);
136 static inline void shl_register_free(struct shl_register *reg)
138 struct shl_dlist *iter;
139 struct shl_register_record *record;
144 shl_dlist_for_each(iter, ®->records) {
145 record = shl_dlist_entry(iter, struct shl_register_record,
147 shl_dlist_unlink(&record->list);
148 shl_register_record_unref(record);
151 pthread_mutex_destroy(®->mutex);
155 static inline int shl_register_add_cb(struct shl_register *reg,
156 const char *name, void *data,
157 shl_register_destroy_cb destroy)
159 struct shl_dlist *iter;
160 struct shl_register_record *record;
166 ret = pthread_mutex_lock(®->mutex);
170 shl_dlist_for_each(iter, ®->records) {
171 record = shl_dlist_entry(iter, struct shl_register_record,
173 if (!strcmp(record->name, name)) {
179 record = malloc(sizeof(*record));
184 memset(record, 0, sizeof(*record));
187 record->destroy = destroy;
189 ret = pthread_mutex_init(&record->mutex, NULL);
195 record->name = strdup(name);
201 shl_dlist_link_tail(®->records, &record->list);
206 pthread_mutex_destroy(&record->mutex);
210 pthread_mutex_unlock(®->mutex);
214 static inline int shl_register_add(struct shl_register *reg, const char *name,
217 return shl_register_add_cb(reg, name, data, NULL);
220 static inline void shl_register_remove(struct shl_register *reg,
223 struct shl_dlist *iter;
224 struct shl_register_record *record;
230 ret = pthread_mutex_lock(®->mutex);
234 shl_dlist_for_each(iter, ®->records) {
235 record = shl_dlist_entry(iter, struct shl_register_record,
237 if (strcmp(record->name, name))
240 shl_dlist_unlink(&record->list);
241 shl_register_record_unref(record);
245 pthread_mutex_unlock(®->mutex);
248 static inline struct shl_register_record *shl_register_find(
249 struct shl_register *reg,
252 struct shl_dlist *iter;
253 struct shl_register_record *record, *res;
259 ret = pthread_mutex_lock(®->mutex);
264 shl_dlist_for_each(iter, ®->records) {
265 record = shl_dlist_entry(iter, struct shl_register_record,
267 if (!strcmp(record->name, name)) {
269 shl_register_record_ref(res);
274 pthread_mutex_unlock(®->mutex);
278 static inline struct shl_register_record *shl_register_first(
279 struct shl_register *reg)
287 ret = pthread_mutex_lock(®->mutex);
291 if (shl_dlist_empty(®->records)) {
294 res = shl_dlist_entry(reg->records.next,
295 struct shl_register_record, list);
296 shl_register_record_ref(res);
299 pthread_mutex_unlock(®->mutex);
303 static inline struct shl_register_record *shl_register_last(
304 struct shl_register *reg)
312 ret = pthread_mutex_lock(®->mutex);
316 if (shl_dlist_empty(®->records)) {
319 res = shl_dlist_entry(reg->records.prev,
320 struct shl_register_record, list);
321 shl_register_record_ref(res);
324 pthread_mutex_unlock(®->mutex);
328 #endif /* SHL_REGISTER_H */