diff --git a/TODO b/TODO index 6d2d2f5f3..39e55fc5e 100644 --- a/TODO +++ b/TODO @@ -112,3 +112,9 @@ * Extend selinux support to other modules * Remove -sat PGP2 compatibility hack + +* gnupg14/mpi: rsa_verify + Is this is optimized for a 160 bit hash? + +* Cleanup m4/ on next gettext update + There is at least one couple of duplicate files: inttype[_-]h.m4. diff --git a/doc/gnupg.texi b/doc/gnupg.texi index 7ba0c0d8a..69771f155 100644 --- a/doc/gnupg.texi +++ b/doc/gnupg.texi @@ -48,7 +48,7 @@ section entitled ``Copying''. @dircategory GNU Utilities @direntry -* gpg: (gnupg). OpenPGP encryption and signing tool. +* gpg2: (gnupg). OpenPGP encryption and signing tool. * gpgsm: (gnupg). S/MIME encryption and signing tool. @end direntry diff --git a/doc/gpgv.texi b/doc/gpgv.texi new file mode 100644 index 000000000..5a9f29754 --- /dev/null +++ b/doc/gpgv.texi @@ -0,0 +1,162 @@ +@c Copyright (C) 2004 Free Software Foundation, Inc. +@c This is part of the GnuPG manual. +@c For copying conditions, see the file GnuPG.texi. + +@c +@c This is included by tools.texi. +@c + +@c Begin GnuPG 1.x specific stuff +@ifset gpgone +@macro gpgvname +gpgv +@end macro +@manpage gpgv.1 +@node gpgv +@section Verify OpenPGP signatures +@ifset manverb +.B gpgv +\- Verify OpenPGP signatures +@end ifset + +@mansect synopsis +@ifset manverb +.B gpgv +.RI [ options ] +.I signed_files +@end ifset +@end ifset +@c End GnuPG 1.x specific stuff + +@c Begin GnuPG 2 specific stuff +@ifclear gpgone +@macro gpgvname +gpgv2 +@end macro +@manpage gpgv2.1 +@node gpgv +@section Verify OpenPGP signatures +@ifset manverb +.B gpgv2 +\- Verify OpenPGP signatures +@end ifset + +@mansect synopsis +@ifset manverb +.B gpgv2 +.RI [ options ] +.I signed_files +@end ifset +@end ifclear +@c End GnuPG 2 specific stuff + + + +@mansect description +@code{@gpgvname} is an OpenPGP signature verification tool. + +This program is actually a stripped down version of @code{gpg} which is +only able to check signatures. It is somewhat smaller than the fully blown +@code{gpg} and uses a different (and simpler) way to check that +the public keys used to make the signature are valid. There are +no configuration files and only a few options are implemented. + +@code{@gpgvname} assumes that all keys in the keyring are trustworthy. +By default it uses a keyring named @file{trustedkeys.gpg} which is +assumed to be in the home directory as defined by GnuPG or set by an +option or an environment variable. An option may be used to specify +another keyring or even multiple keyrings. + +@noindent +@mansect options +@code{@gpgvname} recognizes these options: + +@table @gnupgtabopt + +@item --verbose +@itemx -v +@opindex verbose +Gives more information during processing. If used +twice, the input data is listed in detail. + +@item --quiet +@itemx -q +@opindex quiet +Try to be as quiet as possible. + +@item --keyring @var{file} +@opindex keyring +Add @var{file} to the list of keyrings. +If @var{file} begins with a tilde and a slash, these +are replaced by the HOME directory. If the filename +does not contain a slash, it is assumed to be in the +home-directory ("~/.gnupg" if --homedir is not used). + +@item --status-fd @var{n} +@opindex status-fd +Write special status strings to the file descriptor @var{n}. See the +file DETAILS in the documentation for a listing of them. + +@item --logger-fd @code{n} +@opindex logger-fd +Write log output to file descriptor @code{n} and not to stderr. + +@item --ignore-time-conflict +@opindex ignore-time-conflict +GnuPG normally checks that the timestamps associated with keys and +signatures have plausible values. However, sometimes a signature seems to +be older than the key due to clock problems. This option turns these +checks into warnings. + +@include opt-homedir.texi + +@end table + +@mansect return value + +The program returns 0 if everything was fine, 1 if at least +one signature was bad, and other error codes for fatal errors. + +@mansect examples +@subsection Examples + +@table @asis + +@item @gpgvname @code{pgpfile} +@itemx @gpgvname @code{sigfile} +Verify the signature of the file. The second form +is used for detached signatures, where @code{sigfile} is the detached +signature (either ASCII armored or binary) and are the signed +data; if this is not given the name of the file holding the signed data is +constructed by cutting off the extension (".asc", ".sig" or ".sign") from +@code{sigfile}. + +@end table + +@mansect environment +@subsection Environment + +@table @asis + +@item HOME +Used to locate the default home directory. + +@item GNUPGHOME +If set directory used instead of "~/.gnupg". + +@end table + +@mansect files +@subsection FILES + +@table @asis + +@item ~/.gnupg/trustedkeys.gpg +The default keyring with the allowed keys + +@end table + +@mansect see also +@command{gpg2}(1) +@include see-also-note.texi + diff --git a/intl/export.h b/intl/export.h new file mode 100644 index 000000000..b5c47ad5b --- /dev/null +++ b/intl/export.h @@ -0,0 +1,6 @@ + +#if @HAVE_VISIBILITY@ && BUILDING_LIBINTL +#define LIBINTL_DLL_EXPORTED __attribute__((__visibility__("default"))) +#else +#define LIBINTL_DLL_EXPORTED +#endif diff --git a/intl/hash-string.c b/intl/hash-string.c new file mode 100644 index 000000000..3c513f099 --- /dev/null +++ b/intl/hash-string.c @@ -0,0 +1,51 @@ +/* Implements a string hashing function. + Copyright (C) 1995, 1997, 1998, 2000, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +/* Specification. */ +#include "hash-string.h" + + +/* Defines the so called `hashpjw' function by P.J. Weinberger + [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, + 1986, 1987 Bell Telephone Laboratories, Inc.] */ +unsigned long int +__hash_string (const char *str_param) +{ + unsigned long int hval, g; + const char *str = str_param; + + /* Compute the hash value for the given string. */ + hval = 0; + while (*str != '\0') + { + hval <<= 4; + hval += (unsigned char) *str++; + g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4)); + if (g != 0) + { + hval ^= g >> (HASHWORDBITS - 8); + hval ^= g; + } + } + return hval; +} diff --git a/intl/intl-exports.c b/intl/intl-exports.c new file mode 100644 index 000000000..717658994 --- /dev/null +++ b/intl/intl-exports.c @@ -0,0 +1,36 @@ +/* List of exported symbols of libintl on Cygwin. + Copyright (C) 2006 Free Software Foundation, Inc. + Written by Bruno Haible , 2006. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + USA. */ + + /* IMP(x) is a symbol that contains the address of x. */ +#define IMP(x) _imp__##x + + /* Ensure that the variable x is exported from the library, and that a + pseudo-variable IMP(x) is available. */ +#define VARIABLE(x) \ + /* Export x without redefining x. This code was found by compiling a \ + snippet: \ + extern __declspec(dllexport) int x; int x = 42; */ \ + asm (".section .drectve\n"); \ + asm (".ascii \" -export:" #x ",data\"\n"); \ + asm (".data\n"); \ + /* Allocate a pseudo-variable IMP(x). */ \ + extern int x; \ + void * IMP(x) = &x; + +VARIABLE(libintl_version) diff --git a/intl/langprefs.c b/intl/langprefs.c new file mode 100644 index 000000000..5436040f9 --- /dev/null +++ b/intl/langprefs.c @@ -0,0 +1,130 @@ +/* Determine the user's language preferences. + Copyright (C) 2004-2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + USA. */ + +/* Written by Bruno Haible . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#if HAVE_CFPREFERENCESCOPYAPPVALUE +# include +# include +# include +# include +# include +extern void _nl_locale_name_canonicalize (char *name); +#endif + +/* Determine the user's language preferences, as a colon separated list of + locale names in XPG syntax + language[_territory[.codeset]][@modifier] + The result must not be freed; it is statically allocated. + The LANGUAGE environment variable does not need to be considered; it is + already taken into account by the caller. */ + +const char * +_nl_language_preferences_default (void) +{ +#if HAVE_CFPREFERENCESCOPYAPPVALUE /* MacOS X 10.2 or newer */ + { + /* Cache the preferences list, since CoreFoundation calls are expensive. */ + static const char *cached_languages; + static int cache_initialized; + + if (!cache_initialized) + { + CFTypeRef preferences = + CFPreferencesCopyAppValue (CFSTR ("AppleLanguages"), + kCFPreferencesCurrentApplication); + if (preferences != NULL + && CFGetTypeID (preferences) == CFArrayGetTypeID ()) + { + CFArrayRef prefArray = (CFArrayRef)preferences; + int n = CFArrayGetCount (prefArray); + char buf[256]; + size_t size = 0; + int i; + + for (i = 0; i < n; i++) + { + CFTypeRef element = CFArrayGetValueAtIndex (prefArray, i); + if (element != NULL + && CFGetTypeID (element) == CFStringGetTypeID () + && CFStringGetCString ((CFStringRef)element, + buf, sizeof (buf), + kCFStringEncodingASCII)) + { + _nl_locale_name_canonicalize (buf); + size += strlen (buf) + 1; + /* Most GNU programs use msgids in English and don't ship + an en.mo message catalog. Therefore when we see "en" + in the preferences list, arrange for gettext() to + return the msgid, and ignore all further elements of + the preferences list. */ + if (strcmp (buf, "en") == 0) + break; + } + else + break; + } + if (size > 0) + { + char *languages = (char *) malloc (size); + + if (languages != NULL) + { + char *p = languages; + + for (i = 0; i < n; i++) + { + CFTypeRef element = + CFArrayGetValueAtIndex (prefArray, i); + if (element != NULL + && CFGetTypeID (element) == CFStringGetTypeID () + && CFStringGetCString ((CFStringRef)element, + buf, sizeof (buf), + kCFStringEncodingASCII)) + { + _nl_locale_name_canonicalize (buf); + strcpy (p, buf); + p += strlen (buf); + *p++ = ':'; + if (strcmp (buf, "en") == 0) + break; + } + else + break; + } + *--p = '\0'; + + cached_languages = languages; + } + } + } + cache_initialized = 1; + } + if (cached_languages != NULL) + return cached_languages; + } +#endif + + return NULL; +} diff --git a/intl/lock.c b/intl/lock.c new file mode 100644 index 000000000..a860459d1 --- /dev/null +++ b/intl/lock.c @@ -0,0 +1,924 @@ +/* Locking in multithreaded situations. + Copyright (C) 2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + USA. */ + +/* Written by Bruno Haible , 2005. + Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h, + gthr-win32.h. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "lock.h" + +/* ========================================================================= */ + +#if USE_POSIX_THREADS + +/* Use the POSIX threads library. */ + +# if PTHREAD_IN_USE_DETECTION_HARD + +/* The function to be executed by a dummy thread. */ +static void * +dummy_thread_func (void *arg) +{ + return arg; +} + +int +glthread_in_use (void) +{ + static int tested; + static int result; /* 1: linked with -lpthread, 0: only with libc */ + + if (!tested) + { + pthread_t thread; + + if (pthread_create (&thread, NULL, dummy_thread_func, NULL) != 0) + /* Thread creation failed. */ + result = 0; + else + { + /* Thread creation works. */ + void *retval; + if (pthread_join (thread, &retval) != 0) + abort (); + result = 1; + } + tested = 1; + } + return result; +} + +# endif + +/* -------------------------- gl_lock_t datatype -------------------------- */ + +/* ------------------------- gl_rwlock_t datatype ------------------------- */ + +# if HAVE_PTHREAD_RWLOCK + +# if !defined PTHREAD_RWLOCK_INITIALIZER + +void +glthread_rwlock_init (gl_rwlock_t *lock) +{ + if (pthread_rwlock_init (&lock->rwlock, NULL) != 0) + abort (); + lock->initialized = 1; +} + +void +glthread_rwlock_rdlock (gl_rwlock_t *lock) +{ + if (!lock->initialized) + { + if (pthread_mutex_lock (&lock->guard) != 0) + abort (); + if (!lock->initialized) + glthread_rwlock_init (lock); + if (pthread_mutex_unlock (&lock->guard) != 0) + abort (); + } + if (pthread_rwlock_rdlock (&lock->rwlock) != 0) + abort (); +} + +void +glthread_rwlock_wrlock (gl_rwlock_t *lock) +{ + if (!lock->initialized) + { + if (pthread_mutex_lock (&lock->guard) != 0) + abort (); + if (!lock->initialized) + glthread_rwlock_init (lock); + if (pthread_mutex_unlock (&lock->guard) != 0) + abort (); + } + if (pthread_rwlock_wrlock (&lock->rwlock) != 0) + abort (); +} + +void +glthread_rwlock_unlock (gl_rwlock_t *lock) +{ + if (!lock->initialized) + abort (); + if (pthread_rwlock_unlock (&lock->rwlock) != 0) + abort (); +} + +void +glthread_rwlock_destroy (gl_rwlock_t *lock) +{ + if (!lock->initialized) + abort (); + if (pthread_rwlock_destroy (&lock->rwlock) != 0) + abort (); + lock->initialized = 0; +} + +# endif + +# else + +void +glthread_rwlock_init (gl_rwlock_t *lock) +{ + if (pthread_mutex_init (&lock->lock, NULL) != 0) + abort (); + if (pthread_cond_init (&lock->waiting_readers, NULL) != 0) + abort (); + if (pthread_cond_init (&lock->waiting_writers, NULL) != 0) + abort (); + lock->waiting_writers_count = 0; + lock->runcount = 0; +} + +void +glthread_rwlock_rdlock (gl_rwlock_t *lock) +{ + if (pthread_mutex_lock (&lock->lock) != 0) + abort (); + /* Test whether only readers are currently running, and whether the runcount + field will not overflow. */ + /* POSIX says: "It is implementation-defined whether the calling thread + acquires the lock when a writer does not hold the lock and there are + writers blocked on the lock." Let's say, no: give the writers a higher + priority. */ + while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0)) + { + /* This thread has to wait for a while. Enqueue it among the + waiting_readers. */ + if (pthread_cond_wait (&lock->waiting_readers, &lock->lock) != 0) + abort (); + } + lock->runcount++; + if (pthread_mutex_unlock (&lock->lock) != 0) + abort (); +} + +void +glthread_rwlock_wrlock (gl_rwlock_t *lock) +{ + if (pthread_mutex_lock (&lock->lock) != 0) + abort (); + /* Test whether no readers or writers are currently running. */ + while (!(lock->runcount == 0)) + { + /* This thread has to wait for a while. Enqueue it among the + waiting_writers. */ + lock->waiting_writers_count++; + if (pthread_cond_wait (&lock->waiting_writers, &lock->lock) != 0) + abort (); + lock->waiting_writers_count--; + } + lock->runcount--; /* runcount becomes -1 */ + if (pthread_mutex_unlock (&lock->lock) != 0) + abort (); +} + +void +glthread_rwlock_unlock (gl_rwlock_t *lock) +{ + if (pthread_mutex_lock (&lock->lock) != 0) + abort (); + if (lock->runcount < 0) + { + /* Drop a writer lock. */ + if (!(lock->runcount == -1)) + abort (); + lock->runcount = 0; + } + else + { + /* Drop a reader lock. */ + if (!(lock->runcount > 0)) + abort (); + lock->runcount--; + } + if (lock->runcount == 0) + { + /* POSIX recommends that "write locks shall take precedence over read + locks", to avoid "writer starvation". */ + if (lock->waiting_writers_count > 0) + { + /* Wake up one of the waiting writers. */ + if (pthread_cond_signal (&lock->waiting_writers) != 0) + abort (); + } + else + { + /* Wake up all waiting readers. */ + if (pthread_cond_broadcast (&lock->waiting_readers) != 0) + abort (); + } + } + if (pthread_mutex_unlock (&lock->lock) != 0) + abort (); +} + +void +glthread_rwlock_destroy (gl_rwlock_t *lock) +{ + if (pthread_mutex_destroy (&lock->lock) != 0) + abort (); + if (pthread_cond_destroy (&lock->waiting_readers) != 0) + abort (); + if (pthread_cond_destroy (&lock->waiting_writers) != 0) + abort (); +} + +# endif + +/* --------------------- gl_recursive_lock_t datatype --------------------- */ + +# if HAVE_PTHREAD_MUTEX_RECURSIVE + +# if !(defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) + +void +glthread_recursive_lock_init (gl_recursive_lock_t *lock) +{ + pthread_mutexattr_t attributes; + + if (pthread_mutexattr_init (&attributes) != 0) + abort (); + if (pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE) != 0) + abort (); + if (pthread_mutex_init (&lock->recmutex, &attributes) != 0) + abort (); + if (pthread_mutexattr_destroy (&attributes) != 0) + abort (); + lock->initialized = 1; +} + +void +glthread_recursive_lock_lock (gl_recursive_lock_t *lock) +{ + if (!lock->initialized) + { + if (pthread_mutex_lock (&lock->guard) != 0) + abort (); + if (!lock->initialized) + glthread_recursive_lock_init (lock); + if (pthread_mutex_unlock (&lock->guard) != 0) + abort (); + } + if (pthread_mutex_lock (&lock->recmutex) != 0) + abort (); +} + +void +glthread_recursive_lock_unlock (gl_recursive_lock_t *lock) +{ + if (!lock->initialized) + abort (); + if (pthread_mutex_unlock (&lock->recmutex) != 0) + abort (); +} + +void +glthread_recursive_lock_destroy (gl_recursive_lock_t *lock) +{ + if (!lock->initialized) + abort (); + if (pthread_mutex_destroy (&lock->recmutex) != 0) + abort (); + lock->initialized = 0; +} + +# endif + +# else + +void +glthread_recursive_lock_init (gl_recursive_lock_t *lock) +{ + if (pthread_mutex_init (&lock->mutex, NULL) != 0) + abort (); + lock->owner = (pthread_t) 0; + lock->depth = 0; +} + +void +glthread_recursive_lock_lock (gl_recursive_lock_t *lock) +{ + pthread_t self = pthread_self (); + if (lock->owner != self) + { + if (pthread_mutex_lock (&lock->mutex) != 0) + abort (); + lock->owner = self; + } + if (++(lock->depth) == 0) /* wraparound? */ + abort (); +} + +void +glthread_recursive_lock_unlock (gl_recursive_lock_t *lock) +{ + if (lock->owner != pthread_self ()) + abort (); + if (lock->depth == 0) + abort (); + if (--(lock->depth) == 0) + { + lock->owner = (pthread_t) 0; + if (pthread_mutex_unlock (&lock->mutex) != 0) + abort (); + } +} + +void +glthread_recursive_lock_destroy (gl_recursive_lock_t *lock) +{ + if (lock->owner != (pthread_t) 0) + abort (); + if (pthread_mutex_destroy (&lock->mutex) != 0) + abort (); +} + +# endif + +/* -------------------------- gl_once_t datatype -------------------------- */ + +static const pthread_once_t fresh_once = PTHREAD_ONCE_INIT; + +int +glthread_once_singlethreaded (pthread_once_t *once_control) +{ + /* We don't know whether pthread_once_t is an integer type, a floating-point + type, a pointer type, or a structure type. */ + char *firstbyte = (char *)once_control; + if (*firstbyte == *(const char *)&fresh_once) + { + /* First time use of once_control. Invert the first byte. */ + *firstbyte = ~ *(const char *)&fresh_once; + return 1; + } + else + return 0; +} + +#endif + +/* ========================================================================= */ + +#if USE_PTH_THREADS + +/* Use the GNU Pth threads library. */ + +/* -------------------------- gl_lock_t datatype -------------------------- */ + +/* ------------------------- gl_rwlock_t datatype ------------------------- */ + +/* --------------------- gl_recursive_lock_t datatype --------------------- */ + +/* -------------------------- gl_once_t datatype -------------------------- */ + +void +glthread_once_call (void *arg) +{ + void (**gl_once_temp_addr) (void) = (void (**) (void)) arg; + void (*initfunction) (void) = *gl_once_temp_addr; + initfunction (); +} + +int +glthread_once_singlethreaded (pth_once_t *once_control) +{ + /* We know that pth_once_t is an integer type. */ + if (*once_control == PTH_ONCE_INIT) + { + /* First time use of once_control. Invert the marker. */ + *once_control = ~ PTH_ONCE_INIT; + return 1; + } + else + return 0; +} + +#endif + +/* ========================================================================= */ + +#if USE_SOLARIS_THREADS + +/* Use the old Solaris threads library. */ + +/* -------------------------- gl_lock_t datatype -------------------------- */ + +/* ------------------------- gl_rwlock_t datatype ------------------------- */ + +/* --------------------- gl_recursive_lock_t datatype --------------------- */ + +void +glthread_recursive_lock_init (gl_recursive_lock_t *lock) +{ + if (mutex_init (&lock->mutex, USYNC_THREAD, NULL) != 0) + abort (); + lock->owner = (thread_t) 0; + lock->depth = 0; +} + +void +glthread_recursive_lock_lock (gl_recursive_lock_t *lock) +{ + thread_t self = thr_self (); + if (lock->owner != self) + { + if (mutex_lock (&lock->mutex) != 0) + abort (); + lock->owner = self; + } + if (++(lock->depth) == 0) /* wraparound? */ + abort (); +} + +void +glthread_recursive_lock_unlock (gl_recursive_lock_t *lock) +{ + if (lock->owner != thr_self ()) + abort (); + if (lock->depth == 0) + abort (); + if (--(lock->depth) == 0) + { + lock->owner = (thread_t) 0; + if (mutex_unlock (&lock->mutex) != 0) + abort (); + } +} + +void +glthread_recursive_lock_destroy (gl_recursive_lock_t *lock) +{ + if (lock->owner != (thread_t) 0) + abort (); + if (mutex_destroy (&lock->mutex) != 0) + abort (); +} + +/* -------------------------- gl_once_t datatype -------------------------- */ + +void +glthread_once (gl_once_t *once_control, void (*initfunction) (void)) +{ + if (!once_control->inited) + { + /* Use the mutex to guarantee that if another thread is already calling + the initfunction, this thread waits until it's finished. */ + if (mutex_lock (&once_control->mutex) != 0) + abort (); + if (!once_control->inited) + { + once_control->inited = 1; + initfunction (); + } + if (mutex_unlock (&once_control->mutex) != 0) + abort (); + } +} + +int +glthread_once_singlethreaded (gl_once_t *once_control) +{ + /* We know that gl_once_t contains an integer type. */ + if (!once_control->inited) + { + /* First time use of once_control. Invert the marker. */ + once_control->inited = ~ 0; + return 1; + } + else + return 0; +} + +#endif + +/* ========================================================================= */ + +#if USE_WIN32_THREADS + +/* -------------------------- gl_lock_t datatype -------------------------- */ + +void +glthread_lock_init (gl_lock_t *lock) +{ + InitializeCriticalSection (&lock->lock); + lock->guard.done = 1; +} + +void +glthread_lock_lock (gl_lock_t *lock) +{ + if (!lock->guard.done) + { + if (InterlockedIncrement (&lock->guard.started) == 0) + /* This thread is the first one to need this lock. Initialize it. */ + glthread_lock_init (lock); + else + /* Yield the CPU while waiting for another thread to finish + initializing this lock. */ + while (!lock->guard.done) + Sleep (0); + } + EnterCriticalSection (&lock->lock); +} + +void +glthread_lock_unlock (gl_lock_t *lock) +{ + if (!lock->guard.done) + abort (); + LeaveCriticalSection (&lock->lock); +} + +void +glthread_lock_destroy (gl_lock_t *lock) +{ + if (!lock->guard.done) + abort (); + DeleteCriticalSection (&lock->lock); + lock->guard.done = 0; +} + +/* ------------------------- gl_rwlock_t datatype ------------------------- */ + +static inline void +gl_waitqueue_init (gl_waitqueue_t *wq) +{ + wq->array = NULL; + wq->count = 0; + wq->alloc = 0; + wq->offset = 0; +} + +/* Enqueues the current thread, represented by an event, in a wait queue. + Returns INVALID_HANDLE_VALUE if an allocation failure occurs. */ +static HANDLE +gl_waitqueue_add (gl_waitqueue_t *wq) +{ + HANDLE event; + unsigned int index; + + if (wq->count == wq->alloc) + { + unsigned int new_alloc = 2 * wq->alloc + 1; + HANDLE *new_array = + (HANDLE *) realloc (wq->array, new_alloc * sizeof (HANDLE)); + if (new_array == NULL) + /* No more memory. */ + return INVALID_HANDLE_VALUE; + /* Now is a good opportunity to rotate the array so that its contents + starts at offset 0. */ + if (wq->offset > 0) + { + unsigned int old_count = wq->count; + unsigned int old_alloc = wq->alloc; + unsigned int old_offset = wq->offset; + unsigned int i; + if (old_offset + old_count > old_alloc) + { + unsigned int limit = old_offset + old_count - old_alloc; + for (i = 0; i < limit; i++) + new_array[old_alloc + i] = new_array[i]; + } + for (i = 0; i < old_count; i++) + new_array[i] = new_array[old_offset + i]; + wq->offset = 0; + } + wq->array = new_array; + wq->alloc = new_alloc; + } + event = CreateEvent (NULL, TRUE, FALSE, NULL); + if (event == INVALID_HANDLE_VALUE) + /* No way to allocate an event. */ + return INVALID_HANDLE_VALUE; + index = wq->offset + wq->count; + if (index >= wq->alloc) + index -= wq->alloc; + wq->array[index] = event; + wq->count++; + return event; +} + +/* Notifies the first thread from a wait queue and dequeues it. */ +static inline void +gl_waitqueue_notify_first (gl_waitqueue_t *wq) +{ + SetEvent (wq->array[wq->offset + 0]); + wq->offset++; + wq->count--; + if (wq->count == 0 || wq->offset == wq->alloc) + wq->offset = 0; +} + +/* Notifies all threads from a wait queue and dequeues them all. */ +static inline void +gl_waitqueue_notify_all (gl_waitqueue_t *wq) +{ + unsigned int i; + + for (i = 0; i < wq->count; i++) + { + unsigned int index = wq->offset + i; + if (index >= wq->alloc) + index -= wq->alloc; + SetEvent (wq->array[index]); + } + wq->count = 0; + wq->offset = 0; +} + +void +glthread_rwlock_init (gl_rwlock_t *lock) +{ + InitializeCriticalSection (&lock->lock); + gl_waitqueue_init (&lock->waiting_readers); + gl_waitqueue_init (&lock->waiting_writers); + lock->runcount = 0; + lock->guard.done = 1; +} + +void +glthread_rwlock_rdlock (gl_rwlock_t *lock) +{ + if (!lock->guard.done) + { + if (InterlockedIncrement (&lock->guard.started) == 0) + /* This thread is the first one to need this lock. Initialize it. */ + glthread_rwlock_init (lock); + else + /* Yield the CPU while waiting for another thread to finish + initializing this lock. */ + while (!lock->guard.done) + Sleep (0); + } + EnterCriticalSection (&lock->lock); + /* Test whether only readers are currently running, and whether the runcount + field will not overflow. */ + if (!(lock->runcount + 1 > 0)) + { + /* This thread has to wait for a while. Enqueue it among the + waiting_readers. */ + HANDLE event = gl_waitqueue_add (&lock->waiting_readers); + if (event != INVALID_HANDLE_VALUE) + { + DWORD result; + LeaveCriticalSection (&lock->lock); + /* Wait until another thread signals this event. */ + result = WaitForSingleObject (event, INFINITE); + if (result == WAIT_FAILED || result == WAIT_TIMEOUT) + abort (); + CloseHandle (event); + /* The thread which signalled the event already did the bookkeeping: + removed us from the waiting_readers, incremented lock->runcount. */ + if (!(lock->runcount > 0)) + abort (); + return; + } + else + { + /* Allocation failure. Weird. */ + do + { + LeaveCriticalSection (&lock->lock); + Sleep (1); + EnterCriticalSection (&lock->lock); + } + while (!(lock->runcount + 1 > 0)); + } + } + lock->runcount++; + LeaveCriticalSection (&lock->lock); +} + +void +glthread_rwlock_wrlock (gl_rwlock_t *lock) +{ + if (!lock->guard.done) + { + if (InterlockedIncrement (&lock->guard.started) == 0) + /* This thread is the first one to need this lock. Initialize it. */ + glthread_rwlock_init (lock); + else + /* Yield the CPU while waiting for another thread to finish + initializing this lock. */ + while (!lock->guard.done) + Sleep (0); + } + EnterCriticalSection (&lock->lock); + /* Test whether no readers or writers are currently running. */ + if (!(lock->runcount == 0)) + { + /* This thread has to wait for a while. Enqueue it among the + waiting_writers. */ + HANDLE event = gl_waitqueue_add (&lock->waiting_writers); + if (event != INVALID_HANDLE_VALUE) + { + DWORD result; + LeaveCriticalSection (&lock->lock); + /* Wait until another thread signals this event. */ + result = WaitForSingleObject (event, INFINITE); + if (result == WAIT_FAILED || result == WAIT_TIMEOUT) + abort (); + CloseHandle (event); + /* The thread which signalled the event already did the bookkeeping: + removed us from the waiting_writers, set lock->runcount = -1. */ + if (!(lock->runcount == -1)) + abort (); + return; + } + else + { + /* Allocation failure. Weird. */ + do + { + LeaveCriticalSection (&lock->lock); + Sleep (1); + EnterCriticalSection (&lock->lock); + } + while (!(lock->runcount == 0)); + } + } + lock->runcount--; /* runcount becomes -1 */ + LeaveCriticalSection (&lock->lock); +} + +void +glthread_rwlock_unlock (gl_rwlock_t *lock) +{ + if (!lock->guard.done) + abort (); + EnterCriticalSection (&lock->lock); + if (lock->runcount < 0) + { + /* Drop a writer lock. */ + if (!(lock->runcount == -1)) + abort (); + lock->runcount = 0; + } + else + { + /* Drop a reader lock. */ + if (!(lock->runcount > 0)) + abort (); + lock->runcount--; + } + if (lock->runcount == 0) + { + /* POSIX recommends that "write locks shall take precedence over read + locks", to avoid "writer starvation". */ + if (lock->waiting_writers.count > 0) + { + /* Wake up one of the waiting writers. */ + lock->runcount--; + gl_waitqueue_notify_first (&lock->waiting_writers); + } + else + { + /* Wake up all waiting readers. */ + lock->runcount += lock->waiting_readers.count; + gl_waitqueue_notify_all (&lock->waiting_readers); + } + } + LeaveCriticalSection (&lock->lock); +} + +void +glthread_rwlock_destroy (gl_rwlock_t *lock) +{ + if (!lock->guard.done) + abort (); + if (lock->runcount != 0) + abort (); + DeleteCriticalSection (&lock->lock); + if (lock->waiting_readers.array != NULL) + free (lock->waiting_readers.array); + if (lock->waiting_writers.array != NULL) + free (lock->waiting_writers.array); + lock->guard.done = 0; +} + +/* --------------------- gl_recursive_lock_t datatype --------------------- */ + +void +glthread_recursive_lock_init (gl_recursive_lock_t *lock) +{ + lock->owner = 0; + lock->depth = 0; + InitializeCriticalSection (&lock->lock); + lock->guard.done = 1; +} + +void +glthread_recursive_lock_lock (gl_recursive_lock_t *lock) +{ + if (!lock->guard.done) + { + if (InterlockedIncrement (&lock->guard.started) == 0) + /* This thread is the first one to need this lock. Initialize it. */ + glthread_recursive_lock_init (lock); + else + /* Yield the CPU while waiting for another thread to finish + initializing this lock. */ + while (!lock->guard.done) + Sleep (0); + } + { + DWORD self = GetCurrentThreadId (); + if (lock->owner != self) + { + EnterCriticalSection (&lock->lock); + lock->owner = self; + } + if (++(lock->depth) == 0) /* wraparound? */ + abort (); + } +} + +void +glthread_recursive_lock_unlock (gl_recursive_lock_t *lock) +{ + if (lock->owner != GetCurrentThreadId ()) + abort (); + if (lock->depth == 0) + abort (); + if (--(lock->depth) == 0) + { + lock->owner = 0; + LeaveCriticalSection (&lock->lock); + } +} + +void +glthread_recursive_lock_destroy (gl_recursive_lock_t *lock) +{ + if (lock->owner != 0) + abort (); + DeleteCriticalSection (&lock->lock); + lock->guard.done = 0; +} + +/* -------------------------- gl_once_t datatype -------------------------- */ + +void +glthread_once (gl_once_t *once_control, void (*initfunction) (void)) +{ + if (once_control->inited <= 0) + { + if (InterlockedIncrement (&once_control->started) == 0) + { + /* This thread is the first one to come to this once_control. */ + InitializeCriticalSection (&once_control->lock); + EnterCriticalSection (&once_control->lock); + once_control->inited = 0; + initfunction (); + once_control->inited = 1; + LeaveCriticalSection (&once_control->lock); + } + else + { + /* Undo last operation. */ + InterlockedDecrement (&once_control->started); + /* Some other thread has already started the initialization. + Yield the CPU while waiting for the other thread to finish + initializing and taking the lock. */ + while (once_control->inited < 0) + Sleep (0); + if (once_control->inited <= 0) + { + /* Take the lock. This blocks until the other thread has + finished calling the initfunction. */ + EnterCriticalSection (&once_control->lock); + LeaveCriticalSection (&once_control->lock); + if (!(once_control->inited > 0)) + abort (); + } + } + } +} + +#endif + +/* ========================================================================= */ diff --git a/intl/lock.h b/intl/lock.h new file mode 100644 index 000000000..be99139dc --- /dev/null +++ b/intl/lock.h @@ -0,0 +1,801 @@ +/* Locking in multithreaded situations. + Copyright (C) 2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + USA. */ + +/* Written by Bruno Haible , 2005. + Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h, + gthr-win32.h. */ + +/* This file contains locking primitives for use with a given thread library. + It does not contain primitives for creating threads or for other + synchronization primitives. + + Normal (non-recursive) locks: + Type: gl_lock_t + Declaration: gl_lock_define(extern, name) + Initializer: gl_lock_define_initialized(, name) + Initialization: gl_lock_init (name); + Taking the lock: gl_lock_lock (name); + Releasing the lock: gl_lock_unlock (name); + De-initialization: gl_lock_destroy (name); + + Read-Write (non-recursive) locks: + Type: gl_rwlock_t + Declaration: gl_rwlock_define(extern, name) + Initializer: gl_rwlock_define_initialized(, name) + Initialization: gl_rwlock_init (name); + Taking the lock: gl_rwlock_rdlock (name); + gl_rwlock_wrlock (name); + Releasing the lock: gl_rwlock_unlock (name); + De-initialization: gl_rwlock_destroy (name); + + Recursive locks: + Type: gl_recursive_lock_t + Declaration: gl_recursive_lock_define(extern, name) + Initializer: gl_recursive_lock_define_initialized(, name) + Initialization: gl_recursive_lock_init (name); + Taking the lock: gl_recursive_lock_lock (name); + Releasing the lock: gl_recursive_lock_unlock (name); + De-initialization: gl_recursive_lock_destroy (name); + + Once-only execution: + Type: gl_once_t + Initializer: gl_once_define(extern, name) + Execution: gl_once (name, initfunction); +*/ + + +#ifndef _LOCK_H +#define _LOCK_H + +/* ========================================================================= */ + +#if USE_POSIX_THREADS + +/* Use the POSIX threads library. */ + +# include +# include + +# if PTHREAD_IN_USE_DETECTION_HARD + +/* The pthread_in_use() detection needs to be done at runtime. */ +# define pthread_in_use() \ + glthread_in_use () +extern int glthread_in_use (void); + +# endif + +# if USE_POSIX_THREADS_WEAK + +/* Use weak references to the POSIX threads library. */ + +/* Weak references avoid dragging in external libraries if the other parts + of the program don't use them. Here we use them, because we don't want + every program that uses libintl to depend on libpthread. This assumes + that libpthread would not be loaded after libintl; i.e. if libintl is + loaded first, by an executable that does not depend on libpthread, and + then a module is dynamically loaded that depends on libpthread, libintl + will not be multithread-safe. */ + +/* The way to test at runtime whether libpthread is present is to test + whether a function pointer's value, such as &pthread_mutex_init, is + non-NULL. However, some versions of GCC have a bug through which, in + PIC mode, &foo != NULL always evaluates to true if there is a direct + call to foo(...) in the same function. To avoid this, we test the + address of a function in libpthread that we don't use. */ + +# pragma weak pthread_mutex_init +# pragma weak pthread_mutex_lock +# pragma weak pthread_mutex_unlock +# pragma weak pthread_mutex_destroy +# pragma weak pthread_rwlock_init +# pragma weak pthread_rwlock_rdlock +# pragma weak pthread_rwlock_wrlock +# pragma weak pthread_rwlock_unlock +# pragma weak pthread_rwlock_destroy +# pragma weak pthread_once +# pragma weak pthread_cond_init +# pragma weak pthread_cond_wait +# pragma weak pthread_cond_signal +# pragma weak pthread_cond_broadcast +# pragma weak pthread_cond_destroy +# pragma weak pthread_mutexattr_init +# pragma weak pthread_mutexattr_settype +# pragma weak pthread_mutexattr_destroy +# ifndef pthread_self +# pragma weak pthread_self +# endif + +# if !PTHREAD_IN_USE_DETECTION_HARD +# pragma weak pthread_cancel +# define pthread_in_use() (pthread_cancel != NULL) +# endif + +# else + +# if !PTHREAD_IN_USE_DETECTION_HARD +# define pthread_in_use() 1 +# endif + +# endif + +/* -------------------------- gl_lock_t datatype -------------------------- */ + +typedef pthread_mutex_t gl_lock_t; +# define gl_lock_define(STORAGECLASS, NAME) \ + STORAGECLASS pthread_mutex_t NAME; +# define gl_lock_define_initialized(STORAGECLASS, NAME) \ + STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer; +# define gl_lock_initializer \ + PTHREAD_MUTEX_INITIALIZER +# define gl_lock_init(NAME) \ + if (pthread_in_use () && pthread_mutex_init (&NAME, NULL) != 0) abort () +# define gl_lock_lock(NAME) \ + if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) abort () +# define gl_lock_unlock(NAME) \ + if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) abort () +# define gl_lock_destroy(NAME) \ + if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 0) abort () + +/* ------------------------- gl_rwlock_t datatype ------------------------- */ + +# if HAVE_PTHREAD_RWLOCK + +# ifdef PTHREAD_RWLOCK_INITIALIZER + +typedef pthread_rwlock_t gl_rwlock_t; +# define gl_rwlock_define(STORAGECLASS, NAME) \ + STORAGECLASS pthread_rwlock_t NAME; +# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ + STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer; +# define gl_rwlock_initializer \ + PTHREAD_RWLOCK_INITIALIZER +# define gl_rwlock_init(NAME) \ + if (pthread_in_use () && pthread_rwlock_init (&NAME, NULL) != 0) abort () +# define gl_rwlock_rdlock(NAME) \ + if (pthread_in_use () && pthread_rwlock_rdlock (&NAME) != 0) abort () +# define gl_rwlock_wrlock(NAME) \ + if (pthread_in_use () && pthread_rwlock_wrlock (&NAME) != 0) abort () +# define gl_rwlock_unlock(NAME) \ + if (pthread_in_use () && pthread_rwlock_unlock (&NAME) != 0) abort () +# define gl_rwlock_destroy(NAME) \ + if (pthread_in_use () && pthread_rwlock_destroy (&NAME) != 0) abort () + +# else + +typedef struct + { + int initialized; + pthread_mutex_t guard; /* protects the initialization */ + pthread_rwlock_t rwlock; /* read-write lock */ + } + gl_rwlock_t; +# define gl_rwlock_define(STORAGECLASS, NAME) \ + STORAGECLASS gl_rwlock_t NAME; +# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ + STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer; +# define gl_rwlock_initializer \ + { 0, PTHREAD_MUTEX_INITIALIZER } +# define gl_rwlock_init(NAME) \ + if (pthread_in_use ()) glthread_rwlock_init (&NAME) +# define gl_rwlock_rdlock(NAME) \ + if (pthread_in_use ()) glthread_rwlock_rdlock (&NAME) +# define gl_rwlock_wrlock(NAME) \ + if (pthread_in_use ()) glthread_rwlock_wrlock (&NAME) +# define gl_rwlock_unlock(NAME) \ + if (pthread_in_use ()) glthread_rwlock_unlock (&NAME) +# define gl_rwlock_destroy(NAME) \ + if (pthread_in_use ()) glthread_rwlock_destroy (&NAME) +extern void glthread_rwlock_init (gl_rwlock_t *lock); +extern void glthread_rwlock_rdlock (gl_rwlock_t *lock); +extern void glthread_rwlock_wrlock (gl_rwlock_t *lock); +extern void glthread_rwlock_unlock (gl_rwlock_t *lock); +extern void glthread_rwlock_destroy (gl_rwlock_t *lock); + +# endif + +# else + +typedef struct + { + pthread_mutex_t lock; /* protects the remaining fields */ + pthread_cond_t waiting_readers; /* waiting readers */ + pthread_cond_t waiting_writers; /* waiting writers */ + unsigned int waiting_writers_count; /* number of waiting writers */ + int runcount; /* number of readers running, or -1 when a writer runs */ + } + gl_rwlock_t; +# define gl_rwlock_define(STORAGECLASS, NAME) \ + STORAGECLASS gl_rwlock_t NAME; +# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ + STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer; +# define gl_rwlock_initializer \ + { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 } +# define gl_rwlock_init(NAME) \ + if (pthread_in_use ()) glthread_rwlock_init (&NAME) +# define gl_rwlock_rdlock(NAME) \ + if (pthread_in_use ()) glthread_rwlock_rdlock (&NAME) +# define gl_rwlock_wrlock(NAME) \ + if (pthread_in_use ()) glthread_rwlock_wrlock (&NAME) +# define gl_rwlock_unlock(NAME) \ + if (pthread_in_use ()) glthread_rwlock_unlock (&NAME) +# define gl_rwlock_destroy(NAME) \ + if (pthread_in_use ()) glthread_rwlock_destroy (&NAME) +extern void glthread_rwlock_init (gl_rwlock_t *lock); +extern void glthread_rwlock_rdlock (gl_rwlock_t *lock); +extern void glthread_rwlock_wrlock (gl_rwlock_t *lock); +extern void glthread_rwlock_unlock (gl_rwlock_t *lock); +extern void glthread_rwlock_destroy (gl_rwlock_t *lock); + +# endif + +/* --------------------- gl_recursive_lock_t datatype --------------------- */ + +# if HAVE_PTHREAD_MUTEX_RECURSIVE + +# if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP + +typedef pthread_mutex_t gl_recursive_lock_t; +# define gl_recursive_lock_define(STORAGECLASS, NAME) \ + STORAGECLASS pthread_mutex_t NAME; +# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ + STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer; +# ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER +# define gl_recursive_lock_initializer \ + PTHREAD_RECURSIVE_MUTEX_INITIALIZER +# else +# define gl_recursive_lock_initializer \ + PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP +# endif +# define gl_recursive_lock_init(NAME) \ + if (pthread_in_use () && pthread_mutex_init (&NAME, NULL) != 0) abort () +# define gl_recursive_lock_lock(NAME) \ + if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) abort () +# define gl_recursive_lock_unlock(NAME) \ + if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) abort () +# define gl_recursive_lock_destroy(NAME) \ + if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 0) abort () + +# else + +typedef struct + { + pthread_mutex_t recmutex; /* recursive mutex */ + pthread_mutex_t guard; /* protects the initialization */ + int initialized; + } + gl_recursive_lock_t; +# define gl_recursive_lock_define(STORAGECLASS, NAME) \ + STORAGECLASS gl_recursive_lock_t NAME; +# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ + STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer; +# define gl_recursive_lock_initializer \ + { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 } +# define gl_recursive_lock_init(NAME) \ + if (pthread_in_use ()) glthread_recursive_lock_init (&NAME) +# define gl_recursive_lock_lock(NAME) \ + if (pthread_in_use ()) glthread_recursive_lock_lock (&NAME) +# define gl_recursive_lock_unlock(NAME) \ + if (pthread_in_use ()) glthread_recursive_lock_unlock (&NAME) +# define gl_recursive_lock_destroy(NAME) \ + if (pthread_in_use ()) glthread_recursive_lock_destroy (&NAME) +extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock); +extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock); +extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock); +extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock); + +# endif + +# else + +/* Old versions of POSIX threads on Solaris did not have recursive locks. + We have to implement them ourselves. */ + +typedef struct + { + pthread_mutex_t mutex; + pthread_t owner; + unsigned long depth; + } + gl_recursive_lock_t; +# define gl_recursive_lock_define(STORAGECLASS, NAME) \ + STORAGECLASS gl_recursive_lock_t NAME; +# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ + STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer; +# define gl_recursive_lock_initializer \ + { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 } +# define gl_recursive_lock_init(NAME) \ + if (pthread_in_use ()) glthread_recursive_lock_init (&NAME) +# define gl_recursive_lock_lock(NAME) \ + if (pthread_in_use ()) glthread_recursive_lock_lock (&NAME) +# define gl_recursive_lock_unlock(NAME) \ + if (pthread_in_use ()) glthread_recursive_lock_unlock (&NAME) +# define gl_recursive_lock_destroy(NAME) \ + if (pthread_in_use ()) glthread_recursive_lock_destroy (&NAME) +extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock); +extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock); +extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock); +extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock); + +# endif + +/* -------------------------- gl_once_t datatype -------------------------- */ + +typedef pthread_once_t gl_once_t; +# define gl_once_define(STORAGECLASS, NAME) \ + STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT; +# define gl_once(NAME, INITFUNCTION) \ + do \ + { \ + if (pthread_in_use ()) \ + { \ + if (pthread_once (&NAME, INITFUNCTION) != 0) \ + abort (); \ + } \ + else \ + { \ + if (glthread_once_singlethreaded (&NAME)) \ + INITFUNCTION (); \ + } \ + } \ + while (0) +extern int glthread_once_singlethreaded (pthread_once_t *once_control); + +#endif + +/* ========================================================================= */ + +#if USE_PTH_THREADS + +/* Use the GNU Pth threads library. */ + +# include +# include + +# if USE_PTH_THREADS_WEAK + +/* Use weak references to the GNU Pth threads library. */ + +# pragma weak pth_mutex_init +# pragma weak pth_mutex_acquire +# pragma weak pth_mutex_release +# pragma weak pth_rwlock_init +# pragma weak pth_rwlock_acquire +# pragma weak pth_rwlock_release +# pragma weak pth_once + +# pragma weak pth_cancel +# define pth_in_use() (pth_cancel != NULL) + +# else + +# define pth_in_use() 1 + +# endif + +/* -------------------------- gl_lock_t datatype -------------------------- */ + +typedef pth_mutex_t gl_lock_t; +# define gl_lock_define(STORAGECLASS, NAME) \ + STORAGECLASS pth_mutex_t NAME; +# define gl_lock_define_initialized(STORAGECLASS, NAME) \ + STORAGECLASS pth_mutex_t NAME = gl_lock_initializer; +# define gl_lock_initializer \ + PTH_MUTEX_INIT +# define gl_lock_init(NAME) \ + if (pth_in_use() && !pth_mutex_init (&NAME)) abort () +# define gl_lock_lock(NAME) \ + if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) abort () +# define gl_lock_unlock(NAME) \ + if (pth_in_use() && !pth_mutex_release (&NAME)) abort () +# define gl_lock_destroy(NAME) \ + (void)(&NAME) + +/* ------------------------- gl_rwlock_t datatype ------------------------- */ + +typedef pth_rwlock_t gl_rwlock_t; +# define gl_rwlock_define(STORAGECLASS, NAME) \ + STORAGECLASS pth_rwlock_t NAME; +# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ + STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer; +# define gl_rwlock_initializer \ + PTH_RWLOCK_INIT +# define gl_rwlock_init(NAME) \ + if (pth_in_use() && !pth_rwlock_init (&NAME)) abort () +# define gl_rwlock_rdlock(NAME) \ + if (pth_in_use() && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RD, 0, NULL)) abort () +# define gl_rwlock_wrlock(NAME) \ + if (pth_in_use() && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RW, 0, NULL)) abort () +# define gl_rwlock_unlock(NAME) \ + if (pth_in_use() && !pth_rwlock_release (&NAME)) abort () +# define gl_rwlock_destroy(NAME) \ + (void)(&NAME) + +/* --------------------- gl_recursive_lock_t datatype --------------------- */ + +/* In Pth, mutexes are recursive by default. */ +typedef pth_mutex_t gl_recursive_lock_t; +# define gl_recursive_lock_define(STORAGECLASS, NAME) \ + STORAGECLASS pth_mutex_t NAME; +# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ + STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer; +# define gl_recursive_lock_initializer \ + PTH_MUTEX_INIT +# define gl_recursive_lock_init(NAME) \ + if (pth_in_use() && !pth_mutex_init (&NAME)) abort () +# define gl_recursive_lock_lock(NAME) \ + if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) abort () +# define gl_recursive_lock_unlock(NAME) \ + if (pth_in_use() && !pth_mutex_release (&NAME)) abort () +# define gl_recursive_lock_destroy(NAME) \ + (void)(&NAME) + +/* -------------------------- gl_once_t datatype -------------------------- */ + +typedef pth_once_t gl_once_t; +# define gl_once_define(STORAGECLASS, NAME) \ + STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT; +# define gl_once(NAME, INITFUNCTION) \ + do \ + { \ + if (pth_in_use ()) \ + { \ + void (*gl_once_temp) (void) = INITFUNCTION; \ + if (!pth_once (&NAME, glthread_once_call, &gl_once_temp)) \ + abort (); \ + } \ + else \ + { \ + if (glthread_once_singlethreaded (&NAME)) \ + INITFUNCTION (); \ + } \ + } \ + while (0) +extern void glthread_once_call (void *arg); +extern int glthread_once_singlethreaded (pth_once_t *once_control); + +#endif + +/* ========================================================================= */ + +#if USE_SOLARIS_THREADS + +/* Use the old Solaris threads library. */ + +# include +# include +# include + +# if USE_SOLARIS_THREADS_WEAK + +/* Use weak references to the old Solaris threads library. */ + +# pragma weak mutex_init +# pragma weak mutex_lock +# pragma weak mutex_unlock +# pragma weak mutex_destroy +# pragma weak rwlock_init +# pragma weak rw_rdlock +# pragma weak rw_wrlock +# pragma weak rw_unlock +# pragma weak rwlock_destroy +# pragma weak thr_self + +# pragma weak thr_suspend +# define thread_in_use() (thr_suspend != NULL) + +# else + +# define thread_in_use() 1 + +# endif + +/* -------------------------- gl_lock_t datatype -------------------------- */ + +typedef mutex_t gl_lock_t; +# define gl_lock_define(STORAGECLASS, NAME) \ + STORAGECLASS mutex_t NAME; +# define gl_lock_define_initialized(STORAGECLASS, NAME) \ + STORAGECLASS mutex_t NAME = gl_lock_initializer; +# define gl_lock_initializer \ + DEFAULTMUTEX +# define gl_lock_init(NAME) \ + if (thread_in_use () && mutex_init (&NAME, USYNC_THREAD, NULL) != 0) abort () +# define gl_lock_lock(NAME) \ + if (thread_in_use () && mutex_lock (&NAME) != 0) abort () +# define gl_lock_unlock(NAME) \ + if (thread_in_use () && mutex_unlock (&NAME) != 0) abort () +# define gl_lock_destroy(NAME) \ + if (thread_in_use () && mutex_destroy (&NAME) != 0) abort () + +/* ------------------------- gl_rwlock_t datatype ------------------------- */ + +typedef rwlock_t gl_rwlock_t; +# define gl_rwlock_define(STORAGECLASS, NAME) \ + STORAGECLASS rwlock_t NAME; +# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ + STORAGECLASS rwlock_t NAME = gl_rwlock_initializer; +# define gl_rwlock_initializer \ + DEFAULTRWLOCK +# define gl_rwlock_init(NAME) \ + if (thread_in_use () && rwlock_init (&NAME, USYNC_THREAD, NULL) != 0) abort () +# define gl_rwlock_rdlock(NAME) \ + if (thread_in_use () && rw_rdlock (&NAME) != 0) abort () +# define gl_rwlock_wrlock(NAME) \ + if (thread_in_use () && rw_wrlock (&NAME) != 0) abort () +# define gl_rwlock_unlock(NAME) \ + if (thread_in_use () && rw_unlock (&NAME) != 0) abort () +# define gl_rwlock_destroy(NAME) \ + if (thread_in_use () && rwlock_destroy (&NAME) != 0) abort () + +/* --------------------- gl_recursive_lock_t datatype --------------------- */ + +/* Old Solaris threads did not have recursive locks. + We have to implement them ourselves. */ + +typedef struct + { + mutex_t mutex; + thread_t owner; + unsigned long depth; + } + gl_recursive_lock_t; +# define gl_recursive_lock_define(STORAGECLASS, NAME) \ + STORAGECLASS gl_recursive_lock_t NAME; +# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ + STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer; +# define gl_recursive_lock_initializer \ + { DEFAULTMUTEX, (thread_t) 0, 0 } +# define gl_recursive_lock_init(NAME) \ + if (thread_in_use ()) glthread_recursive_lock_init (&NAME) +# define gl_recursive_lock_lock(NAME) \ + if (thread_in_use ()) glthread_recursive_lock_lock (&NAME) +# define gl_recursive_lock_unlock(NAME) \ + if (thread_in_use ()) glthread_recursive_lock_unlock (&NAME) +# define gl_recursive_lock_destroy(NAME) \ + if (thread_in_use ()) glthread_recursive_lock_destroy (&NAME) +extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock); +extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock); +extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock); +extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock); + +/* -------------------------- gl_once_t datatype -------------------------- */ + +typedef struct + { + volatile int inited; + mutex_t mutex; + } + gl_once_t; +# define gl_once_define(STORAGECLASS, NAME) \ + STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX }; +# define gl_once(NAME, INITFUNCTION) \ + do \ + { \ + if (thread_in_use ()) \ + { \ + glthread_once (&NAME, INITFUNCTION); \ + } \ + else \ + { \ + if (glthread_once_singlethreaded (&NAME)) \ + INITFUNCTION (); \ + } \ + } \ + while (0) +extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void)); +extern int glthread_once_singlethreaded (gl_once_t *once_control); + +#endif + +/* ========================================================================= */ + +#if USE_WIN32_THREADS + +# include + +/* We can use CRITICAL_SECTION directly, rather than the Win32 Event, Mutex, + Semaphore types, because + - we need only to synchronize inside a single process (address space), + not inter-process locking, + - we don't need to support trylock operations. (TryEnterCriticalSection + does not work on Windows 95/98/ME. Packages that need trylock usually + define their own mutex type.) */ + +/* There is no way to statically initialize a CRITICAL_SECTION. It needs + to be done lazily, once only. For this we need spinlocks. */ + +typedef struct { volatile int done; volatile long started; } gl_spinlock_t; + +/* -------------------------- gl_lock_t datatype -------------------------- */ + +typedef struct + { + gl_spinlock_t guard; /* protects the initialization */ + CRITICAL_SECTION lock; + } + gl_lock_t; +# define gl_lock_define(STORAGECLASS, NAME) \ + STORAGECLASS gl_lock_t NAME; +# define gl_lock_define_initialized(STORAGECLASS, NAME) \ + STORAGECLASS gl_lock_t NAME = gl_lock_initializer; +# define gl_lock_initializer \ + { { 0, -1 } } +# define gl_lock_init(NAME) \ + glthread_lock_init (&NAME) +# define gl_lock_lock(NAME) \ + glthread_lock_lock (&NAME) +# define gl_lock_unlock(NAME) \ + glthread_lock_unlock (&NAME) +# define gl_lock_destroy(NAME) \ + glthread_lock_destroy (&NAME) +extern void glthread_lock_init (gl_lock_t *lock); +extern void glthread_lock_lock (gl_lock_t *lock); +extern void glthread_lock_unlock (gl_lock_t *lock); +extern void glthread_lock_destroy (gl_lock_t *lock); + +/* ------------------------- gl_rwlock_t datatype ------------------------- */ + +/* It is impossible to implement read-write locks using plain locks, without + introducing an extra thread dedicated to managing read-write locks. + Therefore here we need to use the low-level Event type. */ + +typedef struct + { + HANDLE *array; /* array of waiting threads, each represented by an event */ + unsigned int count; /* number of waiting threads */ + unsigned int alloc; /* length of allocated array */ + unsigned int offset; /* index of first waiting thread in array */ + } + gl_waitqueue_t; +typedef struct + { + gl_spinlock_t guard; /* protects the initialization */ + CRITICAL_SECTION lock; /* protects the remaining fields */ + gl_waitqueue_t waiting_readers; /* waiting readers */ + gl_waitqueue_t waiting_writers; /* waiting writers */ + int runcount; /* number of readers running, or -1 when a writer runs */ + } + gl_rwlock_t; +# define gl_rwlock_define(STORAGECLASS, NAME) \ + STORAGECLASS gl_rwlock_t NAME; +# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ + STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer; +# define gl_rwlock_initializer \ + { { 0, -1 } } +# define gl_rwlock_init(NAME) \ + glthread_rwlock_init (&NAME) +# define gl_rwlock_rdlock(NAME) \ + glthread_rwlock_rdlock (&NAME) +# define gl_rwlock_wrlock(NAME) \ + glthread_rwlock_wrlock (&NAME) +# define gl_rwlock_unlock(NAME) \ + glthread_rwlock_unlock (&NAME) +# define gl_rwlock_destroy(NAME) \ + glthread_rwlock_destroy (&NAME) +extern void glthread_rwlock_init (gl_rwlock_t *lock); +extern void glthread_rwlock_rdlock (gl_rwlock_t *lock); +extern void glthread_rwlock_wrlock (gl_rwlock_t *lock); +extern void glthread_rwlock_unlock (gl_rwlock_t *lock); +extern void glthread_rwlock_destroy (gl_rwlock_t *lock); + +/* --------------------- gl_recursive_lock_t datatype --------------------- */ + +/* The Win32 documentation says that CRITICAL_SECTION already implements a + recursive lock. But we need not rely on it: It's easy to implement a + recursive lock without this assumption. */ + +typedef struct + { + gl_spinlock_t guard; /* protects the initialization */ + DWORD owner; + unsigned long depth; + CRITICAL_SECTION lock; + } + gl_recursive_lock_t; +# define gl_recursive_lock_define(STORAGECLASS, NAME) \ + STORAGECLASS gl_recursive_lock_t NAME; +# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ + STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer; +# define gl_recursive_lock_initializer \ + { { 0, -1 }, 0, 0 } +# define gl_recursive_lock_init(NAME) \ + glthread_recursive_lock_init (&NAME) +# define gl_recursive_lock_lock(NAME) \ + glthread_recursive_lock_lock (&NAME) +# define gl_recursive_lock_unlock(NAME) \ + glthread_recursive_lock_unlock (&NAME) +# define gl_recursive_lock_destroy(NAME) \ + glthread_recursive_lock_destroy (&NAME) +extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock); +extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock); +extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock); +extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock); + +/* -------------------------- gl_once_t datatype -------------------------- */ + +typedef struct + { + volatile int inited; + volatile long started; + CRITICAL_SECTION lock; + } + gl_once_t; +# define gl_once_define(STORAGECLASS, NAME) \ + STORAGECLASS gl_once_t NAME = { -1, -1 }; +# define gl_once(NAME, INITFUNCTION) \ + glthread_once (&NAME, INITFUNCTION) +extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void)); + +#endif + +/* ========================================================================= */ + +#if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS) + +/* Provide dummy implementation if threads are not supported. */ + +/* -------------------------- gl_lock_t datatype -------------------------- */ + +typedef int gl_lock_t; +# define gl_lock_define(STORAGECLASS, NAME) +# define gl_lock_define_initialized(STORAGECLASS, NAME) +# define gl_lock_init(NAME) +# define gl_lock_lock(NAME) +# define gl_lock_unlock(NAME) + +/* ------------------------- gl_rwlock_t datatype ------------------------- */ + +typedef int gl_rwlock_t; +# define gl_rwlock_define(STORAGECLASS, NAME) +# define gl_rwlock_define_initialized(STORAGECLASS, NAME) +# define gl_rwlock_init(NAME) +# define gl_rwlock_rdlock(NAME) +# define gl_rwlock_wrlock(NAME) +# define gl_rwlock_unlock(NAME) + +/* --------------------- gl_recursive_lock_t datatype --------------------- */ + +typedef int gl_recursive_lock_t; +# define gl_recursive_lock_define(STORAGECLASS, NAME) +# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) +# define gl_recursive_lock_init(NAME) +# define gl_recursive_lock_lock(NAME) +# define gl_recursive_lock_unlock(NAME) + +/* -------------------------- gl_once_t datatype -------------------------- */ + +typedef int gl_once_t; +# define gl_once_define(STORAGECLASS, NAME) \ + STORAGECLASS gl_once_t NAME = 0; +# define gl_once(NAME, INITFUNCTION) \ + do \ + { \ + if (NAME == 0) \ + { \ + NAME = ~ 0; \ + INITFUNCTION (); \ + } \ + } \ + while (0) + +#endif + +/* ========================================================================= */ + +#endif /* _LOCK_H */ diff --git a/intl/version.c b/intl/version.c new file mode 100644 index 000000000..a968cf746 --- /dev/null +++ b/intl/version.c @@ -0,0 +1,26 @@ +/* libintl library version. + Copyright (C) 2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libgnuintl.h" + +/* Version number: (major<<16) + (minor<<8) + subminor */ +int libintl_version = LIBINTL_VERSION; diff --git a/m4/glibc2.m4 b/m4/glibc2.m4 new file mode 100644 index 000000000..e8f5bfe6e --- /dev/null +++ b/m4/glibc2.m4 @@ -0,0 +1,30 @@ +# glibc2.m4 serial 1 +dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +# Test for the GNU C Library, version 2.0 or newer. +# From Bruno Haible. + +AC_DEFUN([gt_GLIBC2], + [ + AC_CACHE_CHECK(whether we are using the GNU C Library 2 or newer, + ac_cv_gnu_library_2, + [AC_EGREP_CPP([Lucky GNU user], + [ +#include +#ifdef __GNU_LIBRARY__ + #if (__GLIBC__ >= 2) + Lucky GNU user + #endif +#endif + ], + ac_cv_gnu_library_2=yes, + ac_cv_gnu_library_2=no) + ] + ) + AC_SUBST(GLIBC2) + GLIBC2="$ac_cv_gnu_library_2" + ] +) diff --git a/m4/libusb.m4 b/m4/libusb.m4 new file mode 100644 index 000000000..809dc1dd9 --- /dev/null +++ b/m4/libusb.m4 @@ -0,0 +1,69 @@ +dnl Check for libusb +dnl Copyright (C) 2004, 2005 Free Software Foundation, Inc. +dnl +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. +dnl +dnl Defines HAVE_LIBUSB to 1 if a working libusb setup is found, and sets +dnl @LIBUSB@ to the necessary libraries. HAVE_USB_GET_BUSSES is set if +dnl usb_get_busses() exists. + +AC_DEFUN([GNUPG_CHECK_LIBUSB], +[ + AC_ARG_WITH(libusb, + AC_HELP_STRING([--with-libusb=DIR], + [look for the libusb library in DIR]), + [_do_libusb=$withval],[_do_libusb=yes]) + + if test "$_do_libusb" != "no" ; then + if test -d "$withval" ; then + CPPFLAGS="${CPPFLAGS} -I$withval/include" + LDFLAGS="${LDFLAGS} -L$withval/lib" + AC_PATH_PROG([_usb_config],["$_do_libusb/bin/libusb-config"]) + else + AC_PATH_PROG([_usb_config],[libusb-config]) + fi + + _libusb_save_libs=$LIBS + _libusb_save_cflags=$CFLAGS + + if test x$_usb_config != "x" ; then + _libusb_try_libs=`$LIBS $_usb_config --libs` + _libusb_try_cflags=`$LIBS $_usb_config --cflags` + else + _libusb_try_libs="-lusb" + _libusb_try_cflags="" + fi + + LIBS="$LIBS $_libusb_try_libs" + CFLAGS="$CFLAGS $_libusb_try_cflags" + + AC_MSG_CHECKING([whether libusb is present and sane]) + + AC_LINK_IFELSE(AC_LANG_PROGRAM([#include ],[ +usb_bulk_write(NULL,0,NULL,0,0); +]),_found_libusb=yes,_found_libusb=no) + + AC_MSG_RESULT([$_found_libusb]) + + if test $_found_libusb = yes ; then + AC_DEFINE(HAVE_LIBUSB,1, + [Define to 1 if you have a fully functional libusb library.]) + AC_SUBST(LIBUSB_CPPFLAGS,$_libusb_try_cflags) + AC_SUBST(LIBUSB,$_libusb_try_libs) + AC_CHECK_FUNCS(usb_get_busses) + fi + + LIBS=$_libusb_save_libs + CFLAGS=$_libusb_save_cflags + + unset _libusb_save_libs + unset _libusb_save_cflags + unset _libusb_try_libs + unset _libusb_try_cflags + unset _found_libusb + fi +])dnl diff --git a/m4/lock.m4 b/m4/lock.m4 new file mode 100644 index 000000000..d1ea1ca83 --- /dev/null +++ b/m4/lock.m4 @@ -0,0 +1,289 @@ +# lock.m4 serial 2 (gettext-0.15) +dnl Copyright (C) 2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +dnl Tests for a multithreading library to be used. +dnl Defines at most one of the macros USE_POSIX_THREADS, USE_SOLARIS_THREADS, +dnl USE_PTH_THREADS, USE_WIN32_THREADS +dnl Sets the variables LIBTHREAD and LTLIBTHREAD to the linker options for use +dnl in a Makefile (LIBTHREAD for use without libtool, LTLIBTHREAD for use with +dnl libtool). +dnl Sets the variables LIBMULTITHREAD and LTLIBMULTITHREAD similarly, for +dnl programs that really need multithread functionality. The difference +dnl between LIBTHREAD and LIBMULTITHREAD is that on platforms supporting weak +dnl symbols, typically LIBTHREAD="" whereas LIBMULTITHREAD="-lpthread". +dnl Adds to CPPFLAGS the flag -D_REENTRANT or -D_THREAD_SAFE if needed for +dnl multithread-safe programs. + +AC_DEFUN([gl_LOCK], +[ + AC_REQUIRE([gl_LOCK_BODY]) +]) + +dnl The guts of gl_LOCK. Needs to be expanded only once. + +AC_DEFUN([gl_LOCK_BODY], +[ + dnl Ordering constraints: This macro modifies CPPFLAGS in a way that + dnl influences the result of the autoconf tests that test for *_unlocked + dnl declarations, on AIX 5 at least. Therefore it must come early. + AC_BEFORE([$0], [gl_FUNC_GLIBC_UNLOCKED_IO])dnl + AC_BEFORE([$0], [gl_ARGP])dnl + + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_REQUIRE([AC_GNU_SOURCE]) dnl needed for pthread_rwlock_t on glibc systems + dnl Check for multithreading. + AC_ARG_ENABLE(threads, +AC_HELP_STRING([--enable-threads={posix|solaris|pth|win32}], [specify multithreading API]) +AC_HELP_STRING([--disable-threads], [build without multithread safety]), + gl_use_threads=$enableval, gl_use_threads=yes) + gl_threads_api=none + LIBTHREAD= + LTLIBTHREAD= + LIBMULTITHREAD= + LTLIBMULTITHREAD= + if test "$gl_use_threads" != no; then + dnl Check whether the compiler and linker support weak declarations. + AC_MSG_CHECKING([whether imported symbols can be declared weak]) + gl_have_weak=no + AC_TRY_LINK([extern void xyzzy (); +#pragma weak xyzzy], [xyzzy();], [gl_have_weak=yes]) + AC_MSG_RESULT([$gl_have_weak]) + if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then + # On OSF/1, the compiler needs the flag -pthread or -D_REENTRANT so that + # it groks . + gl_save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS -D_REENTRANT" + AC_CHECK_HEADER(pthread.h, gl_have_pthread_h=yes, gl_have_pthread_h=no) + CPPFLAGS="$gl_save_CPPFLAGS" + if test "$gl_have_pthread_h" = yes; then + # Other possible tests: + # -lpthreads (FSU threads, PCthreads) + # -lgthreads + case "$host_os" in + osf*) + # On OSF/1, the compiler needs the flag -D_REENTRANT so that it + # groks . cc also understands the flag -pthread, but + # we don't use it because 1. gcc-2.95 doesn't understand -pthread, + # 2. putting a flag into CPPFLAGS that has an effect on the linker + # causes the AC_TRY_LINK test below to succeed unexpectedly, + # leading to wrong values of LIBTHREAD and LTLIBTHREAD. + CPPFLAGS="$CPPFLAGS -D_REENTRANT" + ;; + esac + gl_have_pthread= + # Test whether both pthread_mutex_lock and pthread_mutexattr_init exist + # in libc. IRIX 6.5 has the first one in both libc and libpthread, but + # the second one only in libpthread, and lock.c needs it. + AC_TRY_LINK([#include ], + [pthread_mutex_lock((pthread_mutex_t*)0); + pthread_mutexattr_init((pthread_mutexattr_t*)0);], + [gl_have_pthread=yes]) + # Test for libpthread by looking for pthread_kill. (Not pthread_self, + # since it is defined as a macro on OSF/1.) + if test -n "$gl_have_pthread"; then + # The program links fine without libpthread. But it may actually + # need to link with libpthread in order to create multiple threads. + AC_CHECK_LIB(pthread, pthread_kill, + [LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread + # On Solaris and HP-UX, most pthread functions exist also in libc. + # Therefore pthread_in_use() needs to actually try to create a + # thread: pthread_create from libc will fail, whereas + # pthread_create will actually create a thread. + case "$host_os" in + solaris* | hpux*) + AC_DEFINE([PTHREAD_IN_USE_DETECTION_HARD], 1, + [Define if the pthread_in_use() detection is hard.]) + esac + ]) + else + # Some library is needed. Try libpthread and libc_r. + AC_CHECK_LIB(pthread, pthread_kill, + [gl_have_pthread=yes + LIBTHREAD=-lpthread LTLIBTHREAD=-lpthread + LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread]) + if test -z "$gl_have_pthread"; then + # For FreeBSD 4. + AC_CHECK_LIB(c_r, pthread_kill, + [gl_have_pthread=yes + LIBTHREAD=-lc_r LTLIBTHREAD=-lc_r + LIBMULTITHREAD=-lc_r LTLIBMULTITHREAD=-lc_r]) + fi + fi + if test -n "$gl_have_pthread"; then + gl_threads_api=posix + AC_DEFINE([USE_POSIX_THREADS], 1, + [Define if the POSIX multithreading library can be used.]) + if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then + if test $gl_have_weak = yes; then + AC_DEFINE([USE_POSIX_THREADS_WEAK], 1, + [Define if references to the POSIX multithreading library should be made weak.]) + LIBTHREAD= + LTLIBTHREAD= + fi + fi + # OSF/1 4.0 and MacOS X 10.1 lack the pthread_rwlock_t type and the + # pthread_rwlock_* functions. + AC_CHECK_TYPE([pthread_rwlock_t], + [AC_DEFINE([HAVE_PTHREAD_RWLOCK], 1, + [Define if the POSIX multithreading library has read/write locks.])], + [], + [#include ]) + # glibc defines PTHREAD_MUTEX_RECURSIVE as enum, not as a macro. + AC_TRY_COMPILE([#include ], + [#if __FreeBSD__ == 4 +error "No, in FreeBSD 4.0 recursive mutexes actually don't work." +#else +int x = (int)PTHREAD_MUTEX_RECURSIVE; +#endif], + [AC_DEFINE([HAVE_PTHREAD_MUTEX_RECURSIVE], 1, + [Define if the defines PTHREAD_MUTEX_RECURSIVE.])]) + # Some systems optimize for single-threaded programs by default, and + # need special flags to disable these optimizations. For example, the + # definition of 'errno' in . + case "$host_os" in + aix* | freebsd*) CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE" ;; + solaris*) CPPFLAGS="$CPPFLAGS -D_REENTRANT" ;; + esac + fi + fi + fi + if test -z "$gl_have_pthread"; then + if test "$gl_use_threads" = yes || test "$gl_use_threads" = solaris; then + gl_have_solaristhread= + gl_save_LIBS="$LIBS" + LIBS="$LIBS -lthread" + AC_TRY_LINK([#include +#include ], + [thr_self();], + [gl_have_solaristhread=yes]) + LIBS="$gl_save_LIBS" + if test -n "$gl_have_solaristhread"; then + gl_threads_api=solaris + LIBTHREAD=-lthread + LTLIBTHREAD=-lthread + LIBMULTITHREAD="$LIBTHREAD" + LTLIBMULTITHREAD="$LTLIBTHREAD" + AC_DEFINE([USE_SOLARIS_THREADS], 1, + [Define if the old Solaris multithreading library can be used.]) + if test $gl_have_weak = yes; then + AC_DEFINE([USE_SOLARIS_THREADS_WEAK], 1, + [Define if references to the old Solaris multithreading library should be made weak.]) + LIBTHREAD= + LTLIBTHREAD= + fi + fi + fi + fi + if test "$gl_use_threads" = pth; then + gl_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_LINKFLAGS(pth) + gl_have_pth= + gl_save_LIBS="$LIBS" + LIBS="$LIBS -lpth" + AC_TRY_LINK([#include ], [pth_self();], gl_have_pth=yes) + LIBS="$gl_save_LIBS" + if test -n "$gl_have_pth"; then + gl_threads_api=pth + LIBTHREAD="$LIBPTH" + LTLIBTHREAD="$LTLIBPTH" + LIBMULTITHREAD="$LIBTHREAD" + LTLIBMULTITHREAD="$LTLIBTHREAD" + AC_DEFINE([USE_PTH_THREADS], 1, + [Define if the GNU Pth multithreading library can be used.]) + if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then + if test $gl_have_weak = yes; then + AC_DEFINE([USE_PTH_THREADS_WEAK], 1, + [Define if references to the GNU Pth multithreading library should be made weak.]) + LIBTHREAD= + LTLIBTHREAD= + fi + fi + else + CPPFLAGS="$gl_save_CPPFLAGS" + fi + fi + if test -z "$gl_have_pthread"; then + if test "$gl_use_threads" = yes || test "$gl_use_threads" = win32; then + if { case "$host_os" in + mingw*) true;; + *) false;; + esac + }; then + gl_threads_api=win32 + AC_DEFINE([USE_WIN32_THREADS], 1, + [Define if the Win32 multithreading API can be used.]) + fi + fi + fi + fi + AC_MSG_CHECKING([for multithread API to use]) + AC_MSG_RESULT([$gl_threads_api]) + AC_SUBST(LIBTHREAD) + AC_SUBST(LTLIBTHREAD) + AC_SUBST(LIBMULTITHREAD) + AC_SUBST(LTLIBMULTITHREAD) + gl_PREREQ_LOCK +]) + +# Prerequisites of lib/lock.c. +AC_DEFUN([gl_PREREQ_LOCK], [ + AC_REQUIRE([AC_C_INLINE]) +]) + +dnl Survey of platforms: +dnl +dnl Platform Available Compiler Supports test-lock +dnl flavours option weak result +dnl --------------- --------- --------- -------- --------- +dnl Linux 2.4/glibc posix -lpthread Y OK +dnl +dnl GNU Hurd/glibc posix +dnl +dnl FreeBSD 5.3 posix -lc_r Y +dnl posix -lkse ? Y +dnl posix -lpthread ? Y +dnl posix -lthr Y +dnl +dnl FreeBSD 5.2 posix -lc_r Y +dnl posix -lkse Y +dnl posix -lthr Y +dnl +dnl FreeBSD 4.0,4.10 posix -lc_r Y OK +dnl +dnl NetBSD 1.6 -- +dnl +dnl OpenBSD 3.4 posix -lpthread Y OK +dnl +dnl MacOS X 10.[123] posix -lpthread Y OK +dnl +dnl Solaris 7,8,9 posix -lpthread Y Sol 7,8: 0.0; Sol 9: OK +dnl solaris -lthread Y Sol 7,8: 0.0; Sol 9: OK +dnl +dnl HP-UX 11 posix -lpthread N (cc) OK +dnl Y (gcc) +dnl +dnl IRIX 6.5 posix -lpthread Y 0.5 +dnl +dnl AIX 4.3,5.1 posix -lpthread N AIX 4: 0.5; AIX 5: OK +dnl +dnl OSF/1 4.0,5.1 posix -pthread (cc) N OK +dnl -lpthread (gcc) Y +dnl +dnl Cygwin posix -lpthread Y OK +dnl +dnl Any of the above pth -lpth 0.0 +dnl +dnl Mingw win32 N OK +dnl +dnl BeOS 5 -- +dnl +dnl The test-lock result shows what happens if in test-lock.c EXPLICIT_YIELD is +dnl turned off: +dnl OK if all three tests terminate OK, +dnl 0.5 if the first test terminates OK but the second one loops endlessly, +dnl 0.0 if the first test already loops endlessly. diff --git a/m4/visibility.m4 b/m4/visibility.m4 new file mode 100644 index 000000000..2ff6330aa --- /dev/null +++ b/m4/visibility.m4 @@ -0,0 +1,52 @@ +# visibility.m4 serial 1 (gettext-0.15) +dnl Copyright (C) 2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +dnl Tests whether the compiler supports the command-line option +dnl -fvisibility=hidden and the function and variable attributes +dnl __attribute__((__visibility__("hidden"))) and +dnl __attribute__((__visibility__("default"))). +dnl Does *not* test for __visibility__("protected") - which has tricky +dnl semantics (see the 'vismain' test in glibc) and does not exist e.g. on +dnl MacOS X. +dnl Does *not* test for __visibility__("internal") - which has processor +dnl dependent semantics. +dnl Does *not* test for #pragma GCC visibility push(hidden) - which is +dnl "really only recommended for legacy code". +dnl Set the variable CFLAG_VISIBILITY. +dnl Defines and sets the variable HAVE_VISIBILITY. + +AC_DEFUN([gl_VISIBILITY], +[ + AC_REQUIRE([AC_PROG_CC]) + CFLAG_VISIBILITY= + HAVE_VISIBILITY=0 + if test -n "$GCC"; then + AC_MSG_CHECKING([for simple visibility declarations]) + AC_CACHE_VAL(gl_cv_cc_visibility, [ + gl_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fvisibility=hidden" + AC_TRY_COMPILE( + [extern __attribute__((__visibility__("hidden"))) int hiddenvar; + extern __attribute__((__visibility__("default"))) int exportedvar; + extern __attribute__((__visibility__("hidden"))) int hiddenfunc (void); + extern __attribute__((__visibility__("default"))) int exportedfunc (void);], + [], + gl_cv_cc_visibility=yes, + gl_cv_cc_visibility=no) + CFLAGS="$gl_save_CFLAGS"]) + AC_MSG_RESULT([$gl_cv_cc_visibility]) + if test $gl_cv_cc_visibility = yes; then + CFLAG_VISIBILITY="-fvisibility=hidden" + HAVE_VISIBILITY=1 + fi + fi + AC_SUBST([CFLAG_VISIBILITY]) + AC_SUBST([HAVE_VISIBILITY]) + AC_DEFINE_UNQUOTED([HAVE_VISIBILITY], [$HAVE_VISIBILITY], + [Define to 1 or 0, depending whether the compiler supports simple visibility declarations.]) +])