MANIFEST.SKIP
map.c
maskimg.c
+mutexnull.c
+mutexpthr.c
+mutexwin.c
palimg.c
paste.im
plug.h
bmp.o tga.o color.o fills.o imgdouble.o limits.o hlines.o
imext.o scale.o rubthru.o render.o paste.o compose.o flip.o);
+if ($Config{useithreads}) {
+ if ($Config{i_pthread}) {
+ print "POSIX threads\n";
+ push @objs, "mutexpthr.o";
+ }
+ elsif ($^O eq 'MSWin32') {
+ print "Win32 threads\n";
+ push @objs, "mutexwin.o";
+ }
+ else {
+ print "Unsupported threading model\n";
+ push @objs, "mutexnull.o";
+ }
+}
+else {
+ print "No threads\n";
+ push @objs, "mutexnull.o";
+}
+
my @typemaps = qw(typemap.local typemap);
if ($] < 5.008) {
unshift @typemaps, "typemap.oldperl";
extern im_context_t (*im_get_context)(void);
+/* mutex API */
+extern i_mutex_t i_mutex_new(void);
+extern void i_mutex_destroy(i_mutex_t m);
+extern void i_mutex_lock(i_mutex_t m);
+extern void i_mutex_unlock(i_mutex_t m);
+
#include "imio.h"
#endif
ic_color
} i_combine_t;
+/*
+=item i_mutex_t
+X<i_mutex>
+=category mutex
+=synopsis i_mutex_t mutex;
+
+Opaque type for Imager's mutex API.
+
+=cut
+ */
+typedef struct i_mutex_tag *i_mutex_t;
+
/*
describes an axis of a MM font.
Modelled on FT2's FT_MM_Axis.
im_loog,
im_context_refinc,
im_context_refdec,
- im_errors
+ im_errors,
+ i_mutex_new,
+ i_mutex_destroy,
+ i_mutex_lock,
+ i_mutex_unlock
};
/* in general these functions aren't called by Imager internally, but
#define io_slurp(ig, datap) ((im_extt->f_io_slurp)((ig), (datap)))
#define io_glue_destroy(ig) ((im_extt->f_io_glue_destroy)(ig))
+#define i_mutex_new() ((im_extt->f_i_mutex_new)())
+#define i_mutex_destroy(m) ((im_extt->f_i_mutex_destroy)(m))
+#define i_mutex_lock(m) ((im_extt->f_i_mutex_lock)(m))
+#define i_mutex_unlock(m) ((im_extt->f_i_mutex_unlock)(m))
+
#define im_push_errorf (im_extt->f_im_push_errorf)
#ifdef IMAGER_LOG
void (*f_im_context_refinc)(im_context_t, const char *where);
void (*f_im_context_refdec)(im_context_t, const char *where);
i_errmsg *(*f_im_errors)(im_context_t);
+ i_mutex_t (*f_i_mutex_new)(void);
+ void (*f_i_mutex_destroy)(i_mutex_t m);
+ void (*f_i_mutex_lock)(i_mutex_t m);
+ void (*f_i_mutex_unlock)(i_mutex_t m);
+ im_slot_t (*f_im_context_slot_new)(im_slot_destroy_t);
+ int (*f_im_context_slot_set)(im_context_t, im_slot_t, void *);
+ void *(*f_im_context_slot_get)(im_context_t, im_slot_t);
} im_ext_funcs;
#define PERL_FUNCTION_TABLE_NAME "Imager::__ext_func_table"
...
}
+=head1 Mutex Functions
+
+Since some libraries are not thread safe, Imager's API includes some
+simple mutex functions.
+
+To create a mutex:
+
+ i_mutex_t m = i_mutex_new();
+
+To control or lock the mutex:
+
+ i_mutex_lock(m);
+
+To release or unlock the mutex:
+
+ i_mutex_unlock(m);
+
+To free any resources used by the mutex:
+
+ i_mutex_destroy(m);
+
+I most cases where you'd use these functions, your code would create
+the mutex in your BOOT section, then lock and unlock the mutex as
+needed to control access to the library.
+
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
# Logging
+ # Mutex functions
+ i_mutex_t m = i_mutex_new();
+ i_mutex_destroy(m);
+ i_mutex_lock(m);
+ i_mutex_unlock(m);
+
# Paletted images
# Tags
From: File log.c
+=back
+
+=head2 Mutex functions
+
+=over
+
+=item i_mutex_new()
+
+ i_mutex_t m = i_mutex_new();
+
+Create a mutex.
+
+If a critical section cannot be created for whatever reason, Imager
+will abort.
+
+
+=for comment
+From: File mutexwin.c
+
+=item i_mutex_destroy(m)
+
+ i_mutex_destroy(m);
+
+Destroy a mutex.
+
+
+=for comment
+From: File mutexwin.c
+
+=item i_mutex_lock(m)
+
+ i_mutex_lock(m);
+
+Lock the mutex, waiting if another thread has the mutex locked.
+
+
+=for comment
+From: File mutexwin.c
+
+=item i_mutex_unlock(m)
+
+ i_mutex_unlock(m);
+
+Release the mutex.
+
+The behavior of releasing a mutex you don't hold is unspecified.
+
+
+=for comment
+From: File mutexwin.c
+
+
=back
=head2 Paletted images
=for comment
From: File io.c
+=item im_context_refdec(ctx, where)
+X<im_context_refdec API>
+=section Context objects
+
+ im_context_refdec(aIMCTX, "a description");
+
+Remove a reference to the context, releasing it if all references have
+been removed.
+
+
+=for comment
+From: File context.c
+
+=item im_context_refinc(ctx, where)
+X<im_context_refinc API>
+=section Context objects
+
+ im_context_refinc(aIMCTX, "a description");
+
+Add a new reference to the context.
+
+
+=for comment
+From: File context.c
+
=item im_errors(ctx)
i_errmsg *errors = im_errors(aIMCTX);
=item *
-B<im_context_refdec>
-
-=item *
-
-B<im_context_refinc>
-
-=item *
-
B<im_lhead>
=item *
--- /dev/null
+/*
+ dummy mutexes, for non-threaded builds
+*/
+
+#include "imageri.h"
+
+#include <pthread.h>
+
+/* documented in mutexwin.c */
+
+struct i_mutex_tag {
+ int dummy;
+};
+
+i_mutex_t
+i_mutex_new(void) {
+ i_mutex_t m;
+
+ m = mymalloc(sizeof(*m));
+
+ return m;
+}
+
+void
+i_mutex_destroy(i_mutex_t m) {
+ myfree(m);
+}
+
+void
+i_mutex_lock(i_mutex_t m) {
+ (void)m;
+}
+
+void
+i_mutex_unlock(i_mutex_t m) {
+ (void)m;
+}
--- /dev/null
+/*
+ pthreads mutexes
+*/
+
+#include "imageri.h"
+
+#include <pthread.h>
+#include <errno.h>
+
+/* documented in mutexwin.c */
+
+struct i_mutex_tag {
+ pthread_mutex_t mutex;
+};
+
+i_mutex_t
+i_mutex_new(void) {
+ i_mutex_t m;
+
+ m = mymalloc(sizeof(*m));
+ if (pthread_mutex_init(&m->mutex, NULL) != 0) {
+ i_fatal(3, "Error initializing mutex %d", errno);
+ }
+
+ return m;
+}
+
+void
+i_mutex_destroy(i_mutex_t m) {
+ pthread_mutex_destroy(&(m->mutex));
+ myfree(m);
+}
+
+void
+i_mutex_lock(i_mutex_t m) {
+ pthread_mutex_lock(&(m->mutex));
+}
+
+void
+i_mutex_unlock(i_mutex_t m) {
+ pthread_mutex_unlock(&m->mutex);
+}
--- /dev/null
+/*
+=head1 NAME
+
+mutex.c - Imager's mutex API.
+
+=head1 FUNCTIONS
+
+=over
+
+=cut
+*/
+
+#include "imageri.h"
+
+#include <windows.h>
+
+struct i_mutex_tag {
+ CRITICAL_SECTION section;
+};
+
+/*
+=item i_mutex_new()
+=category Mutex functions
+=synopsis i_mutex_t m = i_mutex_new();
+=order 10
+
+Create a mutex.
+
+If a critical section cannot be created for whatever reason, Imager
+will abort.
+
+=cut
+*/
+
+i_mutex_t
+i_mutex_new(void) {
+ i_mutex_t m;
+
+ m = mymalloc(sizeof(*m));
+ InitializeCriticalSection(&(m->section));
+
+ return m;
+}
+
+/*
+=item i_mutex_destroy(m)
+=category Mutex functions
+=synopsis i_mutex_destroy(m);
+
+Destroy a mutex.
+
+=cut
+*/
+
+void
+i_mutex_destroy(i_mutex_t m) {
+ DeleteCriticalSection(&(m->section));
+ myfree(m);
+}
+
+/*
+=item i_mutex_lock(m)
+=category Mutex functions
+=synopsis i_mutex_lock(m);
+
+Lock the mutex, waiting if another thread has the mutex locked.
+
+=cut
+*/
+
+void
+i_mutex_lock(i_mutex_t m) {
+ EnterCriticalSection(&(m->section));
+}
+
+/*
+=item i_mutex_unlock(m)
+=category Mutex functions
+=synopsis i_mutex_unlock(m);
+
+Release the mutex.
+
+The behavior of releasing a mutex you don't hold is unspecified.
+
+=cut
+*/
+
+void
+i_mutex_unlock(i_mutex_t m) {
+ LeaveCriticalSection(&(m->section));
+}
+
-d "testout" or mkdir "testout";
-plan tests => 115;
+plan tests => 116;
require Inline;
Inline->import(with => 'Imager');
Inline->import("FORCE"); # force rebuild
return i_psampf(im, 0, 1, 0, samps, NULL, chan_count);
}
+int
+test_mutex() {
+ i_mutex_t m;
+
+ m = i_mutex_new();
+ i_mutex_lock(m);
+ i_mutex_unlock(m);
+ i_mutex_destroy(m);
+
+ return 1;
+}
+
EOS
my $im = Imager->new(xsize=>50, ysize=>50);
is($im->type, "paletted", "make sure we kept the image type");
}
+ok(test_mutex(), "call mutex APIs");
+
sub _get_error {
my @errors = Imager::i_errors();
return join(": ", map $_->[0], @errors);
invocant
metadata
multi-threaded
+mutex
paletted
postfix
preload