Reload strlist and iplist resource-files only when needed.
[apps/pfixtools.git] / postlicyd / resources.c
1 /******************************************************************************/
2 /*          pfixtools: a collection of postfix related tools                  */
3 /*          ~~~~~~~~~                                                         */
4 /*  ________________________________________________________________________  */
5 /*                                                                            */
6 /*  Redistribution and use in source and binary forms, with or without        */
7 /*  modification, are permitted provided that the following conditions        */
8 /*  are met:                                                                  */
9 /*                                                                            */
10 /*  1. Redistributions of source code must retain the above copyright         */
11 /*     notice, this list of conditions and the following disclaimer.          */
12 /*  2. Redistributions in binary form must reproduce the above copyright      */
13 /*     notice, this list of conditions and the following disclaimer in the    */
14 /*     documentation and/or other materials provided with the distribution.   */
15 /*  3. The names of its contributors may not be used to endorse or promote    */
16 /*     products derived from this software without specific prior written     */
17 /*     permission.                                                            */
18 /*                                                                            */
19 /*  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND   */
20 /*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE     */
21 /*  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR        */
22 /*  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS    */
23 /*  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR    */
24 /*  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF      */
25 /*  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  */
26 /*  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN   */
27 /*  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)   */
28 /*  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF    */
29 /*  THE POSSIBILITY OF SUCH DAMAGE.                                           */
30 /******************************************************************************/
31
32 /*
33  * Copyright © 2008 Florent Bruneau
34  */
35
36 #include "str.h"
37 #include "array.h"
38 #include "resources.h"
39
40 typedef struct resource_t {
41     char *key;
42     void *data;
43     int  refcount;
44     resource_destructor_t destructor;
45 } resource_t;
46 ARRAY(resource_t);
47
48 #define RESOURCE_INIT { NULL, NULL, 0, NULL }
49
50 static A(resource_t) resources = ARRAY_INIT;
51
52 #define RESOURCE_KEY                                                           \
53     char rskey[BUFSIZ];                                                        \
54     m_strcpy(rskey, BUFSIZ, ns);                                               \
55     m_strcat(rskey, BUFSIZ, "@@");                                             \
56     m_strcat(rskey, BUFSIZ, key);
57
58 static inline void resource_wipe(resource_t *res)
59 {
60     static const resource_t vr = RESOURCE_INIT;
61     if (res->destructor) {
62         res->destructor(res->data);
63     }
64     p_delete(&res->key);
65     *res = vr;
66 }
67
68 static inline resource_t *resource_find(const char *key, bool create)
69 {
70     foreach (resource_t* res, resources) {
71         if (strcmp(res->key, key) == 0) {
72             return res;
73         }
74     }}
75     if (create) {
76         resource_t res = RESOURCE_INIT;
77         res.key = m_strdup(key);
78         array_add(resources, res);
79         return &array_last(resources);
80     }
81     return NULL;
82 }
83
84 void *resource_get(const char *ns, const char *key)
85 {
86     RESOURCE_KEY;
87     resource_t *entry = resource_find(rskey, false);
88     if (entry == NULL) {
89         return NULL;
90     } else {
91         ++entry->refcount;
92         return entry->data;
93     }
94 }
95
96 bool resource_set(const char *ns, const char *key, void *data,
97                   resource_destructor_t destructor) {
98     RESOURCE_KEY;
99     resource_t *entry = resource_find(rskey, true);
100     if (entry->data != NULL) {
101         if (entry->destructor) {
102             entry->destructor(entry->data);
103         }
104     }
105     entry->refcount  += 1;
106     entry->data       = data;
107     entry->destructor = destructor;
108     return true;
109 }
110
111 void resource_release(const char *ns, const char *key)
112 {
113     RESOURCE_KEY;
114     resource_t *entry = resource_find(rskey, false);
115     if (entry != NULL) {
116         assert(entry->refcount > 0);
117         --entry->refcount;
118     }
119 }
120
121 void resource_garbage_collect(void)
122 {
123     uint32_t used = 0;
124     foreach (resource_t *res, resources) {
125         if (res->key != NULL && res->refcount == 0) {
126             debug("resource gc: %s not referenced anymore", res->key);
127             resource_wipe(res);
128         } else if (res->key != NULL) {
129             debug("resource gc: keeping %s, still %d references",
130                   res->key, res->refcount);
131             if (used < __Ai) {
132                 array_elt(resources, used) = *res;
133             }
134             ++used;
135         }
136     }}
137     debug("resource gc: before %d resources, after %d",
138           array_len(resources), used);
139     array_len(resources) = used;
140 }
141
142 static void resources_exit(void)
143 {
144     array_deep_wipe(resources, resource_wipe);
145 }
146 module_exit(resources_exit);