pfix-srsd: add a -I option
[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 CONTRIBUTORS ``AS IS'' AND ANY EXPRESS   */
20 /*  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED         */
21 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE    */
22 /*  DISCLAIMED.  IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY         */
23 /*  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL        */
24 /*  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS   */
25 /*  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)     */
26 /*  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,       */
27 /*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN  */
28 /*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           */
29 /*  POSSIBILITY OF SUCH DAMAGE.                                               */
30 /*                                                                            */
31 /*   Copyright (c) 2006-2008 the Authors                                      */
32 /*   see AUTHORS and source files for details                                 */
33 /******************************************************************************/
34
35 /*
36  * Copyright © 2008 Florent Bruneau
37  */
38
39 #include "str.h"
40 #include "array.h"
41 #include "resources.h"
42
43 typedef struct resource_t {
44     char *key;
45     void *data;
46     int  refcount;
47     resource_destructor_t destructor;
48 } resource_t;
49 ARRAY(resource_t);
50
51 #define RESOURCE_INIT { NULL, NULL, 0, NULL }
52
53 static A(resource_t) resources = ARRAY_INIT;
54
55 #define RESOURCE_KEY                                                           \
56     char rskey[BUFSIZ];                                                        \
57     m_strcpy(rskey, BUFSIZ, ns);                                               \
58     m_strcat(rskey, BUFSIZ, "@@");                                             \
59     m_strcat(rskey, BUFSIZ, key);
60
61 static inline void resource_wipe(resource_t *res)
62 {
63     static const resource_t vr = RESOURCE_INIT;
64     if (res->destructor) {
65         res->destructor(res->data);
66     }
67     p_delete(&res->key);
68     *res = vr;
69 }
70
71 static inline resource_t *resource_find(const char *key, bool create)
72 {
73     foreach (resource_t* res, resources) {
74         if (strcmp(res->key, key) == 0) {
75             return res;
76         }
77     }}
78     if (create) {
79         resource_t res = RESOURCE_INIT;
80         res.key = m_strdup(key);
81         array_add(resources, res);
82         return &array_last(resources);
83     }
84     return NULL;
85 }
86
87 void *resource_get(const char *ns, const char *key)
88 {
89     RESOURCE_KEY;
90     resource_t *entry = resource_find(rskey, false);
91     if (entry == NULL) {
92         return NULL;
93     } else {
94         ++entry->refcount;
95         return entry->data;
96     }
97 }
98
99 bool resource_set(const char *ns, const char *key, void *data,
100                   resource_destructor_t destructor) {
101     RESOURCE_KEY;
102     resource_t *entry = resource_find(rskey, true);
103     if (entry->data != NULL) {
104         if (entry->destructor) {
105             entry->destructor(entry->data);
106         }
107     }
108     entry->refcount  += 1;
109     entry->data       = data;
110     entry->destructor = destructor;
111     return true;
112 }
113
114 void resource_release(const char *ns, const char *key)
115 {
116     RESOURCE_KEY;
117     resource_t *entry = resource_find(rskey, false);
118     if (entry != NULL) {
119         assert(entry->refcount > 0);
120         --entry->refcount;
121     }
122 }
123
124 void resource_garbage_collect(void)
125 {
126     uint32_t used = 0;
127     foreach (resource_t *res, resources) {
128         if (res->key != NULL && res->refcount == 0) {
129             debug("resource gc: %s not referenced anymore", res->key);
130             resource_wipe(res);
131         } else if (res->key != NULL) {
132             debug("resource gc: keeping %s, still %d references",
133                   res->key, res->refcount);
134             if (used < __Ai) {
135                 array_elt(resources, used) = *res;
136             }
137             ++used;
138         }
139     }}
140     debug("resource gc: before %d resources, after %d",
141           array_len(resources), used);
142     array_len(resources) = used;
143 }
144
145 static void resources_exit(void)
146 {
147     array_deep_wipe(resources, resource_wipe);
148 }
149 module_exit(resources_exit);