Main Page | Class List | Directories | File List | Class Members | File Members

pike_threadlib.h

Go to the documentation of this file.
00001 /*
00002 || This file is part of Pike. For copyright information see COPYRIGHT.
00003 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
00004 || for more information.
00005 || $Id: pike_threadlib.h,v 1.58 2004/12/30 13:41:08 grubba Exp $
00006 */
00007 
00008 #ifndef PIKE_THREADLIB_H
00009 #define PIKE_THREADLIB_H
00010 
00011 /*
00012  * This file is for the low-level thread interface functions
00013  * 'threads.h' is for anything that concerns the object interface
00014  * for pike threads.
00015  */
00016 
00017 
00018 #ifndef CONFIGURE_TEST
00019 #include "machine.h"
00020 #include "pike_embed.h"
00021 #include "pike_rusage.h"
00022 #endif
00023 
00024 /* Needed for the sigset_t typedef, which is needed for
00025  * the pthread_sigsetmask() prototype on Solaris 2.x.
00026  */
00027 #include <signal.h>
00028 
00029 #ifdef HAVE_SYS_TYPES_H
00030 /* Needed for pthread_t on OSF/1 */
00031 #include <sys/types.h>
00032 #endif /* HAVE_SYS_TYPES_H */
00033 
00034 extern int threads_disabled;
00035 PMOD_EXPORT extern ptrdiff_t thread_storage_offset;
00036 PMOD_EXPORT extern struct program *thread_id_prog;
00037 
00038 #ifdef PIKE_THREADS
00039 
00040 /* The fp macro conflicts with Solaris's <pthread.h>. */
00041 #ifdef fp
00042 #undef fp
00043 #define FRAMEPOINTER_WAS_DEFINED
00044 #endif /* fp */
00045 
00046 /*
00047  * Decide which type of threads to use
00048  *
00049  * UNIX_THREADS      : Unix international threads
00050  * POSIX_THREADS     : POSIX standard threads
00051  * SGI_SPROC_THREADS : SGI sproc() based threads
00052  * NT_THREADS        : NT threads
00053  */
00054 
00055 #ifdef _UNIX_THREADS
00056 #ifdef HAVE_THREAD_H
00057 #define UNIX_THREADS
00058 #include <thread.h>
00059 #undef HAVE_PTHREAD_H
00060 #undef HAVE_THREAD_H
00061 #endif
00062 #endif /* _UNIX_THREADS */
00063 
00064 #ifdef _MIT_POSIX_THREADS
00065 #define POSIX_THREADS
00066 #include <pthread.h>
00067 
00068 /* AIX is *STUPID* - Hubbe */
00069 #undef func_data
00070 
00071 /* So is OSF/1 - Marcus */
00072 #undef try
00073 #undef except
00074 #undef finally
00075 #undef leave
00076 
00077 #undef HAVE_PTHREAD_H
00078 #endif /* _MIT_POSIX_THREADS */
00079 
00080 #ifdef _SGI_SPROC_THREADS
00081 /* Not supported yet */
00082 #undef SGI_SPROC_THREADS
00083 #undef HAVE_SPROC
00084 #endif /* _SGI_SPROC_THREADS */
00085 
00086 #ifdef HAVE_THREAD_H
00087 #include <thread.h>
00088 #endif
00089 
00090 #ifdef HAVE_MACH_TASK_INFO_H
00091 #include <mach/task_info.h>
00092 #endif
00093 #ifdef HAVE_MACH_TASK_H
00094 #include <mach/task.h>
00095 #endif
00096 #ifdef HAVE_MACH_MACH_INIT_H
00097 #include <mach/mach_init.h>
00098 #endif
00099 
00100 
00101 /* Restore the fp macro. */
00102 #ifdef FRAMEPOINTER_WAS_DEFINED
00103 #define fp Pike_fp
00104 #undef FRAMEPOINTER_WAS_DEFINED
00105 #endif /* FRAMEPOINTER_WAS_DEFINED */
00106 
00107 
00108 extern int num_threads;
00109 PMOD_EXPORT extern int live_threads, disallow_live_threads;
00110 struct object;
00111 PMOD_EXPORT extern size_t thread_stack_size;
00112 
00113 PMOD_EXPORT void thread_low_error (int errcode, const char *cmd,
00114                                    const char *fname, int lineno);
00115 
00116 #define LOW_THREAD_CHECK_NONZERO_ERROR(CALL) do {                       \
00117     int thread_errcode_ = (CALL);                                       \
00118     if (thread_errcode_)                                                \
00119       thread_low_error(thread_errcode_, TOSTR(CALL),                    \
00120                        __FILE__, __LINE__);                             \
00121   } while (0)
00122 
00123 #ifdef CONFIGURE_TEST
00124 #define USE_ERRORCHECK_MUTEX 1
00125 #else
00126 #define USE_ERRORCHECK_MUTEX (debug_options & ERRORCHECK_MUTEXES)
00127 #endif
00128 
00129 #define DEFINE_MUTEX(X) PIKE_MUTEX_T X
00130 
00131 
00132 #ifdef POSIX_THREADS
00133 
00134 #ifdef HAVE_PTHREAD_ATFORK
00135 #define th_atfork(X,Y,Z) pthread_atfork((X),(Y),(Z))
00136 #define th_atfork_prepare()
00137 #define th_atfork_parent()
00138 #define th_atfork_child()
00139 #else
00140 int th_atfork(void (*)(void),void (*)(void),void (*)(void));
00141 void th_atfork_prepare(void);
00142 void th_atfork_parent(void);
00143 void th_atfork_child(void);
00144 #endif
00145 
00146 #define THREAD_T pthread_t
00147 #define PIKE_MUTEX_T pthread_mutex_t
00148 
00149 #ifdef PIKE_MUTEX_ERRORCHECK
00150 #define mt_init(X) do {                                                 \
00151     if (USE_ERRORCHECK_MUTEX) {                                         \
00152       pthread_mutexattr_t attr;                                         \
00153       pthread_mutexattr_init(&attr);                                    \
00154       pthread_mutexattr_settype(&attr, PIKE_MUTEX_ERRORCHECK);          \
00155       pthread_mutex_init((X), &attr);                                   \
00156     }                                                                   \
00157     else                                                                \
00158       pthread_mutex_init((X),0);                                        \
00159   } while (0)
00160 #define DO_IF_PIKE_MUTEX_ERRORCHECK(X) X
00161 #else
00162 #define mt_init(X) pthread_mutex_init((X),0)
00163 #define DO_IF_PIKE_MUTEX_ERRORCHECK(X)
00164 #endif
00165 
00166 #ifdef PIKE_MUTEX_RECURSIVE
00167 #define mt_init_recursive(X)                                            \
00168     do{ \
00169       pthread_mutexattr_t attr;                                 \
00170       pthread_mutexattr_init(&attr);                                    \
00171       pthread_mutexattr_settype(                                        \
00172         &attr,                                                          \
00173         PIKE_MUTEX_RECURSIVE                                            \
00174         DO_IF_PIKE_MUTEX_ERRORCHECK (| PIKE_MUTEX_ERRORCHECK));         \
00175       pthread_mutex_init((X), &attr);                                   \
00176     }while(0)
00177 #endif
00178 
00179 #define mt_lock(X) LOW_THREAD_CHECK_NONZERO_ERROR (pthread_mutex_lock(X))
00180 #define mt_trylock(X) pthread_mutex_trylock(X)
00181 #define mt_unlock(X) LOW_THREAD_CHECK_NONZERO_ERROR (pthread_mutex_unlock(X))
00182 #define mt_destroy(X) LOW_THREAD_CHECK_NONZERO_ERROR (pthread_mutex_destroy(X))
00183 
00184 /* SIGH! No setconcurrency in posix threads. This is more or less
00185  * needed to make usable multi-threaded programs on solaris machines
00186  * with only one CPU. Otherwise, only systemcalls are actually
00187  * threaded.
00188  */
00189 #define th_setconcurrency(X) 
00190 #ifdef HAVE_PTHREAD_YIELD
00191 #define low_th_yield()  pthread_yield()
00192 #else
00193 #ifdef HAVE_PTHREAD_YIELD_NP
00194 /* Some pthread libs define yield as non-portable function. */
00195 #define low_th_yield()  pthread_yield_np()
00196 #endif /* HAVE_PTHREAD_YIELD_NP */
00197 #endif /* HAVE_PTHREAD_YIELD */
00198 extern pthread_attr_t pattr;
00199 extern pthread_attr_t small_pattr;
00200 
00201 #define th_create(ID,fun,arg) pthread_create(ID,&pattr,fun,arg)
00202 #define th_create_small(ID,fun,arg) pthread_create(ID,&small_pattr,fun,arg)
00203 #define th_exit(foo) pthread_exit(foo)
00204 #define th_self() pthread_self()
00205 
00206 #define TH_KEY_T pthread_key_t
00207 #define th_key_create pthread_key_create
00208 #define th_setspecific pthread_setspecific
00209 #define th_getspecific pthread_getspecific
00210 
00211 
00212 #ifdef HAVE_PTHREAD_KILL
00213 #define th_kill(ID,sig) LOW_THREAD_CHECK_NONZERO_ERROR (pthread_kill((ID),(sig)))
00214 #else /* !HAVE_PTHREAD_KILL */
00215 /* MacOS X (aka Darwin) prior to 10.2 doesn't have pthread_kill. */
00216 #define th_kill(ID,sig)
00217 #endif /* HAVE_PTHREAD_KILL */
00218 #ifdef HAVE_PTHREAD_COND_INIT
00219 #define COND_T pthread_cond_t
00220 
00221 #ifdef HAVE_PTHREAD_CONDATTR_DEFAULT_AIX
00222 /* AIX wants the & ... */
00223 #define co_init(X) pthread_cond_init((X), &pthread_condattr_default)
00224 #else /* !HAVE_PTHREAD_CONDATTR_DEFAULT_AIX */
00225 #ifdef HAVE_PTHREAD_CONDATTR_DEFAULT
00226 /* ... while FreeBSD doesn't. */
00227 #define co_init(X) pthread_cond_init((X), pthread_condattr_default)
00228 #else /* !HAVE_PTHREAD_CONDATTR_DEFAULT */
00229 #define co_init(X) pthread_cond_init((X), 0)
00230 #endif /* HAVE_PTHREAD_CONDATTR_DEFAULT */
00231 #endif /* HAVE_PTHREAD_CONDATTR_DEFAULT_AIX */
00232 
00233 #define co_wait(COND, MUTEX) pthread_cond_wait((COND), (MUTEX))
00234 #define co_signal(X) pthread_cond_signal(X)
00235 #define co_broadcast(X) pthread_cond_broadcast(X)
00236 #define co_destroy(X) LOW_THREAD_CHECK_NONZERO_ERROR (pthread_cond_destroy(X))
00237 #else
00238 #error No way to make cond-vars
00239 #endif /* HAVE_PTHREAD_COND_INIT */
00240 
00241 #endif /* POSIX_THREADS */
00242 
00243 
00244 
00245 
00246 #ifdef UNIX_THREADS
00247 #define THREAD_T thread_t
00248 #define PTHREAD_MUTEX_INITIALIZER DEFAULTMUTEX
00249 #define PIKE_MUTEX_T mutex_t
00250 #define mt_init(X) LOW_THREAD_CHECK_NONZERO_ERROR (mutex_init((X),USYNC_THREAD,0))
00251 #define mt_lock(X) LOW_THREAD_CHECK_NONZERO_ERROR (mutex_lock(X))
00252 #define mt_trylock(X) mutex_trylock(X)
00253 #define mt_unlock(X) LOW_THREAD_CHECK_NONZERO_ERROR (mutex_unlock(X))
00254 #define mt_destroy(X) LOW_THREAD_CHECK_NONZERO_ERROR (mutex_destroy(X))
00255 
00256 #define th_setconcurrency(X) thr_setconcurrency(X)
00257 
00258 #define th_create(ID,fun,arg) thr_create(NULL,thread_stack_size,fun,arg,THR_DAEMON|THR_DETACHED,ID)
00259 #define th_create_small(ID,fun,arg) thr_create(NULL,8192*sizeof(char *),fun,arg,THR_DAEMON|THR_DETACHED,ID)
00260 #define th_exit(foo) thr_exit(foo)
00261 #define th_self() thr_self()
00262 #define th_kill(ID,sig) thr_kill((ID),(sig))
00263 #define low_th_yield() thr_yield()
00264 
00265 #define COND_T cond_t
00266 #define co_init(X) cond_init((X),USYNC_THREAD,0)
00267 #define co_wait(COND, MUTEX) cond_wait((COND), (MUTEX))
00268 #define co_signal(X) cond_signal(X)
00269 #define co_broadcast(X) cond_broadcast(X)
00270 #define co_destroy(X) cond_destroy(X)
00271 
00272 
00273 #endif /* UNIX_THREADS */
00274 
00275 #ifdef SGI_SPROC_THREADS
00276 
00277 /*
00278  * Not fully supported yet
00279  */
00280 #define THREAD_T        int
00281 
00282 #define PIKE_MUTEX_T            ulock_t
00283 #define mt_init(X)      (usinitlock(((*X) = usnewlock(/*********/))))
00284 #define mt_lock(X)      ussetlock(*X)
00285 #define mt_unlock(X)    usunsetlock(*X)
00286 #define mt_destroy(X)   usfreelock((*X), /*******/)
00287 
00288 #define th_setconcurrency(X)    /*******/
00289 
00290 #define PIKE_SPROC_FLAGS        (PR_SADDR|PR_SFDS|PR_SDIR|PS_SETEXITSIG)
00291 #define th_create(ID, fun, arg) (((*(ID)) = sproc(fun, PIKE_SPROC_FLAGS, arg)) == -1)
00292 #define th_create_small(ID, fun, arg)   (((*(ID)) = sproc(fun, PIKE_SPROC_FLAGS, arg)) == -1)
00293 #define th_exit(X)      exit(X)
00294 #define th_self()       getpid()
00295 #define low_th_yield()  sginap(0)
00296 #define th_equal(X,Y) ((X)==(Y))
00297 #define th_hash(X) ((unsigned INT32)(X))
00298 
00299 /*
00300  * No cond_vars yet
00301  */
00302 
00303 #endif /* SGI_SPROC_THREADS */
00304 
00305 
00306 #ifdef NT_THREADS
00307 #include <process.h>
00308 #include <windows.h>
00309 
00310 #define LOW_THREAD_CHECK_ZERO_ERROR(CALL) do {                  \
00311     if (!(CALL))                                                \
00312       thread_low_error(GetLastError(), TOSTR(CALL),             \
00313                        __FILE__, __LINE__);                     \
00314   } while (0)
00315 
00316 #define THREAD_T unsigned
00317 #define th_setconcurrency(X)
00318 #define th_create(ID,fun,arg) low_nt_create_thread(thread_stack_size,fun, arg,ID)
00319 #define th_create_small(ID,fun,arg) low_nt_create_thread(8192*sizeof(char *), fun,arg,ID)
00320 #define TH_RETURN_TYPE unsigned __stdcall
00321 #define TH_STDCALL __stdcall
00322 #define th_exit(foo) _endthreadex(foo)
00323 #define th_self() GetCurrentThreadId()
00324 #define th_destroy(X)
00325 #define low_th_yield() Sleep(0)
00326 #define th_equal(X,Y) ((X)==(Y))
00327 #define th_hash(X) (X)
00328 
00329 #define PIKE_MUTEX_T HANDLE
00330 #define mt_init(X) LOW_THREAD_CHECK_ZERO_ERROR ((*(X)=CreateMutex(NULL, 0, NULL)))
00331 #define mt_lock(X)                                                      \
00332   LOW_THREAD_CHECK_ZERO_ERROR (                                         \
00333     WaitForSingleObject(CheckValidHandle(*(X)), INFINITE) == WAIT_OBJECT_0)
00334 #define mt_trylock(X)                                                   \
00335   LOW_THREAD_CHECK_ZERO_ERROR (                                         \
00336     WaitForSingleObject(CheckValidHandle(*(X)), 0) != WAIT_FAILED)
00337 #define mt_unlock(X) LOW_THREAD_CHECK_ZERO_ERROR (ReleaseMutex(CheckValidHandle(*(X))))
00338 #define mt_destroy(X) LOW_THREAD_CHECK_ZERO_ERROR (CloseHandle(CheckValidHandle(*(X))))
00339 
00340 #define EVENT_T HANDLE
00341 #define event_init(X) LOW_THREAD_CHECK_ZERO_ERROR (*(X)=CreateEvent(NULL, 1, 0, NULL))
00342 #define event_signal(X) LOW_THREAD_CHECK_ZERO_ERROR (SetEvent(CheckValidHandle(*(X))))
00343 #define event_destroy(X) LOW_THREAD_CHECK_ZERO_ERROR (CloseHandle(CheckValidHandle(*(X))))
00344 #define event_wait(X)                                                   \
00345   LOW_THREAD_CHECK_ZERO_ERROR (                                         \
00346     WaitForSingleObject(CheckValidHandle(*(X)), INFINITE) == WAIT_OBJECT_0)
00347 
00348 /* No fork -- no atfork */
00349 #define th_atfork(X,Y,Z)
00350 #define th_atfork_prepare()
00351 #define th_atfork_parent()
00352 #define th_atfork_child()
00353 
00354 #endif
00355 
00356 
00357 #if !defined(COND_T) && defined(EVENT_T) && defined(PIKE_MUTEX_T)
00358 
00359 #define SIMULATE_COND_WITH_EVENT
00360 
00361 struct cond_t_queue
00362 {
00363   struct cond_t_queue *next;
00364   EVENT_T event;
00365 };
00366 
00367 typedef struct cond_t_s
00368 {
00369   PIKE_MUTEX_T lock;
00370   struct cond_t_queue *head, *tail;
00371 } COND_T;
00372 
00373 #define COND_T struct cond_t_s
00374 
00375 #define co_init(X) do { mt_init(& (X)->lock); (X)->head=(X)->tail=0; }while(0)
00376 
00377 PMOD_EXPORT int co_wait(COND_T *c, PIKE_MUTEX_T *m);
00378 PMOD_EXPORT int co_signal(COND_T *c);
00379 PMOD_EXPORT int co_broadcast(COND_T *c);
00380 PMOD_EXPORT int co_destroy(COND_T *c);
00381 
00382 #endif
00383 
00384 #ifndef TH_RETURN_TYPE
00385 #define TH_RETURN_TYPE void *
00386 #endif
00387 
00388 #ifndef TH_STDCALL
00389 #define TH_STDCALL
00390 #endif
00391 
00392 #ifndef th_destroy
00393 #define th_destroy(X)
00394 #endif
00395 
00396 #ifndef low_th_yield
00397 #ifdef HAVE_THR_YIELD
00398 #define low_th_yield() thr_yield()
00399 #else
00400 #define low_th_yield() 0
00401 #define HAVE_NO_YIELD
00402 #endif
00403 #endif
00404 
00405 #ifndef th_equal
00406 #define th_equal(X,Y) (!MEMCMP(&(X),&(Y),sizeof(THREAD_T)))
00407 #endif
00408 
00409 #ifndef th_hash
00410 #define th_hash(X) hashmem((unsigned char *)&(X),sizeof(THREAD_T), 16)
00411 #endif
00412 
00413 #ifndef CONFIGURE_TEST
00414 
00415 struct interleave_mutex
00416 {
00417   struct interleave_mutex *next;
00418   struct interleave_mutex *prev;
00419   PIKE_MUTEX_T lock;
00420 };
00421 
00422 #define IMUTEX_T struct interleave_mutex
00423 
00424 #define DEFINE_IMUTEX(name) IMUTEX_T name
00425 
00426 /* If threads are disabled, we already hold the lock.
00427  *
00428  * NOTE: Threads are enabled during the locking operation.
00429  */
00430 #define LOCK_IMUTEX(im) do { \
00431     if (!threads_disabled) { \
00432       THREADS_FPRINTF(0, (stderr, "Locking IMutex 0x%p...\n", (im))); \
00433       THREADS_ALLOW(); \
00434       mt_lock(&((im)->lock)); \
00435       THREADS_DISALLOW(); \
00436     } \
00437   } while(0)
00438 
00439 /* If threads are disabled, the lock will be released later.
00440  *
00441  * NOTE: MUST be called in a THREADS_DISALLOW() context.
00442  */
00443 #define UNLOCK_IMUTEX(im) do { \
00444     if (!threads_disabled) { \
00445       THREADS_FPRINTF(0, (stderr, "Unlocking IMutex 0x%p...\n", (im))); \
00446       mt_unlock(&((im)->lock)); \
00447     } \
00448   } while(0)
00449 
00450 extern int th_running;
00451 
00452 PMOD_EXPORT extern PIKE_MUTEX_T interpreter_lock;
00453 
00454 PMOD_EXPORT extern COND_T live_threads_change;          /* Used by _disable_threads */
00455 PMOD_EXPORT extern COND_T threads_disabled_change;              /* Used by _disable_threads */
00456 
00457 #define THREAD_TABLE_SIZE 127  /* Totally arbitrary prime */
00458 
00459 extern PIKE_MUTEX_T thread_table_lock;
00460 extern struct thread_state *thread_table_chains[THREAD_TABLE_SIZE];
00461 extern int num_pike_threads;
00462 
00463 /* Note: thread_table_lock is held while the code is run. */
00464 #define FOR_EACH_THREAD(TSTATE, CODE)                                   \
00465   do {                                                                  \
00466     INT32 __tt_idx__;                                                   \
00467     mt_lock( & thread_table_lock );                                     \
00468     for(__tt_idx__=0; __tt_idx__<THREAD_TABLE_SIZE; __tt_idx__++)       \
00469       for(TSTATE=thread_table_chains[__tt_idx__];                       \
00470           TSTATE;                                                       \
00471           TSTATE=TSTATE->hashlink) {                                    \
00472         CODE;                                                           \
00473       }                                                                 \
00474     mt_unlock( & thread_table_lock );                                   \
00475   } while (0)
00476 
00477 #if !defined(HAVE_GETHRTIME) && \
00478     !(defined(HAVE_MACH_TASK_INFO_H) && defined(TASK_THREAD_TIMES_INFO)) && \
00479     defined(HAVE_CLOCK) && \
00480     !defined(HAVE_NO_YIELD)
00481 #ifdef HAVE_TIME_H
00482 #include <time.h>
00483 #endif
00484 PMOD_EXPORT extern clock_t thread_start_clock;
00485 #define USE_CLOCK_FOR_SLICES
00486 #define DO_IF_USE_CLOCK_FOR_SLICES(X) X
00487 #else
00488 #define DO_IF_USE_CLOCK_FOR_SLICES(X)
00489 #endif
00490 
00491 /* Define to get a debug-trace of some of the threads operations. */
00492 /* #define VERBOSE_THREADS_DEBUG        0 */ /* Some debug */
00493 /* #define VERBOSE_THREADS_DEBUG        1 */ /* Lots of debug */
00494 
00495 #ifndef VERBOSE_THREADS_DEBUG
00496 #define THREADS_FPRINTF(L,X)
00497 #else
00498 #include <errno.h>
00499 #define THREADS_FPRINTF(L,X)    do { \
00500     if ((VERBOSE_THREADS_DEBUG + 0) >= (L)) {                           \
00501       /* E.g. THREADS_DISALLOW is used in numerous places where the */  \
00502       /* value in errno must not be clobbered. */                       \
00503       int saved_errno__ = errno;                                        \
00504       fprintf X;                                                        \
00505       errno = saved_errno__;                                            \
00506     }                                                                   \
00507   } while(0)
00508 #endif /* VERBOSE_THREADS_DEBUG */
00509 
00510 #if defined(PIKE_DEBUG) && !defined(__NT__)
00511 
00512 /* This is a debug wrapper to enable checks that the interpreter lock
00513  * is hold by the current thread. */
00514 
00515 extern THREAD_T debug_locking_thread;
00516 #define SET_LOCKING_THREAD (debug_locking_thread = th_self(), 0)
00517 
00518 #define low_mt_lock_interpreter()                                       \
00519   do {mt_lock(&interpreter_lock); SET_LOCKING_THREAD;} while (0)
00520 #define low_mt_trylock_interpreter()                                    \
00521   (mt_trylock(&interpreter_lock) || SET_LOCKING_THREAD)
00522 #define low_co_wait_interpreter(COND) \
00523   do {co_wait((COND), &interpreter_lock); SET_LOCKING_THREAD;} while (0)
00524 
00525 PMOD_EXPORT extern const char msg_ip_not_locked[];
00526 PMOD_EXPORT extern const char msg_ip_not_locked_this_thr[];
00527 
00528 #define CHECK_INTERPRETER_LOCK() do {                                   \
00529   if (th_running) {                                                     \
00530     THREAD_T self;                                                      \
00531     if (!mt_trylock(&interpreter_lock))                                 \
00532       Pike_fatal(msg_ip_not_locked);                                    \
00533     self = th_self();                                                   \
00534     if (!th_equal(debug_locking_thread, self))                          \
00535       Pike_fatal(msg_ip_not_locked_this_thr);                           \
00536   }                                                                     \
00537 } while (0)
00538 
00539 #else
00540 
00541 #define low_mt_lock_interpreter() do {mt_lock(&interpreter_lock);} while (0)
00542 #define low_mt_trylock_interpreter() (mt_trylock(&interpreter_lock))
00543 #define low_co_wait_interpreter(COND) do {co_wait((COND), &interpreter_lock);} while (0)
00544 
00545 #endif
00546 
00547 static INLINE int threads_disabled_wait(void)
00548 {
00549   do {
00550     THREADS_FPRINTF(1, (stderr, "Thread %d: Wait on threads_disabled\n",
00551                         (int) th_self()));
00552     low_co_wait_interpreter(&threads_disabled_change);
00553   } while (threads_disabled);
00554   THREADS_FPRINTF(1, (stderr, "Thread %d: Continue after threads_disabled\n",
00555                       (int) th_self()));
00556   return 0;
00557 }
00558 
00559 #define mt_lock_interpreter() do {                                      \
00560     low_mt_lock_interpreter();                                          \
00561     (threads_disabled && threads_disabled_wait());                      \
00562   } while (0)
00563 #define mt_trylock_interpreter() \
00564   (low_mt_trylock_interpreter() || (threads_disabled && threads_disabled_wait()))
00565 #define mt_unlock_interpreter() do {                                    \
00566     mt_unlock(&interpreter_lock);                                       \
00567   } while (0)
00568 #define co_wait_interpreter(COND) do {                                  \
00569     low_co_wait_interpreter(COND);                                      \
00570     if (threads_disabled) threads_disabled_wait();                      \
00571   } while (0)
00572 
00573 #ifdef INTERNAL_PROFILING
00574 PMOD_EXPORT extern unsigned long thread_yields;
00575 #define th_yield() (thread_yields++, low_th_yield())
00576 #else
00577 #define th_yield() low_th_yield()
00578 #endif
00579 
00580 #ifdef PIKE_DEBUG
00581 PMOD_EXPORT extern THREAD_T threads_disabled_thread;
00582 #endif
00583 
00584 #define INIT_THREAD_STATE(_tmp) do {                                    \
00585     struct thread_state *_th_state = (_tmp);                            \
00586     Pike_interpreter.thread_state = _th_state;                          \
00587     _th_state->state = Pike_interpreter;                                \
00588     _th_state->id = th_self();                                          \
00589     _th_state->status = THREAD_RUNNING;                                 \
00590     _th_state->swapped = 0;                                             \
00591     DO_IF_DEBUG(_th_state->debug_flags = 0;)                            \
00592     DO_IF_USE_CLOCK_FOR_SLICES (thread_start_clock = 0);                \
00593   } while (0)
00594 
00595 #define EXIT_THREAD_STATE(_tmp) do {                                    \
00596     DO_IF_DEBUG (Pike_sp = (struct svalue *) (ptrdiff_t) -1);           \
00597   } while (0)
00598 
00599 #define SWAP_OUT_THREAD(_tmp) do {                                      \
00600     struct thread_state *_th_state = (_tmp);                            \
00601     _th_state->state=Pike_interpreter;                                  \
00602     DO_IF_PROFILING({                                                   \
00603         if (!_th_state->swapped) {                                      \
00604           cpu_time_t now = get_cpu_time();                              \
00605           DO_IF_PROFILING_DEBUG({                                       \
00606               fprintf(stderr, "%p: Swap out at: %" PRINT_CPU_TIME       \
00607                       " unlocked: %" PRINT_CPU_TIME "\n",               \
00608                       _th_state, now, _th_state->state.unlocked_time);  \
00609             });                                                         \
00610           _th_state->state.unlocked_time -= now;                        \
00611         }                                                               \
00612       });                                                               \
00613     _th_state->swapped=1;                                               \
00614     DO_IF_DEBUG (                                                       \
00615       /* Yo! Yo run now, yo DIE! Hear! */                               \
00616       Pike_sp = (struct svalue *) (ptrdiff_t) -1;                       \
00617       Pike_fp = (struct pike_frame *) (ptrdiff_t) -1;                   \
00618     );                                                                  \
00619     /* Do this one always to catch nested THREADS_ALLOW(), etc. */      \
00620     Pike_interpreter.thread_state =                                     \
00621       (struct thread_state *) (ptrdiff_t) -1;                           \
00622   } while(0)
00623 
00624 PMOD_EXPORT extern const char msg_thr_swapped_over[];
00625 
00626 #define SWAP_IN_THREAD(_tmp) do {                                       \
00627     struct thread_state *_th_state = (_tmp);                            \
00628     DO_IF_DEBUG (                                                       \
00629       if (Pike_sp != (struct svalue *) (ptrdiff_t) -1)                  \
00630         Pike_fatal (msg_thr_swapped_over,                               \
00631                     (unsigned int) _th_state->id,                       \
00632                     Pike_interpreter.thread_state ?                     \
00633                     (unsigned int) Pike_interpreter.thread_state->id : 0); \
00634     );                                                                  \
00635     DO_IF_PROFILING({                                                   \
00636         if (_th_state->swapped) {                                       \
00637           cpu_time_t now = get_cpu_time();                              \
00638           DO_IF_DEBUG({                                                 \
00639               DO_IF_PROFILING_DEBUG({                                   \
00640                   fprintf(stderr, "%p: Swap in at: %" PRINT_CPU_TIME    \
00641                           " unlocked: %" PRINT_CPU_TIME "\n",           \
00642                           _th_state, now, _th_state->state.unlocked_time); \
00643                 });                                                     \
00644               if (now < -Pike_interpreter.unlocked_time) {              \
00645                 Pike_fatal("Time at swap in is before time at swap out."\
00646                            " %" PRINT_CPU_TIME " < %" PRINT_CPU_TIME    \
00647                            "\n", now, -Pike_interpreter.unlocked_time); \
00648               }                                                         \
00649             });                                                         \
00650           _th_state->state.unlocked_time += now;                        \
00651         }                                                               \
00652       });                                                               \
00653     _th_state->swapped=0;                                               \
00654     Pike_interpreter=_th_state->state;                                  \
00655     DO_IF_USE_CLOCK_FOR_SLICES (thread_start_clock = 0);                \
00656   } while(0)
00657 
00658 #define SWAP_OUT_CURRENT_THREAD() \
00659   do {\
00660      struct thread_state *_tmp = Pike_interpreter.thread_state; \
00661      SWAP_OUT_THREAD(_tmp); \
00662      THREADS_FPRINTF(1, (stderr, "SWAP_OUT_CURRENT_THREAD() %s:%d t:%08x\n", \
00663                          __FILE__, __LINE__, (unsigned int)_tmp->id))
00664 
00665 extern void debug_list_all_threads(void);
00666 extern void dumpmem(const char *desc, void *x, int size);
00667 
00668 PMOD_EXPORT extern const char msg_saved_thread_id[];
00669 PMOD_EXPORT extern const char msg_swap_in_cur_thr_failed[];
00670 
00671 #define SWAP_IN_CURRENT_THREAD()                                              \
00672    THREADS_FPRINTF(1, (stderr, "SWAP_IN_CURRENT_THREAD() %s:%d ... t:%08x\n", \
00673                        __FILE__, __LINE__, (unsigned int)_tmp->id));          \
00674    SWAP_IN_THREAD(_tmp);                                                      \
00675    DO_IF_DEBUG(                                                               \
00676    {                                                                          \
00677      THREAD_T self=th_self();                                                 \
00678      if(MEMCMP( & _tmp->id, &self, sizeof(self)))                             \
00679      {                                                                        \
00680        dumpmem(msg_saved_thread_id,&self,sizeof(self));                       \
00681        debug_list_all_threads();                                              \
00682        Pike_fatal(msg_swap_in_cur_thr_failed);                                \
00683      }                                                                        \
00684    })                                                                         \
00685  } while(0)
00686 
00687 #if defined(PIKE_DEBUG) && ! defined(DONT_HIDE_GLOBALS)
00688 /* Note that scalar types are used in place of pointers and vice versa
00689  * below. This is intended to cause compiler warnings/errors if
00690  * there is an attempt to use the global variables in an unsafe
00691  * environment.
00692  */
00693 
00694 
00695 #ifdef __GCC__
00696 #ifdef __i386__
00697 
00698 /* This is a rather drastic measure since it
00699  * obliterates backtraces, oh well, gcc doesn't work
00700  * very well sometimes anyways... -Hubbe
00701  */
00702 #define HIDE_PC                                                         \
00703   ;void *pc_=(((unsigned char **)__builtin_frame_address(0))[1]);       \
00704   (((unsigned char **)__builtin_frame_address(0))[1])=0
00705 #define REVEAL_PC \
00706   (((unsigned char **)__builtin_frame_address(0))[1])=pc_;
00707 #endif
00708 #endif
00709 
00710 #ifndef HIDE_PC
00711 #define HIDE_PC
00712 #define REVEAL_PC
00713 #endif
00714 
00715 #define HIDE_GLOBAL_VARIABLES() do { \
00716    int Pike_interpreter =0; \
00717    int pop_n_elems = 0; \
00718    int push_sp_mark = 0, pop_sp_mark = 0, threads_disabled = 1 \
00719    HIDE_PC
00720 
00721 /* Note that the semi-colon below is needed to add an empty statement
00722  * in case there is a label before the macro.
00723  */
00724 #define REVEAL_GLOBAL_VARIABLES() ; REVEAL_PC } while(0)
00725 #else /* PIKE_DEBUG */
00726 #define HIDE_GLOBAL_VARIABLES()
00727 #define REVEAL_GLOBAL_VARIABLES()
00728 #endif /* PIKE_DEBUG */
00729 
00730 #ifdef PIKE_DEBUG
00731 
00732 PMOD_EXPORT extern const char msg_thr_not_swapped_in[];
00733 PMOD_EXPORT extern const char msg_cur_thr_not_bound[];
00734 PMOD_EXPORT extern const char msg_thr_states_mixed[];
00735 
00736 #define ASSERT_THREAD_SWAPPED_IN() do {                                 \
00737     struct thread_state *_tmp=thread_state_for_id(th_self());           \
00738     if(_tmp->swapped) Pike_fatal(msg_thr_not_swapped_in);               \
00739     if (_tmp->debug_flags & THREAD_DEBUG_LOOSE) {                       \
00740       Pike_fatal(msg_cur_thr_not_bound);                                \
00741     }                                                                   \
00742   }while(0)
00743 #define DEBUG_CHECK_THREAD() do {                                       \
00744     struct thread_state *_tmp=thread_state_for_id(th_self());           \
00745     if (_tmp->debug_flags & THREAD_DEBUG_LOOSE) {                       \
00746       Pike_fatal(msg_cur_thr_not_bound);                                \
00747     }                                                                   \
00748     if(_tmp != Pike_interpreter.thread_state) {                         \
00749       debug_list_all_threads();                                         \
00750       Pike_fatal(msg_thr_states_mixed);                                 \
00751     }                                                                   \
00752   } while (0)
00753 #else
00754 #define ASSERT_THREAD_SWAPPED_IN() do { } while (0)
00755 #define DEBUG_CHECK_THREAD() do { } while (0)
00756 #endif
00757 
00758 #define THREADSTATE2OBJ(X) ((X)->thread_obj)
00759 
00760 #ifdef PIKE_DEBUG
00761 PMOD_EXPORT extern const char msg_thr_allow_in_gc[];
00762 PMOD_EXPORT extern const char msg_thr_allow_in_disabled[];
00763 PMOD_EXPORT extern const char msg_global_dynbuf_in_use[];
00764 extern dynamic_buffer pike_global_buffer;
00765 #if defined(__ia64) && defined(__xlc__)
00766 /* Workaround for a code generation bug in xlc 5.5.0.0/ia64 . */
00767 #define DO_IF_NOT_XLC_IA64(X)
00768 #else /* !ia64 || !xlc */
00769 #define DO_IF_NOT_XLC_IA64(X)   X
00770 #endif
00771 #endif
00772 
00773 PMOD_EXPORT extern int Pike_in_gc;
00774 #define THREADS_ALLOW() do { \
00775      struct thread_state *_tmp = Pike_interpreter.thread_state; \
00776      DO_IF_PIKE_CLEANUP (                                       \
00777        /* Might get here after th_cleanup() when reporting leaks. */    \
00778        if (_tmp) {)                                             \
00779      DEBUG_CHECK_THREAD();                                      \
00780      DO_IF_DEBUG({ \
00781        if (Pike_in_gc > 50 && Pike_in_gc < 300) \
00782          Pike_fatal(msg_thr_allow_in_gc, Pike_in_gc);                   \
00783        if (pike_global_buffer.s.str)                                    \
00784          Pike_fatal(msg_global_dynbuf_in_use);                          \
00785      }) \
00786      if(num_threads > 1 && !threads_disabled) { \
00787        SWAP_OUT_THREAD(_tmp); \
00788        THREADS_FPRINTF(1, (stderr, "THREADS_ALLOW() %s:%d t:%08x(#%d)\n", \
00789                            __FILE__, __LINE__, \
00790                            (unsigned int)_tmp->id, live_threads)); \
00791        mt_unlock_interpreter(); \
00792      } else {                                                           \
00793        DO_IF_DEBUG(                                                     \
00794          THREAD_T self = th_self();                                     \
00795          if (threads_disabled &&                                        \
00796              !th_equal(threads_disabled_thread, self))                  \
00797            DO_IF_NOT_XLC_IA64(Pike_fatal(msg_thr_allow_in_disabled,     \
00798                                          self,                          \
00799                                          threads_disabled_thread));     \
00800        );                                                               \
00801      }                                                                  \
00802      DO_IF_DEBUG(_tmp->debug_flags |= THREAD_DEBUG_LOOSE;)              \
00803      DO_IF_PIKE_CLEANUP (})                                             \
00804      HIDE_GLOBAL_VARIABLES()
00805 
00806 #define THREADS_DISALLOW() \
00807      REVEAL_GLOBAL_VARIABLES(); \
00808      DO_IF_PIKE_CLEANUP (if (_tmp) {) \
00809      if(_tmp->swapped) { \
00810        low_mt_lock_interpreter(); \
00811        THREADS_FPRINTF(1, (stderr, "THREADS_DISALLOW() %s:%d t:%08x(#%d)\n", \
00812                            __FILE__, __LINE__, \
00813                            (unsigned int)_tmp->id, live_threads)); \
00814        if (threads_disabled) threads_disabled_wait(); \
00815        SWAP_IN_THREAD(_tmp);\
00816      } \
00817      DO_IF_DEBUG(_tmp->debug_flags &= ~THREAD_DEBUG_LOOSE;) \
00818      DEBUG_CHECK_THREAD(); \
00819      DO_IF_PIKE_CLEANUP (}) \
00820    } while(0)
00821 
00822 #define THREADS_ALLOW_UID() do { \
00823      struct thread_state *_tmp_uid = Pike_interpreter.thread_state; \
00824      DO_IF_PIKE_CLEANUP (                                       \
00825        /* Might get here after th_cleanup() when reporting leaks. */    \
00826        if (_tmp_uid) {)                                         \
00827      DEBUG_CHECK_THREAD();                                          \
00828      DO_IF_DEBUG({ \
00829        if ((Pike_in_gc > 50) && (Pike_in_gc < 300)) { \
00830          debug_fatal(msg_thr_allow_in_gc, Pike_in_gc); \
00831        if (pike_global_buffer.s.str)                                    \
00832          Pike_fatal(msg_global_dynbuf_in_use);                          \
00833        } \
00834      }) \
00835      if(num_threads > 1 && !threads_disabled) { \
00836        SWAP_OUT_THREAD(_tmp_uid); \
00837        while (disallow_live_threads) {                                  \
00838          THREADS_FPRINTF(1, (stderr, "THREADS_ALLOW_UID() %s:%d t:%08x(#%d) " \
00839                              "live threads disallowed\n",               \
00840                              __FILE__, __LINE__,                        \
00841                              (unsigned int)_tmp_uid->id, live_threads)); \
00842          co_wait_interpreter(&threads_disabled_change);                 \
00843        }                                                                \
00844        live_threads++; \
00845        THREADS_FPRINTF(1, (stderr, "THREADS_ALLOW_UID() %s:%d t:%08x(#%d)\n", \
00846                            __FILE__, __LINE__, \
00847                            (unsigned int)_tmp_uid->id, live_threads)); \
00848        mt_unlock_interpreter(); \
00849      } else {                                                           \
00850        DO_IF_DEBUG(                                                     \
00851          THREAD_T self = th_self();                                     \
00852          if (threads_disabled &&                                        \
00853              !th_equal(threads_disabled_thread, self))                  \
00854            DO_IF_NOT_XLC_IA64(Pike_fatal(msg_thr_allow_in_disabled,     \
00855                                          self,                          \
00856                                          threads_disabled_thread));     \
00857        );                                                               \
00858      }                                                                  \
00859      DO_IF_DEBUG(_tmp_uid->debug_flags |= THREAD_DEBUG_LOOSE;)          \
00860      DO_IF_PIKE_CLEANUP (})                                             \
00861      HIDE_GLOBAL_VARIABLES()
00862 
00863 #define THREADS_DISALLOW_UID() \
00864      REVEAL_GLOBAL_VARIABLES(); \
00865      DO_IF_PIKE_CLEANUP (if (_tmp_uid) {) \
00866      if(_tmp_uid->swapped) { \
00867        low_mt_lock_interpreter(); \
00868        live_threads--; \
00869        THREADS_FPRINTF(1, (stderr, \
00870                            "THREADS_DISALLOW_UID() %s:%d t:%08x(#%d)\n", \
00871                            __FILE__, __LINE__, \
00872                            (unsigned int)_tmp_uid->id, live_threads)); \
00873        co_broadcast(&live_threads_change); \
00874        if (threads_disabled) threads_disabled_wait(); \
00875        SWAP_IN_THREAD(_tmp_uid);\
00876      } \
00877      DO_IF_DEBUG(_tmp_uid->debug_flags &= ~THREAD_DEBUG_LOOSE;) \
00878      DEBUG_CHECK_THREAD(); \
00879      DO_IF_PIKE_CLEANUP (}) \
00880    } while(0)
00881 
00882 #define SWAP_IN_THREAD_IF_REQUIRED() do {                       \
00883   struct thread_state *_tmp=thread_state_for_id(th_self());     \
00884   HIDE_GLOBAL_VARIABLES();                                      \
00885   THREADS_DISALLOW()
00886 
00887 #endif  /* !CONFIGURE_TEST */
00888 
00889 #endif /* PIKE_THREADS */
00890 
00891 #ifndef PIKE_THREADS
00892 
00893 #define th_atfork(X,Y,Z)
00894 #define th_atfork_prepare()
00895 #define th_atfork_parent()
00896 #define th_atfork_child()
00897 
00898 #define th_setconcurrency(X)
00899 #define DEFINE_MUTEX(X)
00900 #define DEFINE_IMUTEX(X)
00901 #define init_interleave_mutex(X)
00902 #define LOCK_IMUTEX(X)
00903 #define UNLOCK_IMUTEX(X)
00904 #define mt_init(X)
00905 #define mt_lock(X)
00906 #define mt_unlock(X)
00907 #define mt_destroy(X)
00908 #define THREADS_ALLOW()
00909 #define THREADS_DISALLOW()
00910 #define THREADS_ALLOW_UID()
00911 #define THREADS_DISALLOW_UID()
00912 #define HIDE_GLOBAL_VARIABLES()
00913 #define REVEAL_GLOBAL_VARIABLES()
00914 #define ASSERT_THREAD_SWAPPED_IN()
00915 #define SWAP_IN_THREAD_IF_REQUIRED()
00916 #define th_init()
00917 #define low_th_init()
00918 #define th_cleanup()
00919 #define th_init_programs()
00920 #define th_self() NULL
00921 #define co_wait(X,Y)
00922 #define co_signal(X)
00923 #define co_broadcast(X)
00924 #define co_destroy(X)
00925 
00926 #define low_init_threads_disable()
00927 #define init_threads_disable(X)
00928 #define exit_threads_disable(X)
00929 
00930 
00931 #endif /* PIKE_THREADS */
00932 
00933 #ifndef CHECK_INTERPRETER_LOCK
00934 #define CHECK_INTERPRETER_LOCK() do {} while (0)
00935 #endif
00936 
00937 #ifdef __NT__
00938 #if !defined (PIKE_DEBUG) || defined (CONFIGURE_TEST)
00939 #define CheckValidHandle(X) (X)
00940 #else
00941 PMOD_EXPORT HANDLE CheckValidHandle(HANDLE h);
00942 #endif
00943 #endif
00944 
00945 #ifndef NO_PIKE_SHORTHAND
00946 #define MUTEX_T PIKE_MUTEX_T
00947 #endif
00948 
00949 
00950 /* Initializer macros for static mutex and condition variables */
00951 #ifdef PTHREAD_MUTEX_INITIALIZER
00952 #define STATIC_MUTEX_INIT  = PTHREAD_MUTEX_INITIALIZER
00953 #else
00954 #define STATIC_MUTEX_INIT
00955 #endif
00956 #ifdef PTHREAD_COND_INITIALIZER
00957 #define STATIC_COND_INIT   = PTHREAD_COND_INITIALIZER
00958 #else
00959 #define STATIC_COND_INIT
00960 #endif
00961 
00962 #ifndef THREAD_T_TO_PTR
00963 #ifdef PIKE_THREAD_T_IS_POINTER
00964 #define THREAD_T_TO_PTR(X)      ((void *)(X))
00965 #else /* !PIKE_THREAD_T_IS_POINTER */
00966 #define THREAD_T_TO_PTR(X)      ((void *)(ptrdiff_t)(X))
00967 #endif /* PIKE_THREAD_T_IS_POINTER */
00968 #endif /* !THREAD_T_TO_PTR */
00969 
00970 #endif /* PIKE_THREADLIB_H */

Generated on Fri Jul 22 23:44:26 2005 for Pike by  doxygen 1.3.9.1