| dnl Defines the macro CAIRO_CONFIGURE_PTHREAD to find a suitable |
| dnl pthread implementation. There are two levels of pthread conformance |
| dnl we are looking for: |
| dnl |
| dnl a) A minimal level denoted by -DCAIRO_HAS_PTHREAD=1: This level |
| dnl requires mutex and recursive mutexattr support. If possible we try |
| dnl to use weakly linked stubs from libc over the real pthread library. |
| dnl This level is required by the cairo library proper. If the user |
| dnl invokes configure with --enable-pthread=yes or |
| dnl --enable-pthread=always then we avoid trying to use weak stubs. |
| dnl |
| dnl b) A full level denoted by -DCAIRO_HAS_REAL_PTHREAD=1: This level |
| dnl requires full support from a real pthread library, including thread |
| dnl creation, joins, thread attribtues, etc. This level is required by |
| dnl multithreaded applications using cairo, such as the test suite |
| dnl binaries and cairo utilities. |
| dnl |
| dnl Usage: |
| dnl CAIRO_ENABLE(pthread, pthread, <default yes|no|auto|always>, |
| dnl [CAIRO_CONFIGURE_PTHREAD]) |
| dnl |
| dnl This should be invoked near the end of configure.ac so that |
| dnl the pthread specific CFLAGS and LIBS end up at the front |
| dnl of CAIRO_CFLAGS and CAIRO_LIBS -- this helps ensure that we |
| dnl really do get non-weak symbols from the actual pthread library |
| dnl rather than possible stubs in other libraries. |
| dnl |
| dnl The user can override the choices made by |
| dnl CAIRO_CONFIGURE_PTHREAD by using --enable-pthread=yes and |
| dnl giving PTHREAD_CFLAGS and PTHREAD_LIBS to configure. |
| dnl |
| dnl Sets environment variables: |
| dnl use_pthread="yes" | "no (<errmsg>)" |
| dnl have_pthread="yes" | "no (<errmsg)" |
| dnl have_real_pthread="yes" | "no (<errmsg)" |
| dnl pthread_{CFLAGS,LIBS,REQUIRES} |
| dnl real_pthread_{CFLAGS,LIBS} |
| dnl |
| dnl Autoconfigured defines in config.h (conditional): |
| dnl CAIRO_HAS_PTHREAD |
| dnl CAIRO_HAS_REAL_PTHREAD |
| dnl |
| |
| dnl ----------------------------------------------------------------------- |
| dnl A program to test all the pthread features we need to be able to |
| dnl compile libcairo itself. We could test the features independently, |
| dnl but we need all of them anyway. |
| m4_define([libcairo_pthread_program],[dnl |
| #ifndef _GNU_SOURCE |
| #define _GNU_SOURCE /* for PTHREAD_MUTEX_INITIALIZER under linux */ |
| #endif |
| #include <pthread.h> |
| |
| pthread_mutex_t test_mutex_initializer = PTHREAD_MUTEX_INITIALIZER; |
| int test_mutex (void) |
| { |
| int x = 0; |
| pthread_mutex_t mutex; |
| x |= pthread_mutex_init (&mutex, NULL); |
| x |= pthread_mutex_lock (&mutex); |
| x |= pthread_mutex_unlock (&mutex); |
| x |= pthread_mutex_destroy (&mutex); |
| return 0; |
| } |
| |
| int test_mutex_attr (void) |
| { |
| int x = 0; |
| pthread_mutexattr_t attr; |
| pthread_mutex_t mutex; |
| x |= pthread_mutexattr_init (&attr); |
| x |= pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); |
| x |= pthread_mutex_init (&mutex, &attr); |
| x |= pthread_mutex_lock (&mutex); |
| x |= pthread_mutex_unlock (&mutex); |
| x |= pthread_mutex_destroy (&mutex); |
| x |= pthread_mutexattr_destroy (&attr); |
| return x; |
| }]) |
| |
| dnl ----------------------------------------------------------------------- |
| dnl A program to test all the features we want to be able to run the test |
| dnl suite or other thready cairo applications that want real threads. |
| m4_define([testsuite_pthread_program],[dnl |
| libcairo_pthread_program |
| |
| pthread_once_t once_control = PTHREAD_ONCE_INIT; |
| void test_once_init (void) {} |
| int test_once (void) |
| { |
| return pthread_once (&once_control, test_once_init); |
| } |
| |
| pthread_key_t test_specific_key; |
| int test_specific (void) |
| { |
| int x = 0; |
| x |= pthread_key_create (&test_specific_key, NULL); |
| x |= pthread_setspecific (test_specific_key, NULL); |
| x |= pthread_getspecific (test_specific_key) != NULL; |
| return x; |
| } |
| |
| void cleaner (void *arg) { (void)arg; } |
| |
| void * |
| test_thread_main (void *arg) |
| { |
| pthread_cleanup_push (cleaner, arg); |
| pthread_exit (arg); |
| pthread_cleanup_pop (1); |
| return arg; |
| } |
| |
| int |
| test_threads (void) |
| { |
| int x = 0; |
| pthread_t thread; |
| pthread_attr_t attr; |
| void *arg = NULL; |
| x |= pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); |
| x |= pthread_create (&thread, &attr, test_thread_main, arg); |
| x |= pthread_equal (pthread_self(), thread); |
| x |= pthread_join (thread, &arg); |
| x |= pthread_attr_destroy (&attr); |
| return x; |
| }]) |
| |
| dnl ----------------------------------------------------------------------- |
| |
| dnl CAIRO_CHECK_PTHREAD(tag, cflags, libs, program, true-action, false-action) |
| dnl Set <tag>_{CFLAGS,LIBS} to {<cflags>,<libs>} if we can compile and link |
| dnl <program> with the given flags and libs. Execute <true-action> on |
| dnl success and <false-action> on failure. |
| AC_DEFUN([CAIRO_CHECK_PTHREAD],[dnl |
| CAIRO_CC_TRY_LINK_WITH_ENV_SILENT( |
| [CFLAGS="$CFLAGS $2"; |
| LIBS="$LIBS $3"], |
| [$4], |
| [$1_CFLAGS="$2"; |
| $1_LIBS="$3"; |
| $5], |
| [$1_CFLAGS=""; |
| $1_LIBS=""; |
| $6]) |
| ]) |
| |
| dnl CAIRO_CONFIGURE_PTHREADS(): Look for pthreads. |
| dnl |
| dnl If the user specifies PTHREAD_CFLAGS and PTHREAD_LIBS then we use |
| dnl those. Otherwise we try CFLAGS=-D_REENTRANT and LIBS=-lpthread for |
| dnl full pthread support, and look for stubs in libc for the minimal |
| dnl pthread support. |
| dnl |
| dnl CFLAGS=-D_REENTRANT LIBS=-lpthread has been tested to work on: |
| dnl |
| dnl Solaris 9 (5.9) Sun C 5.8 Patch 121015-04 2007/01/10 |
| dnl OpenSolaris (5.11) Sun C 5.9 Patch 124868-08 2008/11/25 |
| dnl OpenSolaris (5.11) clang version 1.1 (trunk 90017) |
| dnl Tru64/OSF1 V5.1 Compaq C V6.5-003 |
| dnl Mac OS X 10.5.5 gcc 4.0.1 (Apple Inc. build 5465) |
| dnl Mac OS X 10.6 gcc 4.2.1 (Apple Inc. build 5659) |
| dnl FreeBSD 7.2 gcc 4.2 |
| dnl OpenBSD 4.5 gcc 3.3.5 (propolice) |
| dnl Debian Linux (Etch) gcc 4.3 |
| dnl |
| dnl Thread support is also in various libcs directly, so often using no |
| dnl flags at all works as well, but unfortunately Solaris 9 has |
| dnl practically _all_ of libpthread stubbed out in libc, so we cannot |
| dnl distinguish between a working libpthread and a stubbed out one by a |
| dnl link-only test. |
| dnl |
| dnl We also explicitly do not link to pthread-stubs or whatever other |
| dnl third-party stubs library, since that forces cairo clients to be |
| dnl extra careful when giving both libcairo and libpthread on the |
| dnl command line: the user would have to use "-lpthread -lcairo" rather |
| dnl than the more common "-lcairo -lpthread" to not accidentally use |
| dnl stubs pulled in by libcairo everywhere in the application. We |
| dnl might also need to have a way to teach pkg-config about library |
| dnl ordering constraints which aren't actual dependencies, and at this |
| dnl point it just starts doing my head in. |
| dnl |
| dnl If your unix-like doesn't work with the secret handshake |
| dnl -D_REENTRANT -lpthread and you can actually compile the rest of |
| dnl cairo just fine otherwise, please take a moment complain loudly |
| dnl to the cairo mailing list! |
| dnl |
| AC_DEFUN([CAIRO_CONFIGURE_PTHREAD],[dnl |
| dnl Try to use the user's PTHREAD_LIBS/CFLAGS |
| dnl if they're available. |
| if test "x$PTHREAD_CFLAGS" = "x"; then |
| PTHREAD_CFLAGS="-D_REENTRANT" |
| fi |
| if test "x$PTHREAD_LIBS" = "x"; then |
| PTHREAD_LIBS="-lpthread" |
| fi |
| |
| dnl First try to find the real pthreads. |
| CAIRO_CHECK_PTHREAD( |
| [real_pthread], [$PTHREAD_CFLAGS], [$PTHREAD_LIBS], |
| [testsuite_pthread_program], |
| [have_real_pthread=yes], |
| [have_real_pthread=no]) |
| if test "x$have_real_pthread" != "xyes"; then |
| dnl Give -pthread a go. |
| CAIRO_CHECK_PTHREAD( |
| [real_pthread], [-pthread], [], |
| [testsuite_pthread_program], |
| [have_real_pthread=yes], |
| [have_real_pthread="no (can't link with -lpthread or -pthread)"]) |
| fi |
| PTHREAD_CFLAGS= |
| PTHREAD_LIBS= |
| |
| dnl Check if we can use libc's stubs in libcairo. |
| dnl Only do this if the user hasn't explicitly enabled |
| dnl pthreads, but is relying on automatic configuration. |
| have_pthread="no" |
| if test "x$enable_pthread" != "xyes"; then |
| CAIRO_CHECK_PTHREAD( |
| [pthread], [-D_REENTRANT], [], |
| [libcairo_pthread_program], |
| [have_pthread=yes], |
| []) |
| fi |
| |
| dnl Default to using the real pthreads for libcairo. |
| if test "x$have_pthread" != "xyes"; then |
| have_pthread="$have_real_pthread"; |
| pthread_CFLAGS="$real_pthread_CFLAGS"; |
| pthread_LIBS="$real_pthread_LIBS"; |
| fi |
| |
| dnl Tell autoconf about the results. |
| if test "x$have_real_pthread" = "xyes"; then |
| AC_DEFINE([CAIRO_HAS_REAL_PTHREAD], 1, |
| [Define to 1 if we have full pthread support]) |
| fi |
| if test "x$have_pthread" = "xyes"; then |
| AC_DEFINE([CAIRO_HAS_PTHREAD], 1, |
| [Define to 1 f we have minimal pthread support]) |
| fi |
| |
| dnl Make sure we scored some pthreads. |
| if test "x$enable_pthread" = "xyes" -a "x$have_pthread" != "xyes"; then |
| AC_MSG_ERROR([pthread requested but not found]) |
| fi |
| |
| dnl Set the output variables for CAIRO_ENABLE. |
| use_pthread="$have_pthread" |
| pthread_REQUIRES="" |
| ]) |