From: Tony Cook Date: Sat, 25 Aug 2012 01:44:36 +0000 (+1000) Subject: add mutex functions to the API X-Git-Tag: v0.93~33^2~19 X-Git-Url: http://git.imager.perl.org/imager.git/commitdiff_plain/12bb8239ed0db89b24912e0c7ed32b0cde004406 add mutex functions to the API --- diff --git a/MANIFEST b/MANIFEST index f706941b..9880063c 100644 --- a/MANIFEST +++ b/MANIFEST @@ -216,6 +216,9 @@ MANIFEST MANIFEST.SKIP map.c maskimg.c +mutexnull.c +mutexpthr.c +mutexwin.c palimg.c paste.im plug.h diff --git a/Makefile.PL b/Makefile.PL index a3ab1d45..8513bf3c 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -169,6 +169,25 @@ my @objs = qw(Imager.o context.o draw.o polygon.o image.o io.o iolayer.o 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"; diff --git a/imager.h b/imager.h index 0d6523f6..6d003bbd 100644 --- a/imager.h +++ b/imager.h @@ -389,6 +389,12 @@ extern im_context_t im_context_clone(im_context_t ctx, const char *where); 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 diff --git a/imdatatypes.h b/imdatatypes.h index 32c92d14..af55f908 100644 --- a/imdatatypes.h +++ b/imdatatypes.h @@ -553,6 +553,18 @@ typedef enum { ic_color } i_combine_t; +/* +=item i_mutex_t +X +=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. diff --git a/imext.c b/imext.c index 24aad642..4c23d916 100644 --- a/imext.c +++ b/imext.c @@ -161,7 +161,11 @@ im_ext_funcs imager_function_table = 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 diff --git a/imext.h b/imext.h index 3f08bd99..131dd1fa 100644 --- a/imext.h +++ b/imext.h @@ -227,6 +227,11 @@ extern im_ext_funcs *imager_function_ext_table; #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 diff --git a/imexttypes.h b/imexttypes.h index 6bdc35ee..8ec8d5c9 100644 --- a/imexttypes.h +++ b/imexttypes.h @@ -228,6 +228,11 @@ typedef struct { 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_ext_funcs; #define PERL_FUNCTION_TABLE_NAME "Imager::__ext_func_table" diff --git a/lib/Imager/API.pod b/lib/Imager/API.pod index 703eb121..7cb5d25b 100644 --- a/lib/Imager/API.pod +++ b/lib/Imager/API.pod @@ -412,6 +412,31 @@ This can be used to define your own local context macro: ... } +=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_create(); + +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 diff --git a/lib/Imager/APIRef.pod b/lib/Imager/APIRef.pod index 8949d460..1f61bb14 100644 --- a/lib/Imager/APIRef.pod +++ b/lib/Imager/APIRef.pod @@ -109,6 +109,12 @@ Imager::APIRef - Imager's C API - reference. # 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 @@ -1876,6 +1882,58 @@ This is an internal function called by the mm_log() macro. 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 @@ -2210,6 +2268,31 @@ Returns ~0UL on failure. =for comment From: File io.c +=item im_context_refdec(ctx, where) +X +=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 +=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); @@ -2251,14 +2334,6 @@ will change: =item * -B - -=item * - -B - -=item * - B =item * diff --git a/mutexnull.c b/mutexnull.c new file mode 100644 index 00000000..ef39ca5c --- /dev/null +++ b/mutexnull.c @@ -0,0 +1,37 @@ +/* + dummy mutexes, for non-threaded builds +*/ + +#include "imageri.h" + +#include + +/* 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; +} diff --git a/mutexpthr.c b/mutexpthr.c new file mode 100644 index 00000000..709f02fd --- /dev/null +++ b/mutexpthr.c @@ -0,0 +1,42 @@ +/* + pthreads mutexes +*/ + +#include "imageri.h" + +#include +#include + +/* 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); +} diff --git a/mutexwin.c b/mutexwin.c new file mode 100644 index 00000000..d4726e2a --- /dev/null +++ b/mutexwin.c @@ -0,0 +1,92 @@ +/* +=head1 NAME + +mutex.c - Imager's mutex API. + +=head1 FUNCTIONS + +=over + +=cut +*/ + +#include "imageri.h" + +#include + +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)); +} + diff --git a/t/t82inline.t b/t/t82inline.t index 92e995db..ff0a216e 100644 --- a/t/t82inline.t +++ b/t/t82inline.t @@ -19,7 +19,7 @@ plan skip_all => "perl 5.005_04, 5.005_05 too buggy" -d "testout" or mkdir "testout"; -plan tests => 115; +plan tests => 116; require Inline; Inline->import(with => 'Imager'); Inline->import("FORCE"); # force rebuild @@ -410,6 +410,16 @@ raw_psampf(Imager im, int chan_count) { 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); +} + EOS my $im = Imager->new(xsize=>50, ysize=>50); @@ -626,6 +636,8 @@ for my $bits (8, 16) { 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); diff --git a/t/x20spell.t b/t/x20spell.t index 9c9928aa..d7368b95 100644 --- a/t/x20spell.t +++ b/t/x20spell.t @@ -47,6 +47,7 @@ infix invocant metadata multi-threaded +mutex paletted postfix preload