diff --git a/.gitattributes b/.gitattributes index 9facb0f5db1634cd74485745c3762c76956c1a39..4268ddbcc6bcfbbc0dcd524a7a1e4c21672508e2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -581,6 +581,7 @@ testfont binary /src/pike_macros.h foreign_ident /src/pike_memory.c foreign_ident /src/pike_memory.h foreign_ident +/src/pike_threadlib.h foreign_ident /src/pike_types.c foreign_ident /src/pike_types.h foreign_ident /src/port.c foreign_ident diff --git a/src/array.c b/src/array.c index 5e3812ad5ff95e3665f1216ed8c0814c9a892a78..4e74241155b9b80f9671d94a63d7262ed948e9a4 100644 --- a/src/array.c +++ b/src/array.c @@ -23,13 +23,16 @@ #include "stuff.h" #include "bignum.h" -RCSID("$Id: array.c,v 1.102 2001/02/03 01:04:48 mast Exp $"); +RCSID("$Id: array.c,v 1.103 2001/04/07 07:38:23 hubbe Exp $"); PMOD_EXPORT struct array empty_array= { 1, /* Never free */ #ifdef PIKE_SECURITY 0, +#endif +#ifdef USE_LOCAL_MUTEX + PTHREAD_MUTEX_INITIALIZER, #endif &empty_array, /* Next */ &empty_array, /* previous (circular) */ @@ -73,11 +76,9 @@ PMOD_EXPORT struct array *low_allocate_array(ptrdiff_t size, ptrdiff_t extra_spa v->malloced_size = DO_NOT_WARN((INT32)(size + extra_space)); v->size = DO_NOT_WARN((INT32)size); - v->refs=1; + INIT_PIKE_MEMOBJ(v); LINK_ARRAY(v); - INITIALIZE_PROT(v); - for(e=0;e<v->size;e++) { ITEM(v)[e].type=T_INT; @@ -115,7 +116,7 @@ PMOD_EXPORT void really_free_array(struct array *v) #endif add_ref(v); - FREE_PROT(v); + EXIT_PIKE_MEMOBJ(v); free_svalues(ITEM(v), v->size, v->type_field); v->refs--; array_free_no_free(v); diff --git a/src/array.h b/src/array.h index 5a278bac1205ada46c16c6146c6ea3150bc7f942..b92ab74e93456358989d398603fc3a47a4583b61 100644 --- a/src/array.h +++ b/src/array.h @@ -5,7 +5,7 @@ \*/ /* - * $Id: array.h,v 1.32 2001/03/23 03:14:39 hubbe Exp $ + * $Id: array.h,v 1.33 2001/04/07 07:38:23 hubbe Exp $ */ #ifndef ARRAY_H #define ARRAY_H @@ -14,10 +14,8 @@ struct array { - INT32 refs; /* Reference count */ -#ifdef PIKE_SECURITY - struct object *prot; -#endif + PIKE_MEMORY_OBJECT_MEMBERS; + struct array *next; /* we need to keep track of all arrays */ struct array *prev; /* Another pointer, so we don't have to search * when freeing arrays */ diff --git a/src/constants.c b/src/constants.c index 4a1c77fdc978968ae90d83490737530240635428..136a53ce15941ad3a1b81287ccc96c2a8a3cf514 100644 --- a/src/constants.c +++ b/src/constants.c @@ -16,7 +16,7 @@ #include "pike_error.h" #include "block_alloc.h" -RCSID("$Id: constants.c,v 1.28 2001/03/03 00:23:45 grubba Exp $"); +RCSID("$Id: constants.c,v 1.29 2001/04/07 07:38:24 hubbe Exp $"); struct mapping *builtin_constants = 0; @@ -68,6 +68,7 @@ PMOD_EXPORT void add_global_program(char *name, struct program *p) #define EXIT_BLOCK(X) do { \ free_type(X->type); \ free_string(X->name); \ + EXIT_PIKE_MEMOBJ(X); \ }while(0) BLOCK_ALLOC(callable,128) @@ -80,7 +81,7 @@ PMOD_EXPORT struct callable *low_make_callable(c_fun fun, docode_fun docode) { struct callable *f=alloc_callable(); - f->refs=1; + INIT_PIKE_MEMOBJ(f); f->function=fun; f->name=name; f->type=type; diff --git a/src/constants.h b/src/constants.h index 6c3bc74241f4c6f67fed4faee0aa35798e3e7d06..5bae6091a2ff09bcee4a1169b9c77edb3cda6406 100644 --- a/src/constants.h +++ b/src/constants.h @@ -5,7 +5,7 @@ \*/ /* - * $Id: constants.h,v 1.16 2001/02/19 23:49:59 grubba Exp $ + * $Id: constants.h,v 1.17 2001/04/07 07:38:24 hubbe Exp $ */ #ifndef ADD_EFUN_H #define ADD_EFUN_H @@ -20,10 +20,7 @@ typedef node *(*optimize_fun)(node *n); struct callable { - INT32 refs; -#ifdef PIKE_SECURITY - struct object *prot; -#endif + PIKE_MEMORY_OBJECT_MEMBERS; c_fun function; struct pike_type *type; struct pike_string *name; diff --git a/src/mapping.h b/src/mapping.h index d25b987509ccb677e106f207a3115105c8b32007..564c231b8b633c1dd72524dabca4e1f2b5c84b8a 100644 --- a/src/mapping.h +++ b/src/mapping.h @@ -5,7 +5,7 @@ \*/ /* - * $Id: mapping.h,v 1.35 2001/03/23 03:14:40 hubbe Exp $ + * $Id: mapping.h,v 1.36 2001/04/07 07:38:24 hubbe Exp $ */ #ifndef MAPPING_H #define MAPPING_H @@ -24,7 +24,7 @@ struct keypair struct mapping_data { - INT32 refs; + PIKE_MEMORY_OBJECT_MEMBERS; INT32 valrefs; /* lock values too */ INT32 hardlinks; INT32 size, hashsize; @@ -41,10 +41,7 @@ struct mapping_data struct mapping { - INT32 refs; -#ifdef PIKE_SECURITY - struct object *prot; -#endif + PIKE_MEMORY_OBJECT_MEMBERS; #ifdef MAPPING_SIZE_DEBUG INT32 debug_size; #endif @@ -75,7 +72,7 @@ extern struct mapping *gc_internal_mapping; #define free_mapping_data(M) do{ \ struct mapping_data *md_=(M); \ debug_malloc_touch(md_); \ - if(!--md_->refs) really_free_mapping_data(md_); \ + if(!sub_ref(md_)) really_free_mapping_data(md_); \ /* FIXME: What about valrefs & hardlinks? */ \ }while(0) diff --git a/src/multiset.c b/src/multiset.c index 1d24a3c9818fad54eac414cbdc1bdc26bf4af7dc..06c1120391e4e7382adb3b13f4a49e454a22d8c5 100644 --- a/src/multiset.c +++ b/src/multiset.c @@ -17,7 +17,7 @@ #include "gc.h" #include "security.h" -RCSID("$Id: multiset.c,v 1.32 2001/01/31 13:19:01 grubba Exp $"); +RCSID("$Id: multiset.c,v 1.33 2001/04/07 07:38:24 hubbe Exp $"); struct multiset *first_multiset; @@ -41,12 +41,10 @@ PMOD_EXPORT struct multiset *allocate_multiset(struct array *ind) struct multiset *l; l=ALLOC_STRUCT(multiset); GC_ALLOC(l); - l->refs = 1; + INIT_PIKE_MEMOBJ(l); l->ind=ind; DOUBLELINK(first_multiset, l); - INITIALIZE_PROT(l); - return l; } @@ -61,7 +59,7 @@ PMOD_EXPORT void really_free_multiset(struct multiset *l) #endif free_array(l->ind); - FREE_PROT(l); + EXIT_PIKE_MEMOBJ(l); DOUBLEUNLINK(first_multiset, l); diff --git a/src/multiset.h b/src/multiset.h index ae0a6e67a9ac43e4facdb6d7e7d759387f550595..42ce9f6a82a6a0d64224ed691acc27820cb1afc0 100644 --- a/src/multiset.h +++ b/src/multiset.h @@ -5,7 +5,7 @@ \*/ /* - * $Id: multiset.h,v 1.17 2001/03/23 03:14:40 hubbe Exp $ + * $Id: multiset.h,v 1.18 2001/04/07 07:38:24 hubbe Exp $ */ #ifndef MULTISET_H #define MULTISET_H @@ -14,10 +14,8 @@ struct multiset { - INT32 refs; -#ifdef PIKE_SECURITY - struct object *prot; -#endif + PIKE_MEMORY_OBJECT_MEMBERS; /* Must be first */ + struct multiset *next,*prev; struct array *ind; }; diff --git a/src/object.c b/src/object.c index e28fd5013597302b97ea7becf5d15ca861a53cd0..7787cd6c460eb5e456603aaf9effe23b89861815 100644 --- a/src/object.c +++ b/src/object.c @@ -5,7 +5,7 @@ \*/ /**/ #include "global.h" -RCSID("$Id: object.c,v 1.166 2001/03/22 02:21:15 hubbe Exp $"); +RCSID("$Id: object.c,v 1.167 2001/04/07 07:38:24 hubbe Exp $"); #include "object.h" #include "dynamic_buffer.h" #include "interpret.h" @@ -135,13 +135,12 @@ PMOD_EXPORT struct object *low_clone(struct program *p) o->parent_identifier=0; DOUBLELINK(first_object,o); - o->refs=1; + INIT_PIKE_MEMOBJ(o); #ifdef PIKE_DEBUG o->program_id=p->id; #endif - INITIALIZE_PROT(o); return o; } @@ -769,7 +768,7 @@ PMOD_EXPORT void schedule_really_free_object(struct object *o) /* As far as the gc is concerned, the fake objects doesn't exist. */ GC_FREE(o); - FREE_PROT(o); + EXIT_PIKE_MEMOBJ(o); if(o->storage) { diff --git a/src/object.h b/src/object.h index 4b9737cb778e9111fb3391d15ac1278d354741a3..64f51a6e6738d2921bd7f013051d94998a6a1de6 100644 --- a/src/object.h +++ b/src/object.h @@ -5,7 +5,7 @@ \*/ /* - * $Id: object.h,v 1.60 2001/03/23 03:14:40 hubbe Exp $ + * $Id: object.h,v 1.61 2001/04/07 07:38:24 hubbe Exp $ */ #ifndef OBJECT_H #define OBJECT_H @@ -20,10 +20,7 @@ #endif struct object { - INT32 refs; /* Reference count, must be first. */ -#ifdef PIKE_SECURITY - struct object *prot; -#endif + PIKE_MEMORY_OBJECT_MEMBERS; /* Must be first */ struct program *prog; struct object *parent; INT16 parent_identifier; diff --git a/src/pike_cpulib.c b/src/pike_cpulib.c index 58ae97fe1ecf1d77e5d6bae410583e4c2ced62e7..4708358d4f2441f4b7c9683e425fbb1c835c7f6e 100644 --- a/src/pike_cpulib.c +++ b/src/pike_cpulib.c @@ -8,10 +8,11 @@ #define PIKE_MEM_HASH 17903 PIKE_MUTEX_T pike_memory_locks[PIKE_MEM_HASH]; -void init_cpulib(void) +void init_pike_cpulib(void) { int e; - for(e=0;e<PIKE_MEM_HASH;e++) mt_init(pike_memory_locks+e); + for(e=0;e<PIKE_MEM_HASH;e++) + mt_init_recursive(pike_memory_locks+e); } #endif diff --git a/src/pike_cpulib.h b/src/pike_cpulib.h index b09ebf0e92e95c8eefd9a891d5d490c5237ad7c9..b4e9ed4530993d42be0dc8ed464d2f6249352a3f 100644 --- a/src/pike_cpulib.h +++ b/src/pike_cpulib.h @@ -26,8 +26,19 @@ mt_unlock(pike_mem_mutex); \ }while(0) +#define pike_memlock(ADDR) do{ \ + PIKE_MUTEX_T *pike_mem_mutex=pike_memory_locks+ \ + ((unsigned long)(ADDR))%PIKE_MEM_HASH; \ + mt_lock(pike_mem_mutex) \ +}while(0) + +#define pike_unmemlock(ADDR) do{ \ + PIKE_MUTEX_T *pike_mem_mutex=pike_memory_locks+ \ + ((unsigned long)(ADDR))%PIKE_MEM_HASH; \ + mt_unlock(pike_mem_mutex) \ +}while(0) - +#define PIKE_NEED_MEMLOCK /* Autoconf this? */ #if defined(__i386__) && defined(__GNUC__) @@ -76,6 +87,7 @@ pike_atomic_compare_and_swap32 (INT32 *p, INT32 oldval, INT32 newval) } +/* NOT USED */ #define PIKE_HAS_COMPARE_AND_SWAP64 static inline int pike_atomic_compare_and_swap64 (INT64 *p, INT64 oldval, INT64 newval) diff --git a/src/pike_threadlib.h b/src/pike_threadlib.h new file mode 100644 index 0000000000000000000000000000000000000000..7d2ffb2845a978141aa8555b10d7ac161d8a8e00 --- /dev/null +++ b/src/pike_threadlib.h @@ -0,0 +1,615 @@ +/* + * $Id: pike_threadlib.h,v 1.1 2001/04/07 07:38:25 hubbe Exp $ + */ +#ifndef PIKE_THREADLIB_H +#define PIKE_THREADLIB_H + +/* + * This file is for the low-level thread interface functions + * 'threads.h' is for anything that concerns the object interface + * for pike threads. + */ + + +#include "machine.h" + +/* Needed for the sigset_t typedef, which is needed for + * the pthread_sigsetmask() prototype on Solaris 2.x. + */ +#include <signal.h> + +#ifdef HAVE_SYS_TYPES_H +/* Needed for pthread_t on OSF/1 */ +#include <sys/types.h> +#endif /* HAVE_SYS_TYPES_H */ +#ifdef PIKE_THREADS + +/* The fp macro conflicts with Solaris's <pthread.h>. */ +#ifdef fp +#undef fp +#define FRAMEPOINTER_WAS_DEFINED +#endif /* fp */ + +/* + * Decide which type of threads to use + * + * UNIX_THREADS : Unix international threads + * POSIX_THREADS : POSIX standard threads + * SGI_SPROC_THREADS : SGI sproc() based threads + * NT_THREADS : NT threads + */ + +#ifdef _UNIX_THREADS +#ifdef HAVE_THREAD_H +#define UNIX_THREADS +#include <thread.h> +#undef HAVE_PTHREAD_H +#undef HAVE_THREAD_H +#endif +#endif /* _UNIX_THREADS */ + +#ifdef _MIT_POSIX_THREADS +#define POSIX_THREADS +#include <pthread.h> + +/* AIX is *STUPID* - Hubbe */ +#undef func_data + +#undef HAVE_PTHREAD_H +#endif /* _MIT_POSIX_THREADS */ + +#ifdef _SGI_SPROC_THREADS +/* Not supported yet */ +#undef SGI_SPROC_THREADS +#undef HAVE_SPROC +#endif /* _SGI_SPROC_THREADS */ + + + +/* Restore the fp macro. */ +#ifdef FRAMEPOINTER_WAS_DEFINED +#define fp Pike_fp +#undef FRAMEPOINTER_WAS_DEFINED +#endif /* FRAMEPOINTER_WAS_DEFINED */ + + +extern int num_threads; +PMOD_EXPORT extern int live_threads; +struct object; +PMOD_EXPORT extern size_t thread_stack_size; + +#define DEFINE_MUTEX(X) PIKE_MUTEX_T X + + +#ifdef POSIX_THREADS + +#ifdef HAVE_PTHREAD_ATFORK +#define th_atfork(X,Y,Z) pthread_atfork((X),(Y),(Z)) +#define th_atfork_prepare() +#define th_atfork_parent() +#define th_atfork_child() +#else +int th_atfork(void (*)(void),void (*)(void),void (*)(void)); +void th_atfork_prepare(void); +void th_atfork_parent(void); +void th_atfork_child(void); +#endif + +#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 +#endif + +#ifdef HAVE_PTHREAD_MUTEX_RECURSIVE_NP +#define mt_init_recursive(X) \ + do{ \ + pthread_mutexattr_t attr; \ + pthread_mutexattr_init(&attr); \ + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); \ + pthread_mutex_init((X), &attr); \ + }while(0) +#endif + +#define mt_lock(X) 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) + +/* SIGH! No setconcurrency in posix threads. This is more or less + * needed to make usable multi-threaded programs on solaris machines + * with only one CPU. Otherwise, only systemcalls are actually + * threaded. + */ +#define th_setconcurrency(X) +#ifdef HAVE_PTHREAD_YIELD +#define th_yield() pthread_yield() +#else +#define th_yield() +#endif /* HAVE_PTHREAD_YIELD */ +extern pthread_attr_t pattr; +extern pthread_attr_t small_pattr; + +#define th_create(ID,fun,arg) pthread_create(ID,&pattr,fun,arg) +#define th_create_small(ID,fun,arg) pthread_create(ID,&small_pattr,fun,arg) +#define th_exit(foo) pthread_exit(foo) +#define th_self() pthread_self() + +#define TH_KEY_T pthread_key_t +#define th_key_create pthread_key_create +#define th_setspecific pthread_setspecific +#define th_getspecific pthread_getspecific + + +#ifdef HAVE_PTHREAD_KILL +#define th_kill(ID,sig) 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)) +#ifdef HAVE_PTHREAD_COND_INIT +#define COND_T pthread_cond_t + +#ifdef HAVE_PTHREAD_CONDATTR_DEFAULT_AIX +/* AIX wants the & ... */ +#define co_init(X) pthread_cond_init((X), &pthread_condattr_default) +#else /* !HAVE_PTHREAD_CONDATTR_DEFAULT_AIX */ +#ifdef HAVE_PTHREAD_CONDATTR_DEFAULT +/* ... while FreeBSD doesn't. */ +#define co_init(X) pthread_cond_init((X), pthread_condattr_default) +#else /* !HAVE_PTHREAD_CONDATTR_DEFAULT */ +#define co_init(X) pthread_cond_init((X), 0) +#endif /* HAVE_PTHREAD_CONDATTR_DEFAULT */ +#endif /* HAVE_PTHREAD_CONDATTR_DEFAULT_AIX */ + +#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) +#else +#error No way to make cond-vars +#endif /* HAVE_PTHREAD_COND_INIT */ + +#endif /* POSIX_THREADS */ + + + + +#ifdef UNIX_THREADS +#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_trylock(X) mutex_trylock(X) +#define mt_unlock(X) mutex_unlock(X) +#define mt_destroy(X) mutex_destroy(X) + +#define th_setconcurrency(X) thr_setconcurrency(X) + +#define th_create(ID,fun,arg) thr_create(NULL,thread_stack_size,fun,arg,THR_DAEMON|THR_DETACHED,ID) +#define th_create_small(ID,fun,arg) thr_create(NULL,8192*sizeof(char *),fun,arg,THR_DAEMON|THR_DETACHED,ID) +#define th_exit(foo) thr_exit(foo) +#define th_self() thr_self() +#define th_kill(ID,sig) thr_kill((ID),(sig)) +#define th_yield() thr_yield() +#define th_join(ID,res) thr_join((ID), NULL, (res)) + +#define COND_T cond_t +#define co_init(X) cond_init((X),USYNC_THREAD,0) +#define co_wait(COND, MUTEX) cond_wait((COND), (MUTEX)) +#define co_signal(X) cond_signal(X) +#define co_broadcast(X) cond_broadcast(X) +#define co_destroy(X) cond_destroy(X) + + +#endif /* UNIX_THREADS */ + +#ifdef SGI_SPROC_THREADS + +/* + * Not fully supported yet + */ +#define THREAD_T int + +#define PIKE_MUTEX_T ulock_t +#define mt_init(X) (usinitlock(((*X) = usnewlock(/*********/)))) +#define mt_lock(X) ussetlock(*X) +#define mt_unlock(X) usunsetlock(*X) +#define mt_destroy(X) usfreelock((*X), /*******/) + +#define th_setconcurrency(X) /*******/ + +#define PIKE_SPROC_FLAGS (PR_SADDR|PR_SFDS|PR_SDIR|PS_SETEXITSIG) +#define th_create(ID, fun, arg) (((*(ID)) = sproc(fun, PIKE_SPROC_FLAGS, arg)) == -1) +#define th_create_small(ID, fun, arg) (((*(ID)) = sproc(fun, PIKE_SPROC_FLAGS, arg)) == -1) +#define th_exit(X) exit(X) +#define th_self() getpid() +#define th_yield() sginap(0) +#define th_join(ID,res) /*********/ +#define th_equal(X,Y) ((X)==(Y)) +#define th_hash(X) ((unsigned INT32)(X)) + +/* + * No cond_vars yet + */ + +#endif /* SGI_SPROC_THREADS */ + + +#ifdef NT_THREADS +#include <process.h> +#include <windows.h> + +#define THREAD_T unsigned +#define th_setconcurrency(X) +#define th_create(ID,fun,arg) low_nt_create_thread(2*1024*1024,fun, arg,ID) +#define th_create_small(ID,fun,arg) low_nt_create_thread(8192*sizeof(char *), fun,arg,ID) +#define TH_RETURN_TYPE unsigned __stdcall +#define TH_STDCALL __stdcall +#define th_exit(foo) _endthreadex(foo) +#define th_join(ID,res) /******************* FIXME! ****************/ +#define th_self() GetCurrentThreadId() +#define th_destroy(X) +#define th_yield() Sleep(0) +#define th_equal(X,Y) ((X)==(Y)) +#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 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) + +#endif + + +#if !defined(COND_T) && defined(EVENT_T) && defined(PIKE_MUTEX_T) + +#define SIMULATE_COND_WITH_EVENT + +struct cond_t_queue +{ + struct cond_t_queue *next; + EVENT_T event; +}; + +typedef struct cond_t_s +{ + PIKE_MUTEX_T lock; + struct cond_t_queue *head, *tail; +} COND_T; + +#define COND_T struct cond_t_s + +#define co_init(X) do { mt_init(& (X)->lock), (X)->head=(X)->tail=0; }while(0) + +PMOD_EXPORT int co_wait(COND_T *c, PIKE_MUTEX_T *m); +PMOD_EXPORT int co_signal(COND_T *c); +PMOD_EXPORT int co_broadcast(COND_T *c); +PMOD_EXPORT int co_destroy(COND_T *c); + +#endif + +extern int th_running; + +PMOD_EXPORT extern PIKE_MUTEX_T interpreter_lock; + +#if defined(PIKE_DEBUG) && !defined(__NT__) + +/* This is a debug wrapper to enable checks that the interpreter lock + * is hold by the current thread. */ + +extern THREAD_T debug_locking_thread; +#define SET_LOCKING_THREAD (debug_locking_thread = th_self(), 0) + +#define mt_lock_interpreter() (mt_lock(&interpreter_lock) || SET_LOCKING_THREAD) +#define mt_trylock_interpreter() (mt_trylock(&interpreter_lock) || SET_LOCKING_THREAD) +#define mt_unlock_interpreter() (mt_unlock(&interpreter_lock)) +#define co_wait_interpreter(COND) \ + do {co_wait((COND), &interpreter_lock); SET_LOCKING_THREAD;} while (0) + +#define CHECK_INTERPRETER_LOCK() do { \ + if (th_running) { \ + THREAD_T self; \ + if (!mt_trylock(&interpreter_lock)) \ + fatal("Interpreter is not locked.\n"); \ + self = th_self(); \ + if (!th_equal(debug_locking_thread, self)) \ + fatal("Interpreter is not locked by this thread.\n"); \ + } \ +} while (0) + +#else + +#define mt_lock_interpreter() (mt_lock(&interpreter_lock)) +#define mt_trylock_interpreter() (mt_trylock(&interpreter_lock)) +#define mt_unlock_interpreter() (mt_unlock(&interpreter_lock)) +#define co_wait_interpreter(COND) do {co_wait((COND), &interpreter_lock);} while (0) + +#endif + +#ifndef TH_RETURN_TYPE +#define TH_RETURN_TYPE void * +#endif + +#ifndef TH_STDCALL +#define TH_STDCALL +#endif + +#ifndef th_destroy +#define th_destroy(X) +#endif + +#ifndef th_yield +#define th_yield() +#endif + +#ifndef th_equal +#define th_equal(X,Y) (!MEMCMP(&(X),&(Y),sizeof(THREAD_T))) +#endif + +#ifndef th_hash +#define th_hash(X) hashmem((unsigned char *)&(X),sizeof(THREAD_T), 16) +#endif + +/* Define to get a debug-trace of some of the threads operations. */ +/* #define VERBOSE_THREADS_DEBUG 0 */ /* Some debug */ +/* #define VERBOSE_THREADS_DEBUG 1 */ /* Lots of debug */ + +#ifndef VERBOSE_THREADS_DEBUG +#define THREADS_FPRINTF(L,X) +#else +#define THREADS_FPRINTF(L,X) do { \ + if ((VERBOSE_THREADS_DEBUG + 0) >= (L)) fprintf X; \ + } while(0) +#endif /* VERBOSE_THREADS_DEBUG */ + +#ifdef THREAD_TRACE +PMOD_EXPORT extern int t_flag; +#define SWAP_OUT_TRACE(_tmp) do { (_tmp)->status.t_flag = t_flag; } while(0) +#define SWAP_IN_TRACE(_tmp) do { t_flag = (_tmp)->status.t_flag; } while(0) +#else /* !THREAD_TRACE */ +#define SWAP_OUT_TRACE(_tmp) +#define SWAP_IN_TRACE(_tmp) +#endif /* THREAD_TRACE */ + +#if defined(PROFILING) && defined(HAVE_GETHRTIME) +#define DO_IF_PROFILING(X) X +#else +#define DO_IF_PROFILING(X) +#endif + +#define SWAP_OUT_THREAD(_tmp) do { \ + (_tmp)->state=Pike_interpreter; \ + (_tmp)->swapped=1; \ + DO_IF_PROFILING( (_tmp)->time_base += gethrtime() ; ) \ + } while(0) + +#define SWAP_IN_THREAD(_tmp) do { \ + (_tmp)->swapped=0; \ + Pike_interpreter=(_tmp)->state; \ + DO_IF_PROFILING( Pike_interpreter.time_base -= gethrtime();) \ + } while(0) + +#define SWAP_OUT_CURRENT_THREAD() \ + do {\ + struct thread_state *_tmp=OBJ2THREAD(Pike_interpreter.thread_id); \ + SWAP_OUT_THREAD(_tmp); \ + THREADS_FPRINTF(1, (stderr, "SWAP_OUT_CURRENT_THREAD() %s:%d t:%08x\n", \ + __FILE__, __LINE__, (unsigned int)_tmp->thread_id)) \ + +#define SWAP_IN_CURRENT_THREAD() \ + THREADS_FPRINTF(1, (stderr, "SWAP_IN_CURRENT_THREAD() %s:%d ... t:%08x\n", \ + __FILE__, __LINE__, (unsigned int)_tmp->thread_id)); \ + SWAP_IN_THREAD(_tmp);\ + } while(0) + +#if defined(PIKE_DEBUG) && ! defined(DONT_HIDE_GLOBALS) +/* Note that scalar types are used in place of pointers and vice versa + * below. This is intended to cause compiler warnings/errors if + * there is an attempt to use the global variables in an unsafe + * environment. + */ +#define HIDE_GLOBAL_VARIABLES() do { \ + int Pike_interpreter =0; \ + int pop_n_elems = 0; \ + int push_sp_mark = 0, pop_sp_mark = 0, threads_disabled = 1 + +/* Note that the semi-colon below is needed to add an empty statement + * in case there is a label before the macro. + */ +#define REVEAL_GLOBAL_VARIABLES() ; } while(0) +#else /* PIKE_DEBUG */ +#define HIDE_GLOBAL_VARIABLES() +#define REVEAL_GLOBAL_VARIABLES() +#endif /* PIKE_DEBUG */ + +#define OBJ2THREAD(X) \ + ((struct thread_state *)((X)->storage+thread_storage_offset)) + +#define THREADSTATE2OBJ(X) ((X)->state.thread_id) + +PMOD_EXPORT extern int Pike_in_gc; +#define THREADS_ALLOW() do { \ + struct thread_state *_tmp=OBJ2THREAD(Pike_interpreter.thread_id); \ + DO_IF_DEBUG({ \ + if(thread_for_id(th_self()) != Pike_interpreter.thread_id) \ + fatal("thread_for_id() (or Pike_interpreter.thread_id) failed!" \ + " %p != %p\n", \ + thread_for_id(th_self()), Pike_interpreter.thread_id); \ + if (Pike_in_gc > 50 && Pike_in_gc < 300) \ + fatal("Threads allowed during garbage collection.\n"); \ + }) \ + if(num_threads > 1 && !threads_disabled) { \ + SWAP_OUT_THREAD(_tmp); \ + THREADS_FPRINTF(1, (stderr, "THREADS_ALLOW() %s:%d t:%08x(#%d)\n", \ + __FILE__, __LINE__, \ + (unsigned int)_tmp->thread_id, live_threads)); \ + mt_unlock_interpreter(); \ + } else {} \ + HIDE_GLOBAL_VARIABLES() + +#define THREADS_DISALLOW() \ + REVEAL_GLOBAL_VARIABLES(); \ + if(_tmp->swapped) { \ + mt_lock_interpreter(); \ + THREADS_FPRINTF(1, (stderr, "THREADS_DISALLOW() %s:%d t:%08x(#%d)\n", \ + __FILE__, __LINE__, \ + (unsigned int)_tmp->thread_id, live_threads)); \ + while (threads_disabled) { \ + THREADS_FPRINTF(1, (stderr, \ + "THREADS_DISALLOW(): Threads disabled\n")); \ + co_wait_interpreter(&threads_disabled_change); \ + } \ + SWAP_IN_THREAD(_tmp);\ + } \ + DO_IF_DEBUG( if(thread_for_id(th_self()) != Pike_interpreter.thread_id) \ + fatal("thread_for_id() (or Pike_interpreter.thread_id) failed! %p != %p\n",thread_for_id(th_self()),Pike_interpreter.thread_id) ; ) \ + } while(0) + +#define THREADS_ALLOW_UID() do { \ + struct thread_state *_tmp_uid=OBJ2THREAD(Pike_interpreter.thread_id); \ + DO_IF_DEBUG({ \ + if(thread_for_id(th_self()) != Pike_interpreter.thread_id) { \ + fatal("thread_for_id() (or Pike_interpreter.thread_id) failed! %p != %p\n", \ + thread_for_id(th_self()),Pike_interpreter.thread_id); \ + } \ + if ((Pike_in_gc > 50) && (Pike_in_gc < 300)) { \ + fprintf(stderr, __FILE__ ":" DEFINETOSTR(__LINE__) ": Fatal error:\n"); \ + debug_fatal("Threads allowed during garbage collection (%d).\n", \ + Pike_in_gc); \ + } \ + }) \ + if(num_threads > 1 && !threads_disabled) { \ + SWAP_OUT_THREAD(_tmp_uid); \ + live_threads++; \ + THREADS_FPRINTF(1, (stderr, "THREADS_ALLOW_UID() %s:%d t:%08x(#%d)\n", \ + __FILE__, __LINE__, \ + (unsigned int)_tmp_uid->thread_id, live_threads)); \ + mt_unlock_interpreter(); \ + } else {} \ + HIDE_GLOBAL_VARIABLES() + +#define THREADS_DISALLOW_UID() \ + REVEAL_GLOBAL_VARIABLES(); \ + if(_tmp_uid->swapped) { \ + mt_lock_interpreter(); \ + live_threads--; \ + THREADS_FPRINTF(1, (stderr, \ + "THREADS_DISALLOW_UID() %s:%d t:%08x(#%d)\n", \ + __FILE__, __LINE__, \ + (unsigned int)_tmp_uid->thread_id, live_threads)); \ + co_broadcast(&live_threads_change); \ + while (threads_disabled) { \ + THREADS_FPRINTF(1, (stderr, "THREADS_DISALLOW_UID(): Wait...\n")); \ + co_wait_interpreter(&threads_disabled_change); \ + } \ + SWAP_IN_THREAD(_tmp_uid);\ + } \ + } while(0) + +#define SWAP_IN_THREAD_IF_REQUIRED() do { \ + struct thread_state *_tmp=thread_state_for_id(th_self()); \ + HIDE_GLOBAL_VARIABLES(); \ + THREADS_DISALLOW() + +#ifdef PIKE_DEBUG +#define ASSERT_THREAD_SWAPPED_IN() do { \ + struct thread_state *_tmp=thread_state_for_id(th_self()); \ + if(_tmp->swapped) fatal("Thread is not swapped in!\n"); \ + }while(0) + +#else +#define ASSERT_THREAD_SWAPPED_IN() +#endif + +#endif /* PIKE_THREADS */ + +#ifndef PIKE_THREADS + +#define th_atfork(X,Y,Z) +#define th_atfork_prepare() +#define th_atfork_parent() +#define th_atfork_child() + +#define th_setconcurrency(X) +#define DEFINE_MUTEX(X) +#define DEFINE_IMUTEX(X) +#define init_interleave_mutex(X) +#define LOCK_IMUTEX(X) +#define UNLOCK_IMUTEX(X) +#define mt_init(X) +#define mt_lock(X) +#define mt_unlock(X) +#define mt_destroy(X) +#define THREADS_ALLOW() +#define THREADS_DISALLOW() +#define THREADS_ALLOW_UID() +#define THREADS_DISALLOW_UID() +#define HIDE_GLOBAL_VARIABLES() +#define REVEAL_GLOBAL_VARIABLES() +#define ASSERT_THREAD_SWAPPED_IN() +#define SWAP_IN_THREAD_IF_REQUIRED() +#define th_init() +#define low_th_init() +#define th_cleanup() +#define th_init_programs() +#define th_self() ((void*)0) +#define co_signal(X) +#define co_broadcast(X) + +#define low_init_threads_disable() +#define init_threads_disable(X) +#define exit_threads_disable(X) + + +#endif /* PIKE_THREADS */ + +#ifndef CHECK_INTERPRETER_LOCK +#define CHECK_INTERPRETER_LOCK() do {} while (0) +#endif + +#ifdef __NT__ +#ifndef PIKE_DEBUG +#define CheckValidHandle(X) (X) +#else +PMOD_EXPORT HANDLE CheckValidHandle(HANDLE h); +#endif +#endif + +extern int threads_disabled; +PMOD_EXPORT extern ptrdiff_t thread_storage_offset; +PMOD_EXPORT extern struct program *thread_id_prog; + +#ifndef NO_PIKE_SHORTHAND +#define MUTEX_T PIKE_MUTEX_T +#endif + + +/* Initializer macros for static mutex and condition variables */ +#ifdef PTHREAD_MUTEX_INITIALIZER +#define STATIC_MUTEX_INIT = PTHREAD_MUTEX_INITIALIZER +#else +#define STATIC_MUTEX_INIT +#endif +#ifdef PTHREAD_COND_INITIALIZER +#define STATIC_COND_INIT = PTHREAD_COND_INITIALIZER +#else +#define STATIC_COND_INIT +#endif + + +#endif /* PIKE_THREADLIB_H */ + diff --git a/src/program.c b/src/program.c index 38367f10216fc06bd5dcf5a6422ee781591e5ecb..63967500a3a7dd075ef62c9d86a42256d2ea631a 100644 --- a/src/program.c +++ b/src/program.c @@ -5,7 +5,7 @@ \*/ /**/ #include "global.h" -RCSID("$Id: program.c,v 1.308 2001/04/01 15:40:21 grubba Exp $"); +RCSID("$Id: program.c,v 1.309 2001/04/07 07:38:25 hubbe Exp $"); #include "program.h" #include "object.h" #include "dynamic_buffer.h" @@ -1108,12 +1108,11 @@ struct program *low_allocate_program(void) p->alignment_needed=1; GC_ALLOC(p); - p->refs=1; p->id=++current_program_id; + INIT_PIKE_MEMOBJ(p); DOUBLELINK(first_program, p); GETTIMEOFDAY(& p->timestamp); - INITIALIZE_PROT(p); return p; } @@ -1395,7 +1394,7 @@ PMOD_EXPORT void really_free_program(struct program *p) #include "program_areas.h" } - FREE_PROT(p); + EXIT_PIKE_MEMOBJ(p); dmfree((char *)p); GC_FREE(p); diff --git a/src/program.h b/src/program.h index 515c9093f2e93be3e59238c47f7176f217d6060a..b612b29ca510ac28ba5a635efe538cd0edc998d0 100644 --- a/src/program.h +++ b/src/program.h @@ -5,7 +5,7 @@ \*/ /* - * $Id: program.h,v 1.122 2001/03/29 02:54:10 per Exp $ + * $Id: program.h,v 1.123 2001/04/07 07:38:25 hubbe Exp $ */ #ifndef PROGRAM_H #define PROGRAM_H @@ -269,10 +269,8 @@ enum pike_program_event struct program { - INT32 refs; -#ifdef PIKE_SECURITY - struct object *prot; -#endif + PIKE_MEMORY_OBJECT_MEMBERS; /* Must be first */ + INT32 id; /* used to identify program in caches */ INT32 parent_program_id; /* storage_needed - storage needed in object struct diff --git a/src/svalue.h b/src/svalue.h index fa38ad84bf1b4e1fdc00a6fc64160c0a4d49853f..bdcff2f28d752f628f396f8b6570f304c43604ed 100644 --- a/src/svalue.h +++ b/src/svalue.h @@ -5,7 +5,7 @@ \*/ /* - * $Id: svalue.h,v 1.86 2001/03/30 02:52:26 hubbe Exp $ + * $Id: svalue.h,v 1.87 2001/04/07 07:38:25 hubbe Exp $ */ #ifndef SVALUE_H #define SVALUE_H @@ -52,11 +52,8 @@ struct processing struct processing *next; void *pointer_a, *pointer_b; }; - -struct ref_dummy -{ - INT32 refs; -}; + +struct ref_dummy; union anything { @@ -274,9 +271,24 @@ do{ \ #ifdef PIKE_RUN_UNLOCKED #define add_ref(X) pike_atomic_inc32(&(X)->refs) #define sub_ref(X) pike_atomic_dec_and_test32(&(X)->refs) + +#if 0 +#define IF_LOCAL_MUTEX(X) X +#define USE_LOCAL_MUTEX +#define pike_lock_data(X) mt_lock(&(X)->mutex) +#define pike_unlock_data(X) mt_unlock(&(X)->mutex) #else +#define IF_LOCAL_MUTEX(X) +#define pike_lock_data(X) pike_lockmem((X)) +#define pike_unlock_data(X) pike_unlockmem((X)) +#endif + +#else +#define IF_LOCAL_MUTEX(X) #define add_ref(X) (void)((X)->refs++) #define sub_ref(X) (--(X)->refs) +#define pike_lock_data(X) (void)(X) +#define pike_unlock_data(X) (void)(X) #endif @@ -621,6 +633,40 @@ static inline void assign_svalue(struct svalue *to, struct svalue *from) #define assign_svalue assign_svalue_unlocked #endif /* FOO_PIKE_RUN_UNLOCKED */ +#ifdef PIKE_RUN_UNLOCKED +#include "pike_threadlib.h" +#endif + +/* + * Note to self: + * It might be better to use a static array of mutexes instead + * and just lock mutex ptr % array_size instead. + * That way I wouldn't need a mutex in each memory object, + * but it would cost a couple of cycles in every lock/unlock + * operation instead. + */ +#define PIKE_MEMORY_OBJECT_MEMBERS \ + INT32 refs \ + DO_IF_SECURITY(; struct object *prot) \ + IF_LOCAL_MUTEX(; PIKE_MUTEX_T mutex) + +#define INIT_PIKE_MEMOBJ(X) do { \ + struct ref_dummy *v_=(struct ref_dummy *)(X); \ + v_->refs=1; \ + DO_IF_SECURITY( INITIALIZE_PROT(v_) ); \ + IF_LOCAL_MUTEX(mt_init_recursive(&(v_->mutex))); \ +}while(0) + +#define EXIT_PIKE_MEMOBJ(X) do { \ + struct ref_dummy *v_=(struct ref_dummy *)(X); \ + DO_IF_SECURITY( FREE_PROT(v_) ); \ + IF_LOCAL_MUTEX(mt_destroy(&(v_->mutex))); \ +}while(0) + +struct ref_dummy +{ + PIKE_MEMORY_OBJECT_MEMBERS; +}; #endif /* !SVALUE_H */ diff --git a/src/threads.h b/src/threads.h index 19086f0045a5cdafd6e15ccd6dbf0d1d5fd89df8..d4e6848f82254c6a61fa87003a0de745b5e6ac89 100644 --- a/src/threads.h +++ b/src/threads.h @@ -1,5 +1,5 @@ /* - * $Id: threads.h,v 1.112 2001/02/28 04:21:53 hubbe Exp $ + * $Id: threads.h,v 1.113 2001/04/07 07:38:26 hubbe Exp $ */ #ifndef THREADS_H #define THREADS_H @@ -8,333 +8,8 @@ #include "object.h" #include "pike_error.h" #include "interpret.h" +#include "pike_threadlib.h" -/* Needed for the sigset_t typedef, which is needed for - * the pthread_sigsetmask() prototype on Solaris 2.x. - */ -#include <signal.h> - -#ifdef HAVE_SYS_TYPES_H -/* Needed for pthread_t on OSF/1 */ -#include <sys/types.h> -#endif /* HAVE_SYS_TYPES_H */ -#ifdef PIKE_THREADS - -/* The fp macro conflicts with Solaris's <pthread.h>. */ -#ifdef fp -#undef fp -#define FRAMEPOINTER_WAS_DEFINED -#endif /* fp */ - -/* - * Decide which type of threads to use - * - * UNIX_THREADS : Unix international threads - * POSIX_THREADS : POSIX standard threads - * SGI_SPROC_THREADS : SGI sproc() based threads - * NT_THREADS : NT threads - */ - -#ifdef _UNIX_THREADS -#ifdef HAVE_THREAD_H -#define UNIX_THREADS -#include <thread.h> -#undef HAVE_PTHREAD_H -#undef HAVE_THREAD_H -#endif -#endif /* _UNIX_THREADS */ - -#ifdef _MIT_POSIX_THREADS -#define POSIX_THREADS -#include <pthread.h> - -/* AIX is *STUPID* - Hubbe */ -#undef func_data - -#undef HAVE_PTHREAD_H -#endif /* _MIT_POSIX_THREADS */ - -#ifdef _SGI_SPROC_THREADS -/* Not supported yet */ -#undef SGI_SPROC_THREADS -#undef HAVE_SPROC -#endif /* _SGI_SPROC_THREADS */ - - - -/* Restore the fp macro. */ -#ifdef FRAMEPOINTER_WAS_DEFINED -#define fp Pike_fp -#undef FRAMEPOINTER_WAS_DEFINED -#endif /* FRAMEPOINTER_WAS_DEFINED */ - - -extern int num_threads; -PMOD_EXPORT extern int live_threads; -struct object; -PMOD_EXPORT extern size_t thread_stack_size; - -#define DEFINE_MUTEX(X) PIKE_MUTEX_T X - - -#ifdef POSIX_THREADS - -#ifdef HAVE_PTHREAD_ATFORK -#define th_atfork(X,Y,Z) pthread_atfork((X),(Y),(Z)) -#define th_atfork_prepare() -#define th_atfork_parent() -#define th_atfork_child() -#else -int th_atfork(void (*)(void),void (*)(void),void (*)(void)); -void th_atfork_prepare(void); -void th_atfork_parent(void); -void th_atfork_child(void); -#endif - -#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 -#endif - -#ifdef HAVE_PTHREAD_MUTEX_RECURSIVE_NP -#define mt_init_recursive(X) \ - do{ \ - pthread_mutexattr_t attr; \ - pthread_mutexattr_init(&attr); \ - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); \ - pthread_mutex_init((X), &attr); \ - }while(0) -#endif - -#define mt_lock(X) 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) - -/* SIGH! No setconcurrency in posix threads. This is more or less - * needed to make usable multi-threaded programs on solaris machines - * with only one CPU. Otherwise, only systemcalls are actually - * threaded. - */ -#define th_setconcurrency(X) -#ifdef HAVE_PTHREAD_YIELD -#define th_yield() pthread_yield() -#else -#define th_yield() -#endif /* HAVE_PTHREAD_YIELD */ -extern pthread_attr_t pattr; -extern pthread_attr_t small_pattr; - -#define th_create(ID,fun,arg) pthread_create(ID,&pattr,fun,arg) -#define th_create_small(ID,fun,arg) pthread_create(ID,&small_pattr,fun,arg) -#define th_exit(foo) pthread_exit(foo) -#define th_self() pthread_self() - -#define TH_KEY_T pthread_key_t -#define th_key_create pthread_key_create -#define th_setspecific pthread_setspecific -#define th_getspecific pthread_getspecific - - -#ifdef HAVE_PTHREAD_KILL -#define th_kill(ID,sig) 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)) -#ifdef HAVE_PTHREAD_COND_INIT -#define COND_T pthread_cond_t - -#ifdef HAVE_PTHREAD_CONDATTR_DEFAULT_AIX -/* AIX wants the & ... */ -#define co_init(X) pthread_cond_init((X), &pthread_condattr_default) -#else /* !HAVE_PTHREAD_CONDATTR_DEFAULT_AIX */ -#ifdef HAVE_PTHREAD_CONDATTR_DEFAULT -/* ... while FreeBSD doesn't. */ -#define co_init(X) pthread_cond_init((X), pthread_condattr_default) -#else /* !HAVE_PTHREAD_CONDATTR_DEFAULT */ -#define co_init(X) pthread_cond_init((X), 0) -#endif /* HAVE_PTHREAD_CONDATTR_DEFAULT */ -#endif /* HAVE_PTHREAD_CONDATTR_DEFAULT_AIX */ - -#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) -#else -#error No way to make cond-vars -#endif /* HAVE_PTHREAD_COND_INIT */ - -#endif /* POSIX_THREADS */ - - - - -#ifdef UNIX_THREADS -#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_trylock(X) mutex_trylock(X) -#define mt_unlock(X) mutex_unlock(X) -#define mt_destroy(X) mutex_destroy(X) - -#define th_setconcurrency(X) thr_setconcurrency(X) - -#define th_create(ID,fun,arg) thr_create(NULL,thread_stack_size,fun,arg,THR_DAEMON|THR_DETACHED,ID) -#define th_create_small(ID,fun,arg) thr_create(NULL,8192*sizeof(char *),fun,arg,THR_DAEMON|THR_DETACHED,ID) -#define th_exit(foo) thr_exit(foo) -#define th_self() thr_self() -#define th_kill(ID,sig) thr_kill((ID),(sig)) -#define th_yield() thr_yield() -#define th_join(ID,res) thr_join((ID), NULL, (res)) - -#define COND_T cond_t -#define co_init(X) cond_init((X),USYNC_THREAD,0) -#define co_wait(COND, MUTEX) cond_wait((COND), (MUTEX)) -#define co_signal(X) cond_signal(X) -#define co_broadcast(X) cond_broadcast(X) -#define co_destroy(X) cond_destroy(X) - - -#endif /* UNIX_THREADS */ - -#ifdef SGI_SPROC_THREADS - -/* - * Not fully supported yet - */ -#define THREAD_T int - -#define PIKE_MUTEX_T ulock_t -#define mt_init(X) (usinitlock(((*X) = usnewlock(/*********/)))) -#define mt_lock(X) ussetlock(*X) -#define mt_unlock(X) usunsetlock(*X) -#define mt_destroy(X) usfreelock((*X), /*******/) - -#define th_setconcurrency(X) /*******/ - -#define PIKE_SPROC_FLAGS (PR_SADDR|PR_SFDS|PR_SDIR|PS_SETEXITSIG) -#define th_create(ID, fun, arg) (((*(ID)) = sproc(fun, PIKE_SPROC_FLAGS, arg)) == -1) -#define th_create_small(ID, fun, arg) (((*(ID)) = sproc(fun, PIKE_SPROC_FLAGS, arg)) == -1) -#define th_exit(X) exit(X) -#define th_self() getpid() -#define th_yield() sginap(0) -#define th_join(ID,res) /*********/ -#define th_equal(X,Y) ((X)==(Y)) -#define th_hash(X) ((unsigned INT32)(X)) - -/* - * No cond_vars yet - */ - -#endif /* SGI_SPROC_THREADS */ - - -#ifdef NT_THREADS -#include <process.h> -#include <windows.h> - -#define THREAD_T unsigned -#define th_setconcurrency(X) -#define th_create(ID,fun,arg) low_nt_create_thread(2*1024*1024,fun, arg,ID) -#define th_create_small(ID,fun,arg) low_nt_create_thread(8192*sizeof(char *), fun,arg,ID) -#define TH_RETURN_TYPE unsigned __stdcall -#define TH_STDCALL __stdcall -#define th_exit(foo) _endthreadex(foo) -#define th_join(ID,res) /******************* FIXME! ****************/ -#define th_self() GetCurrentThreadId() -#define th_destroy(X) -#define th_yield() Sleep(0) -#define th_equal(X,Y) ((X)==(Y)) -#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 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) - -#endif - - -#if !defined(COND_T) && defined(EVENT_T) && defined(PIKE_MUTEX_T) - -#define SIMULATE_COND_WITH_EVENT - -struct cond_t_queue -{ - struct cond_t_queue *next; - EVENT_T event; -}; - -typedef struct cond_t_s -{ - PIKE_MUTEX_T lock; - struct cond_t_queue *head, *tail; -} COND_T; - -#define COND_T struct cond_t_s - -#define co_init(X) do { mt_init(& (X)->lock), (X)->head=(X)->tail=0; }while(0) - -PMOD_EXPORT int co_wait(COND_T *c, PIKE_MUTEX_T *m); -PMOD_EXPORT int co_signal(COND_T *c); -PMOD_EXPORT int co_broadcast(COND_T *c); -PMOD_EXPORT int co_destroy(COND_T *c); - -#endif - -extern int th_running; - -PMOD_EXPORT extern PIKE_MUTEX_T interpreter_lock; - -#if defined(PIKE_DEBUG) && !defined(__NT__) - -/* This is a debug wrapper to enable checks that the interpreter lock - * is hold by the current thread. */ - -extern THREAD_T debug_locking_thread; -#define SET_LOCKING_THREAD (debug_locking_thread = th_self(), 0) - -#define mt_lock_interpreter() (mt_lock(&interpreter_lock) || SET_LOCKING_THREAD) -#define mt_trylock_interpreter() (mt_trylock(&interpreter_lock) || SET_LOCKING_THREAD) -#define mt_unlock_interpreter() (mt_unlock(&interpreter_lock)) -#define co_wait_interpreter(COND) \ - do {co_wait((COND), &interpreter_lock); SET_LOCKING_THREAD;} while (0) - -#define CHECK_INTERPRETER_LOCK() do { \ - if (th_running) { \ - THREAD_T self; \ - if (!mt_trylock(&interpreter_lock)) \ - fatal("Interpreter is not locked.\n"); \ - self = th_self(); \ - if (!th_equal(debug_locking_thread, self)) \ - fatal("Interpreter is not locked by this thread.\n"); \ - } \ -} while (0) - -#else - -#define mt_lock_interpreter() (mt_lock(&interpreter_lock)) -#define mt_trylock_interpreter() (mt_trylock(&interpreter_lock)) -#define mt_unlock_interpreter() (mt_unlock(&interpreter_lock)) -#define co_wait_interpreter(COND) do {co_wait((COND), &interpreter_lock);} while (0) - -#endif PMOD_EXPORT extern COND_T live_threads_change; /* Used by _disable_threads */ PMOD_EXPORT extern COND_T threads_disabled_change; /* Used by _disable_threads */ @@ -390,201 +65,7 @@ struct thread_state { #endif /* PROFILING */ }; - -#ifndef TH_RETURN_TYPE -#define TH_RETURN_TYPE void * -#endif - -#ifndef TH_STDCALL -#define TH_STDCALL -#endif - -#ifndef th_destroy -#define th_destroy(X) -#endif - -#ifndef th_yield -#define th_yield() -#endif - -#ifndef th_equal -#define th_equal(X,Y) (!MEMCMP(&(X),&(Y),sizeof(THREAD_T))) -#endif - -#ifndef th_hash -#define th_hash(X) hashmem((unsigned char *)&(X),sizeof(THREAD_T), 16) -#endif - -/* Define to get a debug-trace of some of the threads operations. */ -/* #define VERBOSE_THREADS_DEBUG 0 */ /* Some debug */ -/* #define VERBOSE_THREADS_DEBUG 1 */ /* Lots of debug */ - -#ifndef VERBOSE_THREADS_DEBUG -#define THREADS_FPRINTF(L,X) -#else -#define THREADS_FPRINTF(L,X) do { \ - if ((VERBOSE_THREADS_DEBUG + 0) >= (L)) fprintf X; \ - } while(0) -#endif /* VERBOSE_THREADS_DEBUG */ - -#ifdef THREAD_TRACE -PMOD_EXPORT extern int t_flag; -#define SWAP_OUT_TRACE(_tmp) do { (_tmp)->status.t_flag = t_flag; } while(0) -#define SWAP_IN_TRACE(_tmp) do { t_flag = (_tmp)->status.t_flag; } while(0) -#else /* !THREAD_TRACE */ -#define SWAP_OUT_TRACE(_tmp) -#define SWAP_IN_TRACE(_tmp) -#endif /* THREAD_TRACE */ - -#if defined(PROFILING) && defined(HAVE_GETHRTIME) -#define DO_IF_PROFILING(X) X -#else -#define DO_IF_PROFILING(X) -#endif - -#define SWAP_OUT_THREAD(_tmp) do { \ - (_tmp)->state=Pike_interpreter; \ - (_tmp)->swapped=1; \ - DO_IF_PROFILING( (_tmp)->time_base += gethrtime() ; ) \ - } while(0) - -#define SWAP_IN_THREAD(_tmp) do { \ - (_tmp)->swapped=0; \ - Pike_interpreter=(_tmp)->state; \ - DO_IF_PROFILING( Pike_interpreter.time_base -= gethrtime();) \ - } while(0) - -#define SWAP_OUT_CURRENT_THREAD() \ - do {\ - struct thread_state *_tmp=OBJ2THREAD(Pike_interpreter.thread_id); \ - SWAP_OUT_THREAD(_tmp); \ - THREADS_FPRINTF(1, (stderr, "SWAP_OUT_CURRENT_THREAD() %s:%d t:%08x\n", \ - __FILE__, __LINE__, (unsigned int)_tmp->thread_id)) \ - -#define SWAP_IN_CURRENT_THREAD() \ - THREADS_FPRINTF(1, (stderr, "SWAP_IN_CURRENT_THREAD() %s:%d ... t:%08x\n", \ - __FILE__, __LINE__, (unsigned int)_tmp->thread_id)); \ - SWAP_IN_THREAD(_tmp);\ - } while(0) - -#if defined(PIKE_DEBUG) && ! defined(DONT_HIDE_GLOBALS) -/* Note that scalar types are used in place of pointers and vice versa - * below. This is intended to cause compiler warnings/errors if - * there is an attempt to use the global variables in an unsafe - * environment. - */ -#define HIDE_GLOBAL_VARIABLES() do { \ - int Pike_interpreter =0; \ - int pop_n_elems = 0; \ - int push_sp_mark = 0, pop_sp_mark = 0, threads_disabled = 1 - -/* Note that the semi-colon below is needed to add an empty statement - * in case there is a label before the macro. - */ -#define REVEAL_GLOBAL_VARIABLES() ; } while(0) -#else /* PIKE_DEBUG */ -#define HIDE_GLOBAL_VARIABLES() -#define REVEAL_GLOBAL_VARIABLES() -#endif /* PIKE_DEBUG */ - -#define OBJ2THREAD(X) \ - ((struct thread_state *)((X)->storage+thread_storage_offset)) - -#define THREADSTATE2OBJ(X) ((X)->state.thread_id) - -PMOD_EXPORT extern int Pike_in_gc; -#define THREADS_ALLOW() do { \ - struct thread_state *_tmp=OBJ2THREAD(Pike_interpreter.thread_id); \ - DO_IF_DEBUG({ \ - if(thread_for_id(th_self()) != Pike_interpreter.thread_id) \ - fatal("thread_for_id() (or Pike_interpreter.thread_id) failed!" \ - " %p != %p\n", \ - thread_for_id(th_self()), Pike_interpreter.thread_id); \ - if (Pike_in_gc > 50 && Pike_in_gc < 300) \ - fatal("Threads allowed during garbage collection.\n"); \ - }) \ - if(num_threads > 1 && !threads_disabled) { \ - SWAP_OUT_THREAD(_tmp); \ - THREADS_FPRINTF(1, (stderr, "THREADS_ALLOW() %s:%d t:%08x(#%d)\n", \ - __FILE__, __LINE__, \ - (unsigned int)_tmp->thread_id, live_threads)); \ - mt_unlock_interpreter(); \ - } else {} \ - HIDE_GLOBAL_VARIABLES() - -#define THREADS_DISALLOW() \ - REVEAL_GLOBAL_VARIABLES(); \ - if(_tmp->swapped) { \ - mt_lock_interpreter(); \ - THREADS_FPRINTF(1, (stderr, "THREADS_DISALLOW() %s:%d t:%08x(#%d)\n", \ - __FILE__, __LINE__, \ - (unsigned int)_tmp->thread_id, live_threads)); \ - while (threads_disabled) { \ - THREADS_FPRINTF(1, (stderr, \ - "THREADS_DISALLOW(): Threads disabled\n")); \ - co_wait_interpreter(&threads_disabled_change); \ - } \ - SWAP_IN_THREAD(_tmp);\ - } \ - DO_IF_DEBUG( if(thread_for_id(th_self()) != Pike_interpreter.thread_id) \ - fatal("thread_for_id() (or Pike_interpreter.thread_id) failed! %p != %p\n",thread_for_id(th_self()),Pike_interpreter.thread_id) ; ) \ - } while(0) - -#define THREADS_ALLOW_UID() do { \ - struct thread_state *_tmp_uid=OBJ2THREAD(Pike_interpreter.thread_id); \ - DO_IF_DEBUG({ \ - if(thread_for_id(th_self()) != Pike_interpreter.thread_id) { \ - fatal("thread_for_id() (or Pike_interpreter.thread_id) failed! %p != %p\n", \ - thread_for_id(th_self()),Pike_interpreter.thread_id); \ - } \ - if ((Pike_in_gc > 50) && (Pike_in_gc < 300)) { \ - fprintf(stderr, __FILE__ ":" DEFINETOSTR(__LINE__) ": Fatal error:\n"); \ - debug_fatal("Threads allowed during garbage collection (%d).\n", \ - Pike_in_gc); \ - } \ - }) \ - if(num_threads > 1 && !threads_disabled) { \ - SWAP_OUT_THREAD(_tmp_uid); \ - live_threads++; \ - THREADS_FPRINTF(1, (stderr, "THREADS_ALLOW_UID() %s:%d t:%08x(#%d)\n", \ - __FILE__, __LINE__, \ - (unsigned int)_tmp_uid->thread_id, live_threads)); \ - mt_unlock_interpreter(); \ - } else {} \ - HIDE_GLOBAL_VARIABLES() - -#define THREADS_DISALLOW_UID() \ - REVEAL_GLOBAL_VARIABLES(); \ - if(_tmp_uid->swapped) { \ - mt_lock_interpreter(); \ - live_threads--; \ - THREADS_FPRINTF(1, (stderr, \ - "THREADS_DISALLOW_UID() %s:%d t:%08x(#%d)\n", \ - __FILE__, __LINE__, \ - (unsigned int)_tmp_uid->thread_id, live_threads)); \ - co_broadcast(&live_threads_change); \ - while (threads_disabled) { \ - THREADS_FPRINTF(1, (stderr, "THREADS_DISALLOW_UID(): Wait...\n")); \ - co_wait_interpreter(&threads_disabled_change); \ - } \ - SWAP_IN_THREAD(_tmp_uid);\ - } \ - } while(0) - -#define SWAP_IN_THREAD_IF_REQUIRED() do { \ - struct thread_state *_tmp=thread_state_for_id(th_self()); \ - HIDE_GLOBAL_VARIABLES(); \ - THREADS_DISALLOW() - -#ifdef PIKE_DEBUG -#define ASSERT_THREAD_SWAPPED_IN() do { \ - struct thread_state *_tmp=thread_state_for_id(th_self()); \ - if(_tmp->swapped) fatal("Thread is not swapped in!\n"); \ - }while(0) - -#else -#define ASSERT_THREAD_SWAPPED_IN() -#endif +#ifdef PIKE_THREADS /* Prototypes begin here */ int low_nt_create_thread(unsigned Pike_stack_size, @@ -638,77 +119,6 @@ int th_num_farmers(void); PMOD_EXPORT void th_farm(void (*fun)(void *), void *here); /* Prototypes end here */ -#else - -#define th_atfork(X,Y,Z) -#define th_atfork_prepare() -#define th_atfork_parent() -#define th_atfork_child() - -#define th_setconcurrency(X) -#define DEFINE_MUTEX(X) -#define DEFINE_IMUTEX(X) -#define init_interleave_mutex(X) -#define LOCK_IMUTEX(X) -#define UNLOCK_IMUTEX(X) -#define mt_init(X) -#define mt_lock(X) -#define mt_unlock(X) -#define mt_destroy(X) -#define THREADS_ALLOW() -#define THREADS_DISALLOW() -#define THREADS_ALLOW_UID() -#define THREADS_DISALLOW_UID() -#define HIDE_GLOBAL_VARIABLES() -#define REVEAL_GLOBAL_VARIABLES() -#define ASSERT_THREAD_SWAPPED_IN() -#define SWAP_IN_THREAD_IF_REQUIRED() -#define th_init() -#define low_th_init() -#define th_cleanup() -#define th_init_programs() -#define th_self() ((void*)0) -#define co_signal(X) -#define co_broadcast(X) - -#define low_init_threads_disable() -#define init_threads_disable(X) -#define exit_threads_disable(X) - - -#endif /* PIKE_THREADS */ - -#ifndef CHECK_INTERPRETER_LOCK -#define CHECK_INTERPRETER_LOCK() do {} while (0) -#endif - -#ifdef __NT__ -#ifndef PIKE_DEBUG -#define CheckValidHandle(X) (X) -#else -PMOD_EXPORT HANDLE CheckValidHandle(HANDLE h); -#endif -#endif - -extern int threads_disabled; -PMOD_EXPORT extern ptrdiff_t thread_storage_offset; -PMOD_EXPORT extern struct program *thread_id_prog; - -#ifndef NO_PIKE_SHORTHAND -#define MUTEX_T PIKE_MUTEX_T -#endif - - -/* Initializer macros for static mutex and condition variables */ -#ifdef PTHREAD_MUTEX_INITIALIZER -#define STATIC_MUTEX_INIT = PTHREAD_MUTEX_INITIALIZER -#else -#define STATIC_MUTEX_INIT -#endif -#ifdef PTHREAD_COND_INITIALIZER -#define STATIC_COND_INIT = PTHREAD_COND_INITIALIZER -#else -#define STATIC_COND_INIT #endif