]> git.imager.perl.org - imager.git/blob - context.c
thread-safe T1lib interface
[imager.git] / context.c
1 #include "imageri.h"
2 #include <stdio.h>
3
4 static im_slot_t slot_count;
5 static im_slot_destroy_t *slot_destructors;
6 static i_mutex_t slot_mutex;
7
8 /*
9 =item im_context_new()
10
11 Create a new Imager context object.
12
13 =cut
14 */
15
16 im_context_t
17 im_context_new(void) {
18   im_context_t ctx = malloc(sizeof(im_context_struct));
19   int i;
20
21   if (!slot_mutex)
22     slot_mutex = i_mutex_new();
23
24   if (!ctx)
25     return NULL;
26   
27   ctx->error_sp = IM_ERROR_COUNT-1;
28   for (i = 0; i < IM_ERROR_COUNT; ++i) {
29     ctx->error_alloc[i] = 0;
30     ctx->error_stack[i].msg = NULL;
31     ctx->error_stack[i].code = 0;
32   }
33 #ifdef IMAGER_LOG
34   ctx->log_level = 0;
35   ctx->lg_file = NULL;
36 #endif
37   ctx->max_width = 0;
38   ctx->max_height = 0;
39   ctx->max_bytes = DEF_BYTES_LIMIT;
40
41   ctx->slots = calloc(sizeof(void *), slot_count);
42   if (!ctx->slots) {
43     free(ctx);
44     return NULL;
45   }
46
47   ctx->refcount = 1;
48
49 #ifdef IMAGER_TRACE_CONTEXT
50   fprintf(stderr, "im_context: created %p\n", ctx);
51 #endif
52
53
54   return ctx;
55 }
56
57 /*
58 =item im_context_refinc(ctx, where)
59 X<im_context_refinc API>
60 =section Context objects
61 =synopsis im_context_refinc(aIMCTX, "a description");
62
63 Add a new reference to the context.
64
65 =cut
66 */
67
68 void
69 im_context_refinc(im_context_t ctx, const char *where) {
70   ++ctx->refcount;
71
72 #ifdef IMAGER_TRACE_CONTEXT
73   fprintf(stderr, "im_context:%s: refinc %p (count now %lu)\n", where,
74           ctx, (unsigned long)ctx->refcount);
75 #endif
76 }
77
78 /*
79 =item im_context_refdec(ctx, where)
80 X<im_context_refdec API>
81 =section Context objects
82 =synopsis im_context_refdec(aIMCTX, "a description");
83
84 Remove a reference to the context, releasing it if all references have
85 been removed.
86
87 =cut
88 */
89
90 void
91 im_context_refdec(im_context_t ctx, const char *where) {
92   int i;
93   im_slot_t slot;
94
95   im_assert(ctx->refcount > 0);
96
97   --ctx->refcount;
98
99 #ifdef IMAGER_TRACE_CONTEXT
100   fprintf(stderr, "im_context:%s: delete %p (count now %lu)\n", where,
101           ctx, (unsigned long)ctx->refcount);
102 #endif
103
104   if (ctx->refcount != 0)
105     return;
106
107   for (slot = 0; slot < ctx->slot_alloc; ++slot) {
108     if (ctx->slots[slot] && slot_destructors[slot])
109       slot_destructors[slot](ctx->slots[slot]);
110   }
111
112   free(ctx->slots);
113
114   for (i = 0; i < IM_ERROR_COUNT; ++i) {
115     if (ctx->error_stack[i].msg)
116       myfree(ctx->error_stack[i].msg);
117   }
118 #ifdef IMAGER_LOG
119   if (ctx->lg_file)
120     fclose(ctx->lg_file);
121 #endif
122
123   free(ctx);
124 }
125
126 /*
127 =item im_context_clone(ctx)
128
129 Clone an Imager context object, returning the result.
130
131 =cut
132 */
133
134 im_context_t
135 im_context_clone(im_context_t ctx, const char *where) {
136   im_context_t nctx = malloc(sizeof(im_context_struct));
137   int i;
138
139   if (!nctx)
140     return NULL;
141
142   nctx->slots = calloc(sizeof(void *), slot_count);
143   if (!nctx->slots) {
144     free(nctx);
145     return NULL;
146   }
147   nctx->slot_alloc = slot_count;
148
149   nctx->error_sp = ctx->error_sp;
150   for (i = 0; i < IM_ERROR_COUNT; ++i) {
151     if (ctx->error_stack[i].msg) {
152       size_t sz = ctx->error_alloc[i];
153       nctx->error_alloc[i] = sz;
154       nctx->error_stack[i].msg = mymalloc(sz);
155       memcpy(nctx->error_stack[i].msg, ctx->error_stack[i].msg, sz);
156     }
157     else {
158       nctx->error_alloc[i] = 0;
159       nctx->error_stack[i].msg = NULL;
160     }
161     nctx->error_stack[i].code = ctx->error_stack[i].code;
162   }
163 #ifdef IMAGER_LOG
164   nctx->log_level = ctx->log_level;
165   if (ctx->lg_file) {
166     /* disable buffering, this isn't perfect */
167     setvbuf(ctx->lg_file, NULL, _IONBF, 0);
168
169     /* clone that and disable buffering some more */
170     nctx->lg_file = fdopen(fileno(ctx->lg_file), "a");
171     if (nctx->lg_file)
172       setvbuf(nctx->lg_file, NULL, _IONBF, 0);
173   }
174   else {
175     nctx->lg_file = NULL;
176   }
177 #endif
178   nctx->max_width = ctx->max_width;
179   nctx->max_height = ctx->max_height;
180   nctx->max_bytes = ctx->max_bytes;
181
182   nctx->refcount = 1;
183
184 #ifdef IMAGER_TRACE_CONTEXT
185   fprintf(stderr, "im_context:%s: cloned %p to %p\n", where, ctx, nctx);
186 #endif
187
188   return nctx;
189 }
190
191 /*
192 =item im_context_slot_new(destructor)
193
194 Allocate a new context-local-storage slot.
195
196 =cut
197 */
198
199 im_slot_t
200 im_context_slot_new(im_slot_destroy_t destructor) {
201   im_slot_t new_slot;
202   im_slot_destroy_t *new_destructors;
203   if (!slot_mutex)
204     slot_mutex = i_mutex_new();
205
206   i_mutex_lock(slot_mutex);
207
208   new_slot = slot_count++;
209   new_destructors = realloc(slot_destructors, sizeof(void *) * slot_count);
210   if (!new_destructors)
211     i_fatal(1, "Cannot allocate memory for slot destructors");
212   slot_destructors = new_destructors;
213
214   slot_destructors[new_slot] = destructor;
215
216   i_mutex_unlock(slot_mutex);
217
218   return new_slot;
219 }
220
221 /*
222 =item im_context_slot_set(slot, value)
223
224 Set the value of a slot.
225
226 Returns true on success.
227
228 Aborts if the slot supplied is invalid.
229
230 If reallocation of slot storage fails, returns false.
231
232 =cut
233 */
234
235 int
236 im_context_slot_set(im_context_t ctx, im_slot_t slot, void *value) {
237   if (slot < 0 || slot >= slot_count) {
238     fprintf(stderr, "Invalid slot %d (valid 0 - %d)\n",
239             (int)slot, (int)slot_count-1);
240     abort();
241   }
242
243   if (slot >= ctx->slot_alloc) {
244     ssize_t i;
245     size_t new_alloc = slot_count;
246     void **new_slots = realloc(ctx->slots, sizeof(void *) * new_alloc);
247
248     if (!new_slots)
249       return 0;
250
251     for (i = ctx->slot_alloc; i < new_alloc; ++i)
252       new_slots[i] = NULL;
253
254     ctx->slots = new_slots;
255     ctx->slot_alloc = new_alloc;
256   }
257
258   ctx->slots[slot] = value;
259
260   return 1;
261 }
262
263 /*
264 =item im_context_slot_get(ctx, slot)
265
266 Retrieve the value previously stored in the given slot of the context
267 object.
268
269 =cut
270 */
271
272 void *
273 im_context_slot_get(im_context_t ctx, im_slot_t slot) {
274   if (slot < 0 || slot >= slot_count) {
275     fprintf(stderr, "Invalid slot %d (valid 0 - %d)\n",
276             (int)slot, (int)slot_count-1);
277     abort();
278   }
279
280   if (slot >= ctx->slot_alloc)
281     return NULL;
282
283   return ctx->slots[slot];
284 }