diff --git a/man/pike.1 b/man/pike.1 index 9f01345224ecd525bf1fbf37f05fc9a07b83472f..b84e104454be5c7fe5bfc8150dc6268c252ff7d6 100644 --- a/man/pike.1 +++ b/man/pike.1 @@ -1,11 +1,11 @@ -.\" $Id: pike.1,v 1.16 2003/01/24 16:05:44 nilsson Exp $ +.\" $Id: pike.1,v 1.17 2003/04/01 19:41:13 mast Exp $ .\" name section last-modified title section-name product/status architecture .ds ]L Pike -.TH pike 1 "$Date: 2003/01/24 16:05:44 $" Pike "Pike Manual" Pike -.\" On Solaris ]L will contain "Last modified $Date: 2003/01/24 16:05:44 $" +.TH pike 1 "$Date: 2003/04/01 19:41:13 $" Pike "Pike Manual" Pike +.\" On Solaris ]L will contain "Last modified $Date: 2003/04/01 19:41:13 $" .\" while HPUX uses ]L to contain "Pike". .\" On OSF/1 ]L will already contain the wanted string. -.if !\*(]LPike .ds ]L $Date: 2003/01/24 16:05:44 $ \" Solaris nroff +.if !\*(]LPike .ds ]L $Date: 2003/04/01 19:41:13 $ \" Solaris nroff .\" Major (mj) and minor (mn) version of Pike .nr mj 7 .nr mn 5 @@ -61,6 +61,9 @@ Debug signals (debug). .B \-dt Turn off tail recursion optimization (debug). .TP +.B \-dT +Enable extra checks in the the thread library, e.g. mutex sanity checks (debug). +.TP .B \-l Increase the debug level of the global optimizer with 1 (debug). .TP diff --git a/src/acconfig.h b/src/acconfig.h index 9b4b3ce34fe463d55933556ebf9f7f160305a45a..77b00c187501722e20f7d9dfac0e638966f2271e 100644 --- a/src/acconfig.h +++ b/src/acconfig.h @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: acconfig.h,v 1.122 2003/03/29 01:45:22 mast Exp $ +|| $Id: acconfig.h,v 1.123 2003/04/01 19:41:13 mast Exp $ */ #ifndef MACHINE_H @@ -417,14 +417,14 @@ /* Define this if your THREAD_T type is a pointer type. */ #undef PIKE_THREAD_T_IS_POINTER -/* Define this if your pthreads have pthread_condattr_default */ -#undef HAVE_PTHREAD_CONDATTR_DEFAULT +/* Define to the flag to get an error checking mutex, if supported. */ +#undef PIKE_MUTEX_ERRORCHECK -/* Define if your pthreads have PTHREAD_MUTEX_RECURSIVE */ -#undef HAVE_PTHREAD_MUTEX_RECURSIVE +/* Define to the flag to get a recursive mutex, if supported. */ +#undef PIKE_MUTEX_RECURSIVE -/* Define if your pthreads have PTHREAD_MUTEX_RECURSIVE_NP */ -#undef HAVE_PTHREAD_MUTEX_RECURSIVE_NP +/* Define this if your pthreads have pthread_condattr_default */ +#undef HAVE_PTHREAD_CONDATTR_DEFAULT /* Define this if you need to use &pthread_condattr_default in cond_init() */ #undef HAVE_PTHREAD_CONDATTR_DEFAULT_AIX diff --git a/src/aclocal.m4 b/src/aclocal.m4 index 679009b2e835764da9100bd1da695026b21b5d86..3a02a1e743e5e4218ab2e568a36eb574afadf4fc 100644 --- a/src/aclocal.m4 +++ b/src/aclocal.m4 @@ -1,4 +1,4 @@ -dnl $Id: aclocal.m4,v 1.67 2003/04/01 19:09:53 mast Exp $ +dnl $Id: aclocal.m4,v 1.68 2003/04/01 19:41:13 mast Exp $ dnl Some compatibility with Autoconf 2.50+. Not complete. dnl newer Autoconf calls substr m4_substr @@ -253,6 +253,31 @@ ifelse([$3], , , [ rm -rf conftest* fi rm -rf conftest*]) +dnl PIKE_CHECK_CONSTANTS(checking_message, constant_names, includes, define_name) +dnl +dnl define_name will be defined to the first constant in +dnl constant_names that exists. It will remain undefined if none of +dnl them exists. +AC_DEFUN(PIKE_CHECK_CONSTANTS, +[ + AC_MSG_CHECKING([$1]) + AC_CACHE_VAL(pike_cv_$4_value, [ + pike_cv_$4_value="" + for const in $2 + do + AC_TRY_COMPILE([$3], [int tmp = (int) $const;], [ + pike_cv_$4_value="$const" + break + ]) + done + ]) + if test x"$pike_cv_$4_value" != x; then + AC_MSG_RESULT($pike_cv_$4_value) + AC_DEFINE_UNQUOTED([$4], $pike_cv_$4_value) + else + AC_MSG_RESULT(none) + fi +]) dnl @@ -295,7 +320,7 @@ define(PIKE_FEATURE_OK,[ define([AC_LOW_MODULE_INIT], [ -# $Id: aclocal.m4,v 1.67 2003/04/01 19:09:53 mast Exp $ +# $Id: aclocal.m4,v 1.68 2003/04/01 19:41:13 mast Exp $ MY_AC_PROG_CC diff --git a/src/configure.in b/src/configure.in index 888f2af7f977c6d66cfcbeb792eb1ecbfcb13389..1cd1edbcf6832fd37faa06315a87530846bbc978 100644 --- a/src/configure.in +++ b/src/configure.in @@ -1,4 +1,4 @@ -AC_REVISION("$Id: configure.in,v 1.712 2003/04/01 19:10:53 mast Exp $") +AC_REVISION("$Id: configure.in,v 1.713 2003/04/01 19:41:13 mast Exp $") AC_INIT(interpret.c) AC_CONFIG_HEADER(machine.h) @@ -3081,6 +3081,28 @@ fi ######################################################################## +PIKE_CHECK_CONSTANTS(mutex error check flag, + PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_ERRORCHECK_NP, [ +#ifdef HAVE_PTHREAD_H +#include <pthread.h> +#elif defined (HAVE_THREAD_H) +#include <thread.h> +#endif + ], PIKE_MUTEX_ERRORCHECK) + +######################################################################## + +PIKE_CHECK_CONSTANTS(recursive mutex flag, + PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP, [ +#ifdef HAVE_PTHREAD_H +#include <pthread.h> +#elif defined (HAVE_THREAD_H) +#include <thread.h> +#endif + ], PIKE_MUTEX_RECURSIVE) + +######################################################################## + # NOTE: The following test is hardcoded to fail when crosscompiling # It also clobbers $LIBOBJS. @@ -4054,22 +4076,6 @@ MY_CHECK_FUNCTION(fork, exit(fork()==-1); ]) -######################################################################## -MY_CHECK_FUNCTION(PTHREAD_MUTEX_RECURSIVE, -[ -#include <pthread.h> -], [ - PTHREAD_MUTEX_RECURSIVE; - exit(0); -]) -######################################################################## -MY_CHECK_FUNCTION(PTHREAD_MUTEX_RECURSIVE_NP, -[ -#include <pthread.h> -], [ - PTHREAD_MUTEX_RECURSIVE_NP; - exit(0); -]) ######################################################################## MY_CHECK_FUNCTION(fpsetmask, [ diff --git a/src/main.c b/src/main.c index 598bb9ac66c5f0590f18c5b8b37695e314b6c1b4..713b58d83b5fe6b0a42386988f9ac30e019b3e05 100644 --- a/src/main.c +++ b/src/main.c @@ -2,11 +2,11 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: main.c,v 1.170 2003/03/30 17:15:09 mast Exp $ +|| $Id: main.c,v 1.171 2003/04/01 19:41:13 mast Exp $ */ #include "global.h" -RCSID("$Id: main.c,v 1.170 2003/03/30 17:15:09 mast Exp $"); +RCSID("$Id: main.c,v 1.171 2003/04/01 19:41:13 mast Exp $"); #include "fdlib.h" #include "backend.h" #include "module.h" @@ -444,6 +444,11 @@ int dbm_main(int argc, char **argv) p++; goto more_d_flags; + case 'T': + debug_options |= ERRORCHECK_MUTEXES; + p++; + goto more_d_flags; + default: d_flag += (p[0] == 'd'); p++; @@ -518,6 +523,13 @@ int dbm_main(int argc, char **argv) } } +#ifndef PIKE_MUTEX_ERRORCHECK + if (debug_options & ERRORCHECK_MUTEXES) + fputs ("Warning: -dT (error checking mutexes) not supported on this system.\n", + stderr); +#endif + if (d_flag) debug_options |= ERRORCHECK_MUTEXES; + #if !defined(RLIMIT_NOFILE) && defined(RLIMIT_OFILE) #define RLIMIT_NOFILE RLIMIT_OFILE #endif diff --git a/src/main.h b/src/main.h index 4bdc966571c9e8932c1f6364e6ce62123fa4526c..c421ef46596e65c9cae5019d7e1a801f7822a470 100644 --- a/src/main.h +++ b/src/main.h @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: main.h,v 1.21 2003/01/08 19:35:42 mast Exp $ +|| $Id: main.h,v 1.22 2003/04/01 19:41:13 mast Exp $ */ #ifndef MAIN_H @@ -23,6 +23,7 @@ extern int try_use_mmx; #define NO_TAILRECURSION 2 #define NO_PEEP_OPTIMIZING 4 #define GC_RESET_DMALLOC 8 +#define ERRORCHECK_MUTEXES 16 /* Runtime options */ #define RUNTIME_CHECK_TYPES 1 diff --git a/src/pike_threadlib.h b/src/pike_threadlib.h index 4fadb98342dccd57355147aec781eefb03151a69..a710c4d2e66fbbad9cd0ee0ee48476f82877dd10 100644 --- a/src/pike_threadlib.h +++ b/src/pike_threadlib.h @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: pike_threadlib.h,v 1.38 2003/04/01 19:12:48 mast Exp $ +|| $Id: pike_threadlib.h,v 1.39 2003/04/01 19:41:13 mast Exp $ */ #ifndef PIKE_THREADLIB_H @@ -17,6 +17,7 @@ #ifndef CONFIGURE_TEST #include "machine.h" +#include "main.h" #endif /* Needed for the sigset_t typedef, which is needed for @@ -98,6 +99,13 @@ PMOD_EXPORT extern int live_threads, disallow_live_threads; struct object; PMOD_EXPORT extern size_t thread_stack_size; +PMOD_EXPORT void thread_low_error (int errcode); + +#define LOW_THREAD_CHECK_NONZERO_ERROR(CALL) do { \ + int thread_errcode_ = (CALL); \ + if (thread_errcode_) thread_low_error (thread_errcode_); \ + } while (0) + #define DEFINE_MUTEX(X) PIKE_MUTEX_T X @@ -117,27 +125,41 @@ void th_atfork_child(void); #define THREAD_T pthread_t #define PIKE_MUTEX_T pthread_mutex_t -#define mt_init(X) pthread_mutex_init((X),0) -#if !defined(HAVE_PTHREAD_MUTEX_RECURSIVE_NP) && defined(HAVE_PTHREAD_MUTEX_RECURSIVE) -#define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE -#define HAVE_PTHREAD_MUTEX_RECURSIVE_NP +#ifdef PIKE_MUTEX_ERRORCHECK +#define mt_init(X) do { \ + if (debug_options & ERRORCHECK_MUTEXES) { \ + pthread_mutexattr_t attr; \ + pthread_mutexattr_init(&attr); \ + pthread_mutexattr_settype(&attr, PIKE_MUTEX_ERRORCHECK); \ + pthread_mutex_init((X), &attr); \ + } \ + else \ + pthread_mutex_init((X),0); \ + } while (0) +#define DO_IF_PIKE_MUTEX_ERRORCHECK(X) X +#else +#define mt_init(X) pthread_mutex_init((X),0) +#define DO_IF_PIKE_MUTEX_ERRORCHECK(X) #endif -#ifdef HAVE_PTHREAD_MUTEX_RECURSIVE_NP +#ifdef PIKE_MUTEX_RECURSIVE #define mt_init_recursive(X) \ do{ \ pthread_mutexattr_t attr; \ pthread_mutexattr_init(&attr); \ - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); \ + pthread_mutexattr_settype( \ + &attr, \ + PIKE_MUTEX_RECURSIVE \ + DO_IF_PIKE_MUTEX_ERRORCHECK (| PIKE_MUTEX_ERRORCHECK)); \ pthread_mutex_init((X), &attr); \ }while(0) #endif -#define mt_lock(X) pthread_mutex_lock(X) +#define mt_lock(X) LOW_THREAD_CHECK_NONZERO_ERROR (pthread_mutex_lock(X)) #define mt_trylock(X) pthread_mutex_trylock(X) -#define mt_unlock(X) pthread_mutex_unlock(X) -#define mt_destroy(X) pthread_mutex_destroy(X) +#define mt_unlock(X) LOW_THREAD_CHECK_NONZERO_ERROR (pthread_mutex_unlock(X)) +#define mt_destroy(X) LOW_THREAD_CHECK_NONZERO_ERROR (pthread_mutex_destroy(X)) /* SIGH! No setconcurrency in posix threads. This is more or less * needed to make usable multi-threaded programs on solaris machines @@ -163,12 +185,12 @@ extern pthread_attr_t small_pattr; #ifdef HAVE_PTHREAD_KILL -#define th_kill(ID,sig) pthread_kill((ID),(sig)) +#define th_kill(ID,sig) LOW_THREAD_CHECK_NONZERO_ERROR (pthread_kill((ID),(sig))) #else /* !HAVE_PTHREAD_KILL */ /* MacOS X (aka Darwin) doesn't have pthread_kill. */ #define th_kill(ID,sig) #endif /* HAVE_PTHREAD_KILL */ -#define th_join(ID,res) pthread_join((ID),(res)) +#define th_join(ID,res) LOW_THREAD_CHECK_NONZERO_ERROR (pthread_join((ID),(res))) #ifdef HAVE_PTHREAD_COND_INIT #define COND_T pthread_cond_t @@ -187,7 +209,7 @@ extern pthread_attr_t small_pattr; #define co_wait(COND, MUTEX) pthread_cond_wait((COND), (MUTEX)) #define co_signal(X) pthread_cond_signal(X) #define co_broadcast(X) pthread_cond_broadcast(X) -#define co_destroy(X) pthread_cond_destroy(X) +#define co_destroy(X) LOW_THREAD_CHECK_NONZERO_ERROR (pthread_cond_destroy(X)) #else #error No way to make cond-vars #endif /* HAVE_PTHREAD_COND_INIT */ @@ -201,11 +223,11 @@ extern pthread_attr_t small_pattr; #define THREAD_T thread_t #define PTHREAD_MUTEX_INITIALIZER DEFAULTMUTEX #define PIKE_MUTEX_T mutex_t -#define mt_init(X) mutex_init((X),USYNC_THREAD,0) -#define mt_lock(X) mutex_lock(X) +#define mt_init(X) LOW_THREAD_CHECK_NONZERO_ERROR (mutex_init((X),USYNC_THREAD,0)) +#define mt_lock(X) LOW_THREAD_CHECK_NONZERO_ERROR (mutex_lock(X)) #define mt_trylock(X) mutex_trylock(X) -#define mt_unlock(X) mutex_unlock(X) -#define mt_destroy(X) mutex_destroy(X) +#define mt_unlock(X) LOW_THREAD_CHECK_NONZERO_ERROR (mutex_unlock(X)) +#define mt_destroy(X) LOW_THREAD_CHECK_NONZERO_ERROR (mutex_destroy(X)) #define th_setconcurrency(X) thr_setconcurrency(X) @@ -263,6 +285,10 @@ extern pthread_attr_t small_pattr; #include <process.h> #include <windows.h> +#define LOW_THREAD_CHECK_ZERO_ERROR(CALL) do { \ + if (!(CALL)) thread_low_error (GetLastError()); \ + } while (0) + #define THREAD_T unsigned #define th_setconcurrency(X) #define th_create(ID,fun,arg) low_nt_create_thread(2*1024*1024,fun, arg,ID) @@ -278,17 +304,23 @@ extern pthread_attr_t small_pattr; #define th_hash(X) (X) #define PIKE_MUTEX_T HANDLE -#define mt_init(X) CheckValidHandle((*(X)=CreateMutex(NULL, 0, NULL))) -#define mt_lock(X) WaitForSingleObject(CheckValidHandle(*(X)), INFINITE) -#define mt_trylock(X) WaitForSingleObject(CheckValidHandle(*(X)), 0) -#define mt_unlock(X) ReleaseMutex(CheckValidHandle(*(X))) -#define mt_destroy(X) CloseHandle(CheckValidHandle(*(X))) +#define mt_init(X) LOW_THREAD_CHECK_ZERO_ERROR ((*(X)=CreateMutex(NULL, 0, NULL))) +#define mt_lock(X) \ + LOW_THREAD_CHECK_ZERO_ERROR ( \ + WaitForSingleObject(CheckValidHandle(*(X)), INFINITE) == WAIT_OBJECT_0) +#define mt_trylock(X) \ + LOW_THREAD_CHECK_ZERO_ERROR ( \ + WaitForSingleObject(CheckValidHandle(*(X)), 0) != WAIT_FAILED) +#define mt_unlock(X) LOW_THREAD_CHECK_ZERO_ERROR (ReleaseMutex(CheckValidHandle(*(X)))) +#define mt_destroy(X) LOW_THREAD_CHECK_ZERO_ERROR (CloseHandle(CheckValidHandle(*(X)))) #define EVENT_T HANDLE -#define event_init(X) CheckValidHandle(*(X)=CreateEvent(NULL, 1, 0, NULL)) -#define event_signal(X) SetEvent(CheckValidHandle(*(X))) -#define event_destroy(X) CloseHandle(CheckValidHandle(*(X))) -#define event_wait(X) WaitForSingleObject(CheckValidHandle(*(X)), INFINITE) +#define event_init(X) LOW_THREAD_CHECK_ZERO_ERROR (*(X)=CreateEvent(NULL, 1, 0, NULL)) +#define event_signal(X) LOW_THREAD_CHECK_ZERO_ERROR (SetEvent(CheckValidHandle(*(X)))) +#define event_destroy(X) LOW_THREAD_CHECK_ZERO_ERROR (CloseHandle(CheckValidHandle(*(X)))) +#define event_wait(X) \ + LOW_THREAD_CHECK_ZERO_ERROR ( \ + WaitForSingleObject(CheckValidHandle(*(X)), INFINITE) == WAIT_OBJECT_0) /* No fork -- no atfork */ #define th_atfork(X,Y,Z) @@ -451,8 +483,10 @@ PMOD_EXPORT extern clock_t thread_start_clock; extern THREAD_T debug_locking_thread; #define SET_LOCKING_THREAD (debug_locking_thread = th_self(), 0) -#define low_mt_lock_interpreter() (mt_lock(&interpreter_lock) || SET_LOCKING_THREAD) -#define low_mt_trylock_interpreter() (mt_trylock(&interpreter_lock) || SET_LOCKING_THREAD) +#define low_mt_lock_interpreter() \ + do {mt_lock(&interpreter_lock); SET_LOCKING_THREAD;} while (0) +#define low_mt_trylock_interpreter() \ + (mt_trylock(&interpreter_lock) || SET_LOCKING_THREAD) #define low_co_wait_interpreter(COND) \ do {co_wait((COND), &interpreter_lock); SET_LOCKING_THREAD;} while (0) @@ -469,7 +503,7 @@ extern THREAD_T debug_locking_thread; #else -#define low_mt_lock_interpreter() (mt_lock(&interpreter_lock)) +#define low_mt_lock_interpreter() do {mt_lock(&interpreter_lock);} while (0) #define low_mt_trylock_interpreter() (mt_trylock(&interpreter_lock)) #define low_co_wait_interpreter(COND) do {co_wait((COND), &interpreter_lock);} while (0) @@ -487,11 +521,15 @@ static INLINE int threads_disabled_wait(void) return 0; } -#define mt_lock_interpreter() \ - (low_mt_lock_interpreter() || (threads_disabled && threads_disabled_wait())) +#define mt_lock_interpreter() do { \ + low_mt_lock_interpreter(); \ + (threads_disabled && threads_disabled_wait()); \ + } while (0) #define mt_trylock_interpreter() \ (low_mt_trylock_interpreter() || (threads_disabled && threads_disabled_wait())) -#define mt_unlock_interpreter() (mt_unlock(&interpreter_lock)) +#define mt_unlock_interpreter() do { \ + mt_unlock(&interpreter_lock); \ + } while (0) #define co_wait_interpreter(COND) do { \ low_co_wait_interpreter(COND); \ if (threads_disabled) threads_disabled_wait(); \ diff --git a/src/threads.c b/src/threads.c index bc31fe09450906145ff451bfd69ff58f6a2b8c54..ec3561f169d147e4490a0c5ed080771f5b4a8221 100644 --- a/src/threads.c +++ b/src/threads.c @@ -2,12 +2,12 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: threads.c,v 1.213 2003/04/01 19:12:09 mast Exp $ +|| $Id: threads.c,v 1.214 2003/04/01 19:41:13 mast Exp $ */ #ifndef CONFIGURE_TEST #include "global.h" -RCSID("$Id: threads.c,v 1.213 2003/04/01 19:12:09 mast Exp $"); +RCSID("$Id: threads.c,v 1.214 2003/04/01 19:41:13 mast Exp $"); PMOD_EXPORT int num_threads = 1; PMOD_EXPORT int threads_disabled = 0; @@ -47,6 +47,11 @@ PMOD_EXPORT COND_T live_threads_change; PMOD_EXPORT COND_T threads_disabled_change; PMOD_EXPORT size_t thread_stack_size=256 * 1204; +PMOD_EXPORT void thread_low_error (int errcode) +{ + Pike_fatal ("Unexpected error from thread function: %d\n", errcode); +} + #else #include "pike_threadlib.h" #endif /* !CONFIGURE_TEST */ @@ -730,14 +735,7 @@ TH_RETURN_TYPE new_thread_func(void *data) } #endif /* HAVE_BROKEN_LINUX_THREAD_EUID */ - if((tmp=mt_lock_interpreter())) - Pike_fatal("Failed to lock interpreter, return value=%d, errno=%d\n",tmp, -#ifdef __NT__ - GetLastError() -#else - errno -#endif - ); + mt_lock_interpreter(); #if defined(PIKE_DEBUG) if(d_flag) {