handle the race between writing the head and tail of an entry between threads
[imager.git] / context.c
CommitLineData
74315ca9 1#include "imageri.h"
31a13473 2#include <stdio.h>
74315ca9 3
fc02e376
TC
4static im_slot_t slot_count;
5static im_slot_destroy_t *slot_destructors;
6static i_mutex_t slot_mutex;
7
74315ca9
TC
8/*
9=item im_context_new()
10
11Create a new Imager context object.
12
13=cut
14*/
15
16im_context_t
17im_context_new(void) {
cf8c77ae 18 im_context_t ctx = malloc(sizeof(im_context_struct));
74315ca9
TC
19 int i;
20
fc02e376
TC
21 if (!slot_mutex)
22 slot_mutex = i_mutex_new();
23
cf8c77ae
TC
24 if (!ctx)
25 return NULL;
26
74315ca9
TC
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
44d86483
TC
37 ctx->max_width = 0;
38 ctx->max_height = 0;
cf8c77ae 39 ctx->max_bytes = DEF_BYTES_LIMIT;
74315ca9 40
fc02e376
TC
41 ctx->slots = calloc(sizeof(void *), slot_count);
42 if (!ctx->slots) {
43 free(ctx);
44 return NULL;
45 }
46
31a13473
TC
47 ctx->refcount = 1;
48
49#ifdef IMAGER_TRACE_CONTEXT
50 fprintf(stderr, "im_context: created %p\n", ctx);
51#endif
52
fc02e376 53
74315ca9
TC
54 return ctx;
55}
56
57/*
31a13473 58=item im_context_refinc(ctx, where)
abffffed
TC
59X<im_context_refinc API>
60=section Context objects
61=synopsis im_context_refinc(aIMCTX, "a description");
31a13473
TC
62
63Add a new reference to the context.
64
65=cut
66*/
67
68void
69im_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/*
abffffed
TC
79=item im_context_refdec(ctx, where)
80X<im_context_refdec API>
81=section Context objects
82=synopsis im_context_refdec(aIMCTX, "a description");
74315ca9 83
abffffed
TC
84Remove a reference to the context, releasing it if all references have
85been removed.
74315ca9
TC
86
87=cut
88*/
89
90void
31a13473 91im_context_refdec(im_context_t ctx, const char *where) {
74315ca9 92 int i;
fc02e376 93 im_slot_t slot;
74315ca9 94
31a13473
TC
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
fc02e376
TC
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
74315ca9
TC
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
6ee0c41f 119 if (ctx->lg_file && ctx->own_log)
74315ca9
TC
120 fclose(ctx->lg_file);
121#endif
cf8c77ae
TC
122
123 free(ctx);
74315ca9
TC
124}
125
126/*
127=item im_context_clone(ctx)
128
129Clone an Imager context object, returning the result.
130
a6c8996f
TC
131The error stack is not copied from the original context.
132
74315ca9
TC
133=cut
134*/
135
136im_context_t
31a13473 137im_context_clone(im_context_t ctx, const char *where) {
cf8c77ae 138 im_context_t nctx = malloc(sizeof(im_context_struct));
74315ca9
TC
139 int i;
140
cf8c77ae
TC
141 if (!nctx)
142 return NULL;
143
fc02e376
TC
144 nctx->slots = calloc(sizeof(void *), slot_count);
145 if (!nctx->slots) {
146 free(nctx);
147 return NULL;
148 }
149 nctx->slot_alloc = slot_count;
150
a6c8996f 151 nctx->error_sp = IM_ERROR_COUNT-1;
74315ca9 152 for (i = 0; i < IM_ERROR_COUNT; ++i) {
a6c8996f
TC
153 nctx->error_alloc[i] = 0;
154 nctx->error_stack[i].msg = NULL;
74315ca9
TC
155 }
156#ifdef IMAGER_LOG
157 nctx->log_level = ctx->log_level;
158 if (ctx->lg_file) {
6ee0c41f
TC
159 if (ctx->own_log) {
160 int newfd = dup(fileno(ctx->lg_file));
161 nctx->own_log = 1;
162 nctx->lg_file = fdopen(newfd, "w");
163 if (nctx->lg_file)
164 setvbuf(nctx->lg_file, NULL, _IONBF, BUFSIZ);
165 }
166 else {
167 /* stderr */
168 nctx->lg_file = ctx->lg_file;
169 nctx->own_log = 0;
170 }
74315ca9
TC
171 }
172 else {
44d86483 173 nctx->lg_file = NULL;
74315ca9
TC
174 }
175#endif
44d86483
TC
176 nctx->max_width = ctx->max_width;
177 nctx->max_height = ctx->max_height;
178 nctx->max_bytes = ctx->max_bytes;
fc02e376 179
31a13473 180 nctx->refcount = 1;
74315ca9 181
31a13473
TC
182#ifdef IMAGER_TRACE_CONTEXT
183 fprintf(stderr, "im_context:%s: cloned %p to %p\n", where, ctx, nctx);
184#endif
185
186 return nctx;
74315ca9 187}
fc02e376
TC
188
189/*
190=item im_context_slot_new(destructor)
191
192Allocate a new context-local-storage slot.
193
194=cut
195*/
196
197im_slot_t
198im_context_slot_new(im_slot_destroy_t destructor) {
199 im_slot_t new_slot;
200 im_slot_destroy_t *new_destructors;
201 if (!slot_mutex)
202 slot_mutex = i_mutex_new();
203
204 i_mutex_lock(slot_mutex);
205
206 new_slot = slot_count++;
207 new_destructors = realloc(slot_destructors, sizeof(void *) * slot_count);
208 if (!new_destructors)
209 i_fatal(1, "Cannot allocate memory for slot destructors");
210 slot_destructors = new_destructors;
211
212 slot_destructors[new_slot] = destructor;
213
214 i_mutex_unlock(slot_mutex);
215
216 return new_slot;
217}
218
219/*
220=item im_context_slot_set(slot, value)
221
222Set the value of a slot.
223
224Returns true on success.
225
226Aborts if the slot supplied is invalid.
227
228If reallocation of slot storage fails, returns false.
229
230=cut
231*/
232
233int
234im_context_slot_set(im_context_t ctx, im_slot_t slot, void *value) {
235 if (slot < 0 || slot >= slot_count) {
236 fprintf(stderr, "Invalid slot %d (valid 0 - %d)\n",
237 (int)slot, (int)slot_count-1);
238 abort();
239 }
240
241 if (slot >= ctx->slot_alloc) {
242 ssize_t i;
243 size_t new_alloc = slot_count;
244 void **new_slots = realloc(ctx->slots, sizeof(void *) * new_alloc);
245
246 if (!new_slots)
247 return 0;
248
249 for (i = ctx->slot_alloc; i < new_alloc; ++i)
250 new_slots[i] = NULL;
251
252 ctx->slots = new_slots;
253 ctx->slot_alloc = new_alloc;
254 }
255
256 ctx->slots[slot] = value;
257
258 return 1;
259}
260
261/*
262=item im_context_slot_get(ctx, slot)
263
264Retrieve the value previously stored in the given slot of the context
265object.
266
267=cut
268*/
269
270void *
271im_context_slot_get(im_context_t ctx, im_slot_t slot) {
272 if (slot < 0 || slot >= slot_count) {
273 fprintf(stderr, "Invalid slot %d (valid 0 - %d)\n",
274 (int)slot, (int)slot_count-1);
275 abort();
276 }
277
278 if (slot >= ctx->slot_alloc)
279 return NULL;
280
281 return ctx->slots[slot];
282}