4 static volatile im_slot_t slot_count = 1;
5 static im_slot_destroy_t *volatile slot_destructors;
6 static volatile i_mutex_t slot_mutex;
11 Create a new Imager context object.
17 im_context_new(void) {
18 im_context_t ctx = malloc(sizeof(im_context_struct));
22 slot_mutex = i_mutex_new();
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;
39 ctx->max_bytes = DEF_BYTES_LIMIT;
41 ctx->slot_alloc = slot_count;
42 ctx->slots = calloc(sizeof(void *), ctx->slot_alloc);
50 #ifdef IMAGER_TRACE_CONTEXT
51 fprintf(stderr, "im_context: created %p\n", ctx);
59 =item im_context_refinc(ctx, where)
60 X<im_context_refinc API>
61 =section Context objects
62 =synopsis im_context_refinc(aIMCTX, "a description");
64 Add a new reference to the context.
70 im_context_refinc(im_context_t ctx, const char *where) {
73 #ifdef IMAGER_TRACE_CONTEXT
74 fprintf(stderr, "im_context:%s: refinc %p (count now %lu)\n", where,
75 ctx, (unsigned long)ctx->refcount);
80 =item im_context_refdec(ctx, where)
81 X<im_context_refdec API>
82 =section Context objects
83 =synopsis im_context_refdec(aIMCTX, "a description");
85 Remove a reference to the context, releasing it if all references have
92 im_context_refdec(im_context_t ctx, const char *where) {
96 im_assert(ctx->refcount > 0);
100 #ifdef IMAGER_TRACE_CONTEXT
101 fprintf(stderr, "im_context:%s: delete %p (count now %lu)\n", where,
102 ctx, (unsigned long)ctx->refcount);
105 if (ctx->refcount != 0)
108 /* lock here to avoid slot_destructors from being moved under us */
109 i_mutex_lock(slot_mutex);
110 for (slot = 0; slot < ctx->slot_alloc; ++slot) {
111 if (ctx->slots[slot] && slot_destructors[slot])
112 slot_destructors[slot](ctx->slots[slot]);
114 i_mutex_unlock(slot_mutex);
118 for (i = 0; i < IM_ERROR_COUNT; ++i) {
119 if (ctx->error_stack[i].msg)
120 myfree(ctx->error_stack[i].msg);
123 if (ctx->lg_file && ctx->own_log)
124 fclose(ctx->lg_file);
131 =item im_context_clone(ctx)
133 Clone an Imager context object, returning the result.
135 The error stack is not copied from the original context.
141 im_context_clone(im_context_t ctx, const char *where) {
142 im_context_t nctx = malloc(sizeof(im_context_struct));
148 nctx->slot_alloc = slot_count;
149 nctx->slots = calloc(sizeof(void *), nctx->slot_alloc);
155 nctx->error_sp = IM_ERROR_COUNT-1;
156 for (i = 0; i < IM_ERROR_COUNT; ++i) {
157 nctx->error_alloc[i] = 0;
158 nctx->error_stack[i].msg = NULL;
161 nctx->log_level = ctx->log_level;
164 int newfd = dup(fileno(ctx->lg_file));
167 nctx->lg_file = fdopen(newfd, "w");
169 setvbuf(nctx->lg_file, NULL, _IONBF, BUFSIZ);
172 #ifdef IMAGER_TRACE_CONTEXT
173 perror("im_context:failed to clone log");
182 nctx->lg_file = ctx->lg_file;
187 nctx->lg_file = NULL;
190 nctx->max_width = ctx->max_width;
191 nctx->max_height = ctx->max_height;
192 nctx->max_bytes = ctx->max_bytes;
196 #ifdef IMAGER_TRACE_CONTEXT
197 fprintf(stderr, "im_context:%s: cloned %p to %p\n", where, ctx, nctx);
204 =item im_context_slot_new(destructor)
206 Allocate a new context-local-storage slot.
208 C<desctructor> will be called when the context is destroyed if the
209 corresponding slot is non-NULL.
215 im_context_slot_new(im_slot_destroy_t destructor) {
217 im_slot_destroy_t *new_destructors;
219 slot_mutex = i_mutex_new();
221 i_mutex_lock(slot_mutex);
223 new_slot = slot_count++;
224 new_destructors = realloc(slot_destructors, sizeof(void *) * slot_count);
225 if (!new_destructors)
226 i_fatal(1, "Cannot allocate memory for slot destructors");
227 slot_destructors = new_destructors;
229 slot_destructors[new_slot] = destructor;
231 i_mutex_unlock(slot_mutex);
237 =item im_context_slot_set(slot, value)
239 Set the value of a slot.
241 Returns true on success.
243 Aborts if the slot supplied is invalid.
245 If reallocation of slot storage fails, returns false.
251 im_context_slot_set(im_context_t ctx, im_slot_t slot, void *value) {
252 if (slot < 0 || slot >= slot_count) {
253 fprintf(stderr, "Invalid slot %d (valid 0 - %d)\n",
254 (int)slot, (int)slot_count-1);
258 if (slot >= ctx->slot_alloc) {
260 size_t new_alloc = slot_count;
261 void **new_slots = realloc(ctx->slots, sizeof(void *) * new_alloc);
266 for (i = ctx->slot_alloc; i < new_alloc; ++i)
269 ctx->slots = new_slots;
270 ctx->slot_alloc = new_alloc;
273 ctx->slots[slot] = value;
279 =item im_context_slot_get(ctx, slot)
281 Retrieve the value previously stored in the given slot of the context
288 im_context_slot_get(im_context_t ctx, im_slot_t slot) {
289 if (slot < 0 || slot >= slot_count) {
290 fprintf(stderr, "Invalid slot %d (valid 0 - %d)\n",
291 (int)slot, (int)slot_count-1);
295 if (slot >= ctx->slot_alloc)
298 return ctx->slots[slot];