e576bb2002-10-11Martin Nilsson /* || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information.
2d18e12008-06-28Martin Stjernholm || $Id: threads.c,v 1.257 2008/06/28 01:26:37 mast Exp $
e576bb2002-10-11Martin Nilsson */
1b10db2002-10-08Martin Nilsson 
07513e1996-10-04Fredrik Hübinette (Hubbe) #include "global.h"
a29e021996-10-15Fredrik Hübinette (Hubbe) 
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int num_threads = 1; PMOD_EXPORT int threads_disabled = 0;
a29e021996-10-15Fredrik Hübinette (Hubbe) 
2702952004-04-21Martin Stjernholm /* #define PICKY_MUTEX */
a29e021996-10-15Fredrik Hübinette (Hubbe) #ifdef _REENTRANT
83b1842003-02-08Martin Stjernholm 
c7f2712007-06-09Martin Stjernholm #include "pike_error.h"
83b1842003-02-08Martin Stjernholm #ifndef CONFIGURE_TEST
f72d412004-04-23Henrik Grubbström (Grubba) /* #define VERBOSE_THREADS_DEBUG */
07513e1996-10-04Fredrik Hübinette (Hubbe) #include "threads.h" #include "array.h"
d86cd71998-08-24Marcus Comstedt #include "mapping.h"
07513e1996-10-04Fredrik Hübinette (Hubbe) #include "object.h"
bb55f81997-03-16Fredrik Hübinette (Hubbe) #include "pike_macros.h"
a29e021996-10-15Fredrik Hübinette (Hubbe) #include "callback.h"
9c6f7d1997-04-15Fredrik Hübinette (Hubbe) #include "builtin_functions.h" #include "constants.h"
be478c1997-08-30Henrik Grubbström (Grubba) #include "program.h"
3f87be1999-12-14Martin Stjernholm #include "program_id.h"
c5b96b1997-11-11Henrik Grubbström (Grubba) #include "gc.h"
3c0c281998-01-26Fredrik Hübinette (Hubbe) #include "main.h"
a49ee61999-04-02Fredrik Hübinette (Hubbe) #include "module_support.h"
52e4c61999-12-13Martin Stjernholm #include "pike_types.h"
9a0d422000-02-06Martin Stjernholm #include "operators.h"
7e8ea32000-08-13Henrik Grubbström (Grubba) #include "bignum.h"
700dac2002-02-05Martin Stjernholm #include "signal_handler.h"
d5c61f2002-12-07Henrik Grubbström (Grubba) #include "pike_rusage.h"
07513e1996-10-04Fredrik Hübinette (Hubbe) 
cd11fa1999-05-13Henrik Grubbström (Grubba) #include <errno.h>
f663a02003-03-05Martin Stjernholm #ifdef HAVE_SYS_PRCTL_H #include <sys/prctl.h> #endif /* HAVE_SYS_PRCTL_H */
08c53c2003-11-25Jonas Wallden #ifdef HAVE_SYS_TIME_H #include <sys/time.h> #endif
335a552001-11-02Martin Stjernholm PMOD_EXPORT int live_threads = 0, disallow_live_threads = 0;
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT COND_T live_threads_change; PMOD_EXPORT COND_T threads_disabled_change;
ef1e931998-03-26Henrik Grubbström (Grubba) 
7d7b022003-04-02Martin Stjernholm #else #include "pike_threadlib.h" #endif /* !CONFIGURE_TEST */
e3ee062005-03-31Martin Nilsson #ifndef PIKE_THREAD_C_STACK_SIZE #define PIKE_THREAD_C_STACK_SIZE (256 * 1024) #endif PMOD_EXPORT size_t thread_stack_size=PIKE_THREAD_C_STACK_SIZE;
c432f72003-05-02Henrik Grubbström (Grubba) PMOD_EXPORT void thread_low_error (int errcode, const char *cmd, const char *fname, int lineno)
01185d2003-04-01Martin Stjernholm {
c7f2712007-06-09Martin Stjernholm #ifdef CONFIGURE_TEST fprintf (stderr, "%s:%d: %s\n" "Unexpected error from thread function: %d\n", fname, lineno, cmd, errcode); abort(); #else
c432f72003-05-02Henrik Grubbström (Grubba)  Pike_fatal ("%s:%d: %s\n" "Unexpected error from thread function: %d\n", fname, lineno, cmd, errcode);
c7f2712007-06-09Martin Stjernholm #endif
01185d2003-04-01Martin Stjernholm }
1f88bf2001-09-24Henrik Grubbström (Grubba) /* SCO magic... */ int __thread_sys_behavior = 1;
83b1842003-02-08Martin Stjernholm #ifndef CONFIGURE_TEST
3c55762001-09-20Fredrik Hübinette (Hubbe) #if !defined(HAVE_PTHREAD_ATFORK) && !defined(th_atfork)
71ac9e1999-08-29Fredrik Hübinette (Hubbe) #include "callback.h"
58580c2001-11-12Martin Stjernholm #define PIKE_USE_OWN_ATFORK
71ac9e1999-08-29Fredrik Hübinette (Hubbe) 
3c55762001-09-20Fredrik Hübinette (Hubbe) 
71ac9e1999-08-29Fredrik Hübinette (Hubbe) static struct callback_list atfork_prepare_callback; static struct callback_list atfork_parent_callback; static struct callback_list atfork_child_callback; int th_atfork(void (*prepare)(void),void (*parent)(void),void (*child)(void)) { if(prepare) add_to_callback(&atfork_prepare_callback, (callback_func) prepare, 0, 0); if(parent) add_to_callback(&atfork_parent_callback, (callback_func) parent, 0, 0); if(child) add_to_callback(&atfork_child_callback, (callback_func) child, 0, 0); return 0; } void th_atfork_prepare(void) { call_callback(& atfork_prepare_callback, 0); } void th_atfork_parent(void) { call_callback(& atfork_parent_callback, 0); } void th_atfork_child(void) { call_callback(& atfork_child_callback, 0); } #endif
83b1842003-02-08Martin Stjernholm #endif /* !CONFIGURE_TEST */
dc7cc91998-01-14Fredrik Hübinette (Hubbe) #ifdef __NT__
7965d72001-01-24Fredrik Hübinette (Hubbe) int low_nt_create_thread(unsigned Pike_stack_size,
cd67ac1999-05-11Fredrik Hübinette (Hubbe)  unsigned (TH_STDCALL *fun)(void *), void *arg, unsigned *id) {
7965d72001-01-24Fredrik Hübinette (Hubbe)  HANDLE h = (HANDLE)_beginthreadex(NULL, Pike_stack_size, fun, arg, 0, id);
cd67ac1999-05-11Fredrik Hübinette (Hubbe)  if(h) { CloseHandle(h); return 0; } else { return 1; } }
dc7cc91998-01-14Fredrik Hübinette (Hubbe) #endif
e42eaf1998-01-02Fredrik Hübinette (Hubbe) #ifdef SIMULATE_COND_WITH_EVENT
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int co_wait(COND_T *c, MUTEX_T *m)
e42eaf1998-01-02Fredrik Hübinette (Hubbe) { struct cond_t_queue me; event_init(&me.event);
dc7cc91998-01-14Fredrik Hübinette (Hubbe)  me.next=0;
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  mt_lock(& c->lock);
dc7cc91998-01-14Fredrik Hübinette (Hubbe)  if(c->tail) { c->tail->next=&me; c->tail=&me; }else{ c->head=c->tail=&me; }
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  mt_unlock(& c->lock); mt_unlock(m); event_wait(&me.event); mt_lock(m); event_destroy(& me.event); /* Cancellation point?? */
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
dc7cc91998-01-14Fredrik Hübinette (Hubbe)  if(me.next)
5aad932002-08-15Marcus Comstedt  Pike_fatal("Wait on event return prematurely!!\n");
dc7cc91998-01-14Fredrik Hübinette (Hubbe) #endif
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  return 0; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int co_signal(COND_T *c)
e42eaf1998-01-02Fredrik Hübinette (Hubbe) { struct cond_t_queue *t; mt_lock(& c->lock);
dc7cc91998-01-14Fredrik Hübinette (Hubbe)  if((t=c->head))
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  { c->head=t->next; t->next=0; if(!c->head) c->tail=0; } mt_unlock(& c->lock); if(t) event_signal(& t->event); return 0; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int co_broadcast(COND_T *c)
e42eaf1998-01-02Fredrik Hübinette (Hubbe) { struct cond_t_queue *t,*n; mt_lock(& c->lock); n=c->head; c->head=c->tail=0; mt_unlock(& c->lock); while((t=n)) { n=t->next;
dc7cc91998-01-14Fredrik Hübinette (Hubbe)  t->next=0;
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  event_signal(& t->event); } return 0; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int co_destroy(COND_T *c)
e42eaf1998-01-02Fredrik Hübinette (Hubbe) { struct cond_t_queue *t; mt_lock(& c->lock);
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  t=c->head; mt_unlock(& c->lock); if(t) return -1; mt_destroy(& c->lock);
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  return 0; } #endif
83b1842003-02-08Martin Stjernholm #ifdef POSIX_THREADS pthread_attr_t pattr; pthread_attr_t small_pattr; #endif static void really_low_th_init(void) { #ifdef SGI_SPROC_THREADS #error /* Need to specify a filename */ us_cookie = usinit(""); #endif /* SGI_SPROC_THREADS */ #ifdef POSIX_THREADS #ifdef HAVE_PTHREAD_INIT pthread_init(); #endif /* HAVE_PTHREAD_INIT */ #endif /* POSIX_THREADS */ #ifdef POSIX_THREADS pthread_attr_init(&pattr); #ifndef CONFIGURE_TEST #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE pthread_attr_setstacksize(&pattr, thread_stack_size); #endif #endif pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED); pthread_attr_init(&small_pattr); #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE pthread_attr_setstacksize(&small_pattr, 4096*sizeof(char *)); #endif pthread_attr_setdetachstate(&small_pattr, PTHREAD_CREATE_DETACHED); #endif } #ifndef CONFIGURE_TEST
e42eaf1998-01-02Fredrik Hübinette (Hubbe) 
17f08c2000-07-06Fredrik Hübinette (Hubbe) #define THIS_THREAD ((struct thread_state *)CURRENT_STORAGE)
5740881998-01-01Fredrik Hübinette (Hubbe) 
a29e021996-10-15Fredrik Hübinette (Hubbe) static struct callback *threads_evaluator_callback=0;
07513e1996-10-04Fredrik Hübinette (Hubbe) 
b32ef12000-04-19Martin Stjernholm int th_running = 0;
c91f892000-04-19Martin Stjernholm #ifdef PIKE_DEBUG int debug_interpreter_is_locked = 0; THREAD_T debug_locking_thread;
95c8152001-11-01Martin Stjernholm THREAD_T threads_disabled_thread = 0;
c91f892000-04-19Martin Stjernholm #endif
c5f4e22002-09-14Martin Stjernholm #ifdef INTERNAL_PROFILING PMOD_EXPORT unsigned long thread_yields = 0; #endif
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT MUTEX_T interpreter_lock; MUTEX_T thread_table_lock, interleave_lock;
07513e1996-10-04Fredrik Hübinette (Hubbe) struct program *mutex_key = 0;
fa8c692000-11-30Fredrik Hübinette (Hubbe) PMOD_EXPORT struct program *thread_id_prog = 0;
d86cd71998-08-24Marcus Comstedt struct program *thread_local_prog = 0;
89fc4c2000-08-10Henrik Grubbström (Grubba) PMOD_EXPORT ptrdiff_t thread_storage_offset;
7ee4aa2002-09-14Martin Stjernholm #ifdef USE_CLOCK_FOR_SLICES PMOD_EXPORT clock_t thread_start_clock = 0; #endif
07513e1996-10-04Fredrik Hübinette (Hubbe) 
c237242003-10-19Martin Stjernholm #ifdef PIKE_DEBUG PMOD_EXPORT const char msg_ip_not_locked[] = "Interpreter not locked.\n"; PMOD_EXPORT const char msg_ip_not_locked_this_thr[] = "Interpreter not locked by this thread.\n"; PMOD_EXPORT const char msg_thr_swapped_over[] = "Thread %08x swapped in over existing thread %08x.\n"; PMOD_EXPORT const char msg_saved_thread_id[] = "Saved thread id: "; PMOD_EXPORT const char msg_swap_in_cur_thr_failed[] = "SWAP_IN_CURRENT_THREAD failed.\n"; PMOD_EXPORT const char msg_thr_not_swapped_in[] = "Thread is not swapped in.\n"; PMOD_EXPORT const char msg_cur_thr_not_bound[] = "Current thread is not bound to the interpreter. " "Nested use of ALLOW_THREADS()?\n"; PMOD_EXPORT const char msg_thr_states_mixed[] = "Thread states mixed up between threads.\n"; PMOD_EXPORT const char msg_thr_allow_in_gc[] = "Threads allowed during garbage collection (pass %d).\n"; PMOD_EXPORT const char msg_thr_allow_in_disabled[] = "Threads allowed from a different thread "
a19c062004-07-16Henrik Grubbström (Grubba)  "while threads are disabled. (self: %08x, disabler: %08x)\n";
7f851f2003-11-09Martin Stjernholm PMOD_EXPORT const char msg_global_dynbuf_in_use[] = "Threads allowed while the global dynamic buffer is in use.\n";
c237242003-10-19Martin Stjernholm #endif
d86cd71998-08-24Marcus Comstedt struct thread_local { INT32 id; };
a91ca01998-07-10Henrik Grubbström (Grubba) static volatile IMUTEX_T *interleave_list = NULL;
335a552001-11-02Martin Stjernholm /* This is a variant of init_threads_disable that blocks all other * threads that might run pike code, but still doesn't block the * THREADS_ALLOW_UID threads. */
f328f11998-07-17Henrik Grubbström (Grubba) void low_init_threads_disable(void)
a91ca01998-07-10Henrik Grubbström (Grubba) { /* Serious black magic to avoid dead-locks */ if (!threads_disabled) {
f328f11998-07-17Henrik Grubbström (Grubba)  THREADS_FPRINTF(0, (stderr, "low_init_threads_disable(): Locking IM's...\n"));
a91ca01998-07-10Henrik Grubbström (Grubba) 
b867f92003-02-16Martin Stjernholm  if (Pike_interpreter.thread_state) {
2f748a1999-02-20Henrik Grubbström (Grubba)  /* Threads have been enabled. */
a91ca01998-07-10Henrik Grubbström (Grubba)  IMUTEX_T *im; THREADS_ALLOW(); /* Keep this the entire session. */ mt_lock(&interleave_lock); im = (IMUTEX_T *)interleave_list; while(im) { mt_lock(&(im->lock)); im = im->next; } THREADS_DISALLOW(); } else {
2f748a1999-02-20Henrik Grubbström (Grubba)  /* Threads haven't been enabled yet. */
a91ca01998-07-10Henrik Grubbström (Grubba)  IMUTEX_T *im; /* Keep this the entire session. */ mt_lock(&interleave_lock); im = (IMUTEX_T *)interleave_list; while(im) { mt_lock(&(im->lock)); im = im->next; } }
f328f11998-07-17Henrik Grubbström (Grubba)  THREADS_FPRINTF(0, (stderr, "low_init_threads_disable(): Disabling threads.\n"));
a91ca01998-07-10Henrik Grubbström (Grubba)  threads_disabled = 1;
95c8152001-11-01Martin Stjernholm #ifdef PIKE_DEBUG threads_disabled_thread = th_self(); #endif
a91ca01998-07-10Henrik Grubbström (Grubba)  } else { threads_disabled++; }
f328f11998-07-17Henrik Grubbström (Grubba)  THREADS_FPRINTF(0, (stderr, "low_init_threads_disable(): threads_disabled:%d\n", threads_disabled)); }
16df701998-07-16Fredrik Hübinette (Hubbe) 
e413da2001-02-01Henrik Grubbström (Grubba) /*! @decl object(_disable_threads) _disable_threads() *!
335a552001-11-02Martin Stjernholm  *! This function first posts a notice to all threads that it is time *! to stop. It then waits until all threads actually *have* stopped, *! and then then returns a lock object. All other threads will be *! blocked from running until that object has been freed/destroyed. *! *! It's mainly useful to do things that require a temporary uid/gid *! change, since on many OS the effective user and group applies to *! all threads.
e413da2001-02-01Henrik Grubbström (Grubba)  *! *! @note
335a552001-11-02Martin Stjernholm  *! You should make sure that the returned object is freed even if *! some kind of error is thrown. That means in practice that it *! should only have references (direct or indirect) from function *! local variables. Also, it shouldn't be referenced from cyclic *! memory structures, since those are only destructed by the periodic *! gc. (This advice applies to mutex locks in general, for that *! matter.)
e413da2001-02-01Henrik Grubbström (Grubba)  */
f328f11998-07-17Henrik Grubbström (Grubba) void init_threads_disable(struct object *o) {
335a552001-11-02Martin Stjernholm  disallow_live_threads = 1;
f328f11998-07-17Henrik Grubbström (Grubba)  if(live_threads) { SWAP_OUT_CURRENT_THREAD(); while (live_threads) { THREADS_FPRINTF(0, (stderr, "_disable_threads(): Waiting for %d threads to finish\n", live_threads));
bc21dc2001-11-01Martin Stjernholm  low_co_wait_interpreter(&live_threads_change);
16df701998-07-16Fredrik Hübinette (Hubbe)  }
f328f11998-07-17Henrik Grubbström (Grubba)  SWAP_IN_CURRENT_THREAD();
a91ca01998-07-10Henrik Grubbström (Grubba)  }
335a552001-11-02Martin Stjernholm  low_init_threads_disable();
a91ca01998-07-10Henrik Grubbström (Grubba) }
de413f1998-03-26Per Hedbor void exit_threads_disable(struct object *o) {
a91ca01998-07-10Henrik Grubbström (Grubba)  THREADS_FPRINTF(0, (stderr, "exit_threads_disable(): threads_disabled:%d\n", threads_disabled));
40e9491998-07-05Henrik Grubbström (Grubba)  if(threads_disabled) { if(!--threads_disabled) {
a91ca01998-07-10Henrik Grubbström (Grubba)  IMUTEX_T *im = (IMUTEX_T *)interleave_list; /* Order shouldn't matter for unlock, so no need to do it backwards. */ while(im) { THREADS_FPRINTF(0, (stderr,
95c8152001-11-01Martin Stjernholm  "exit_threads_disable(): Unlocking IM 0x%p\n", im));
a91ca01998-07-10Henrik Grubbström (Grubba)  mt_unlock(&(im->lock)); im = im->next; } mt_unlock(&interleave_lock); THREADS_FPRINTF(0, (stderr, "_exit_threads_disable(): Wake up!\n"));
335a552001-11-02Martin Stjernholm  disallow_live_threads = 0;
2202fe1998-04-23Fredrik Hübinette (Hubbe)  co_broadcast(&threads_disabled_change);
95c8152001-11-01Martin Stjernholm #ifdef PIKE_DEBUG threads_disabled_thread = 0; #endif
40e9491998-07-05Henrik Grubbström (Grubba)  }
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
40e9491998-07-05Henrik Grubbström (Grubba)  } else {
5aad932002-08-15Marcus Comstedt  Pike_fatal("exit_threads_disable() called too many times!\n");
71f3a21998-11-22Fredrik Hübinette (Hubbe) #endif /* PIKE_DEBUG */
40e9491998-07-05Henrik Grubbström (Grubba)  }
de413f1998-03-26Per Hedbor }
063fe31998-03-10Per Hedbor 
a91ca01998-07-10Henrik Grubbström (Grubba) void init_interleave_mutex(IMUTEX_T *im)
063fe31998-03-10Per Hedbor {
a91ca01998-07-10Henrik Grubbström (Grubba)  mt_init(&(im->lock));
6e1db51998-07-09Henrik Grubbström (Grubba) 
a91ca01998-07-10Henrik Grubbström (Grubba)  THREADS_FPRINTF(0, (stderr, "init_interleave_mutex(): init_threads_disable()\n"));
6e1db51998-07-09Henrik Grubbström (Grubba) 
a91ca01998-07-10Henrik Grubbström (Grubba)  init_threads_disable(NULL);
6e1db51998-07-09Henrik Grubbström (Grubba) 
a91ca01998-07-10Henrik Grubbström (Grubba)  THREADS_FPRINTF(0, (stderr,
95c8152001-11-01Martin Stjernholm  "init_interleave_mutex(): Locking IM 0x%p\n", im));
6e1db51998-07-09Henrik Grubbström (Grubba) 
a91ca01998-07-10Henrik Grubbström (Grubba)  /* Lock it so that it can be unlocked by exit_threads_disable() */ mt_lock(&(im->lock)); im->next = (IMUTEX_T *)interleave_list; if (interleave_list) { interleave_list->prev = im;
6e1db51998-07-09Henrik Grubbström (Grubba)  }
a91ca01998-07-10Henrik Grubbström (Grubba)  interleave_list = im; im->prev = NULL;
6e1db51998-07-09Henrik Grubbström (Grubba) 
a91ca01998-07-10Henrik Grubbström (Grubba)  THREADS_FPRINTF(0, (stderr, "init_interleave_mutex(): exit_threads_disable()\n")); exit_threads_disable(NULL); } void exit_interleave_mutex(IMUTEX_T *im) { init_threads_disable(NULL); if (im->prev) { im->prev->next = im->next; } else { interleave_list = im->next; } if (im->next) { im->next->prev = im->prev;
ef1e931998-03-26Henrik Grubbström (Grubba)  }
a91ca01998-07-10Henrik Grubbström (Grubba)  /* Just to be nice... */ mt_unlock(&(im->lock)); exit_threads_disable(NULL);
063fe31998-03-10Per Hedbor }
eac2091998-02-27Marcus Comstedt  /* Thread hashtable */
f2c01e2003-01-08Martin Stjernholm struct thread_state *thread_table_chains[THREAD_TABLE_SIZE]; int num_pike_threads=0;
eac2091998-02-27Marcus Comstedt 
22ca071998-04-08Fredrik Hübinette (Hubbe) void thread_table_init(void)
eac2091998-02-27Marcus Comstedt { INT32 x; for(x=0; x<THREAD_TABLE_SIZE; x++) thread_table_chains[x] = NULL; } unsigned INT32 thread_table_hash(THREAD_T *tid) {
d213271998-02-28Fredrik Hübinette (Hubbe)  return th_hash(*tid) % THREAD_TABLE_SIZE;
eac2091998-02-27Marcus Comstedt }
26cd941999-05-07Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
c237242003-10-19Martin Stjernholm void dumpmem(const char *desc, void *x, int size)
26cd941999-05-07Fredrik Hübinette (Hubbe) { int e; unsigned char *tmp=(unsigned char *)x;
ad183c2003-10-19Martin Stjernholm  fprintf(stderr, "%s0x", desc);
26cd941999-05-07Fredrik Hübinette (Hubbe)  for(e=0;e<size;e++) fprintf(stderr,"%02x",tmp[e]); fprintf(stderr,"\n"); } #endif
0431312003-02-15Henrik Grubbström (Grubba) PMOD_EXPORT void thread_table_insert(struct thread_state *s)
eac2091998-02-27Marcus Comstedt { unsigned INT32 h = thread_table_hash(&s->id);
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
939b181998-07-17Fredrik Hübinette (Hubbe)  if(h>=THREAD_TABLE_SIZE)
5aad932002-08-15Marcus Comstedt  Pike_fatal("thread_table_hash failed miserably!\n");
26cd941999-05-07Fredrik Hübinette (Hubbe)  if(thread_state_for_id(s->id))
3be5501999-06-08Fredrik Hübinette (Hubbe)  { if(thread_state_for_id(s->id) == s)
5aad932002-08-15Marcus Comstedt  Pike_fatal("Registring thread twice!\n");
3be5501999-06-08Fredrik Hübinette (Hubbe)  else
5aad932002-08-15Marcus Comstedt  Pike_fatal("Forgot to unregister thread!\n");
3be5501999-06-08Fredrik Hübinette (Hubbe)  }
ad183c2003-10-19Martin Stjernholm /* dumpmem("thread_table_insert: ",&s->id, sizeof(THREAD_T)); */
939b181998-07-17Fredrik Hübinette (Hubbe) #endif
eac2091998-02-27Marcus Comstedt  mt_lock( & thread_table_lock );
56ac102000-03-29Fredrik Hübinette (Hubbe)  num_pike_threads++;
eac2091998-02-27Marcus Comstedt  if((s->hashlink = thread_table_chains[h]) != NULL) s->hashlink->backlink = &s->hashlink; thread_table_chains[h] = s; s->backlink = &thread_table_chains[h]; mt_unlock( & thread_table_lock ); }
0431312003-02-15Henrik Grubbström (Grubba) PMOD_EXPORT void thread_table_delete(struct thread_state *s)
eac2091998-02-27Marcus Comstedt {
ad183c2003-10-19Martin Stjernholm /* dumpmem("thread_table_delete: ",&s->id, sizeof(THREAD_T)); */
eac2091998-02-27Marcus Comstedt  mt_lock( & thread_table_lock );
56ac102000-03-29Fredrik Hübinette (Hubbe)  num_pike_threads--;
eac2091998-02-27Marcus Comstedt  if(s->hashlink != NULL) s->hashlink->backlink = s->backlink; *(s->backlink) = s->hashlink; mt_unlock( & thread_table_lock ); }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct thread_state *thread_state_for_id(THREAD_T tid)
eac2091998-02-27Marcus Comstedt { unsigned INT32 h = thread_table_hash(&tid);
17f08c2000-07-06Fredrik Hübinette (Hubbe)  struct thread_state *s = NULL;
26cd941999-05-07Fredrik Hübinette (Hubbe) #if 0 if(num_threads>1) dumpmem("thread_state_for_id: ",&tid,sizeof(tid)); #endif
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
939b181998-07-17Fredrik Hübinette (Hubbe)  if(h>=THREAD_TABLE_SIZE)
5aad932002-08-15Marcus Comstedt  Pike_fatal("thread_table_hash failed miserably!\n");
939b181998-07-17Fredrik Hübinette (Hubbe) #endif
eac2091998-02-27Marcus Comstedt  mt_lock( & thread_table_lock );
d213271998-02-28Fredrik Hübinette (Hubbe)  if(thread_table_chains[h] == NULL) {
eac2091998-02-27Marcus Comstedt  /* NULL result */
d213271998-02-28Fredrik Hübinette (Hubbe)  } else if(th_equal((s=thread_table_chains[h])->id, tid)) {
eac2091998-02-27Marcus Comstedt  /* Quick return */
d213271998-02-28Fredrik Hübinette (Hubbe)  } else {
eac2091998-02-27Marcus Comstedt  while((s = s->hashlink) != NULL)
d213271998-02-28Fredrik Hübinette (Hubbe)  if(th_equal(s->id, tid))
eac2091998-02-27Marcus Comstedt  break; if(s != NULL) {
ec2bab2000-06-24Fredrik Hübinette (Hubbe)  /* Move the Pike_interpreter to the head of the chain, in case
eac2091998-02-27Marcus Comstedt  we want to search for it again */ /* Unlink */ if(s->hashlink != NULL) s->hashlink->backlink = s->backlink; *(s->backlink) = s->hashlink; /* And relink at the head of the chain */ if((s->hashlink = thread_table_chains[h]) != NULL) s->hashlink->backlink = &s->hashlink; thread_table_chains[h] = s; s->backlink = &thread_table_chains[h]; } } mt_unlock( & thread_table_lock );
26cd941999-05-07Fredrik Hübinette (Hubbe) #if 0 if(num_threads>1 && s) dumpmem("thread_state_for_id return value: ",&s->id,sizeof(tid)); #endif
eac2091998-02-27Marcus Comstedt  return s; /* NOTEZ BIEN: Return value only guaranteed to remain valid as long as you have the interpreter lock, unless tid == th_self() */ }
048d232001-02-27Martin Stjernholm struct thread_state *gdb_thread_state_for_id(THREAD_T tid) /* Should only be used from a debugger session. */ { unsigned INT32 h = thread_table_hash(&tid); struct thread_state *s; for (s = thread_table_chains[h]; s != NULL; s = s->hashlink) if(th_equal(s->id, tid)) break; return s; } INT32 gdb_next_thread_state(INT32 prev, struct thread_state **ts) /* Used by gdb_backtraces. */ { if (!*ts || !(*ts)->hashlink) { if (!*ts) prev = -1; while (++prev < THREAD_TABLE_SIZE) if ((*ts = thread_table_chains[prev])) return prev; *ts = NULL; return 0; } *ts = (*ts)->hashlink; return prev; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct object *thread_for_id(THREAD_T tid)
eac2091998-02-27Marcus Comstedt {
17f08c2000-07-06Fredrik Hübinette (Hubbe)  struct thread_state *s = thread_state_for_id(tid);
26cd941999-05-07Fredrik Hübinette (Hubbe)  return (s == NULL? NULL : THREADSTATE2OBJ(s));
eac2091998-02-27Marcus Comstedt  /* See NB in thread_state_for_id. Lifespan of result can be prolonged by incrementing refcount though. */ }
2b42cc2007-10-06Marcus Comstedt PMOD_EXPORT void call_with_interpreter(void (*func)(void *ctx), void *ctx) { struct thread_state *state; if((state = thread_state_for_id(th_self()))!=NULL) { /* This is a pike thread. Do we have the interpreter lock? */ if(!state->swapped) { /* Yes. Go for it... */ func(ctx); } else { /* Nope, let's get it... */ mt_lock_interpreter(); SWAP_IN_THREAD(state); func(ctx); /* Restore */ SWAP_OUT_THREAD(state); mt_unlock_interpreter(); } } else { /* Not a pike thread. Create a temporary thread_id... */ struct object *thread_obj; mt_lock_interpreter(); init_interpreter(); Pike_interpreter.stack_top=((char *)&state)+ (thread_stack_size-16384) * STACK_DIRECTION; Pike_interpreter.recoveries = NULL; thread_obj = fast_clone_object(thread_id_prog); INIT_THREAD_STATE((struct thread_state *)(thread_obj->storage + thread_storage_offset)); num_threads++; thread_table_insert(Pike_interpreter.thread_state); func(ctx); cleanup_interpret(); /* Must be done before EXIT_THREAD_STATE */ Pike_interpreter.thread_state->status=THREAD_EXITED; co_signal(&Pike_interpreter.thread_state->status_change); thread_table_delete(Pike_interpreter.thread_state); EXIT_THREAD_STATE(Pike_interpreter.thread_state); Pike_interpreter.thread_state=NULL; free_object(thread_obj); thread_obj = NULL; num_threads--; mt_unlock_interpreter(); } } PMOD_EXPORT void enable_external_threads(void) { num_threads++; } PMOD_EXPORT void disable_external_threads(void) { num_threads--; }
e413da2001-02-01Henrik Grubbström (Grubba) /*! @module Thread */
95363a2000-04-11Fredrik Hübinette (Hubbe) 
e413da2001-02-01Henrik Grubbström (Grubba) /*! @decl array(Thread.Thread) all_threads() *! *! This function returns an array with the thread ids of all threads. *! *! @seealso
c7b7dd2001-10-28Martin Nilsson  *! @[Thread()]
e413da2001-02-01Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_all_threads(INT32 args)
eac2091998-02-27Marcus Comstedt { /* Return an unordered array containing all threads that was running at the time this function was invoked */ struct svalue *oldsp;
17f08c2000-07-06Fredrik Hübinette (Hubbe)  struct thread_state *s;
eac2091998-02-27Marcus Comstedt  pop_n_elems(args);
17f08c2000-07-06Fredrik Hübinette (Hubbe)  oldsp = Pike_sp;
f2c01e2003-01-08Martin Stjernholm  FOR_EACH_THREAD (s, {
26cd941999-05-07Fredrik Hübinette (Hubbe)  struct object *o = THREADSTATE2OBJ(s);
88f3202002-06-17Henrik Grubbström (Grubba)  if (o) { ref_push_object(o); }
f2c01e2003-01-08Martin Stjernholm  });
89fc4c2000-08-10Henrik Grubbström (Grubba)  f_aggregate(DO_NOT_WARN(Pike_sp - oldsp));
eac2091998-02-27Marcus Comstedt }
38e1e82001-11-08Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
00e6682006-07-05Martin Stjernholm PMOD_EXPORT void debug_list_all_threads(void)
38e1e82001-11-08Fredrik Hübinette (Hubbe) { INT32 x; struct thread_state *s; THREAD_T self = th_self(); fprintf(stderr,"--Listing all threads--\n"); dumpmem("Current thread: ",&self, sizeof(self));
ad183c2003-10-19Martin Stjernholm  fprintf(stderr,"Current interpreter thread state: %p%s\n", Pike_interpreter.thread_state, Pike_interpreter.thread_state == (struct thread_state *) (ptrdiff_t) -1 ? " (swapped)" : "");
c237242003-10-19Martin Stjernholm  fprintf(stderr,"Current thread state according to thread_state_for_id(): %p\n", thread_state_for_id (self));
1d456f2003-02-20Henrik Grubbström (Grubba)  fprintf(stderr,"Current thread obj: %p\n",
ad183c2003-10-19Martin Stjernholm  (Pike_interpreter.thread_state && Pike_interpreter.thread_state != (struct thread_state *) (ptrdiff_t) -1) ? Pike_interpreter.thread_state->thread_obj : NULL);
38e1e82001-11-08Fredrik Hübinette (Hubbe)  fprintf(stderr,"Current thread hash: %d\n",thread_table_hash(&self)); fprintf(stderr,"Current stack pointer: %p\n",&self); for(x=0; x<THREAD_TABLE_SIZE; x++) { for(s=thread_table_chains[x]; s; s=s->hashlink) { struct object *o = THREADSTATE2OBJ(s);
ad183c2003-10-19Martin Stjernholm  fprintf(stderr,"ThTab[%d]: state=%p, obj=%p, "
2d76f22005-05-20Martin Stjernholm  "swapped=%d, sp=%p (%+"PRINTPTRDIFFT"d), fp=%p, stackbase=%p",
ad183c2003-10-19Martin Stjernholm  x, s, o, s->swapped, s->state.stack_pointer, s->state.stack_pointer - s->state.evaluator_stack, s->state.frame_pointer, s->state.stack_top); dumpmem(", id=",&s->id, sizeof(s->id));
38e1e82001-11-08Fredrik Hübinette (Hubbe)  } } fprintf(stderr,"-----------------------\n"); } #endif
95363a2000-04-11Fredrik Hübinette (Hubbe) 
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int count_pike_threads(void)
56ac102000-03-29Fredrik Hübinette (Hubbe) { return num_pike_threads; }
eac2091998-02-27Marcus Comstedt 
9ef9a31996-11-16Fredrik Hübinette (Hubbe) static void check_threads(struct callback *cb, void *arg, void * arg2)
a29e021996-10-15Fredrik Hübinette (Hubbe) {
319fb12002-09-14Martin Stjernholm #ifndef HAVE_NO_YIELD /* If we have no yield we can't cut calls here since it's possible * that a thread switch will take place only occasionally in the * window below. */
0a861b1997-09-17Fredrik Hübinette (Hubbe)  static int div_;
a85ac52001-08-23Per Hedbor  if(div_++ & 255) return;
7ee4aa2002-09-14Martin Stjernholm #ifdef HAVE_GETHRTIME { static hrtime_t last_ = 0; hrtime_t now = gethrtime(); if( now-last_ < 50000000 ) /* 0.05s slice */ return; last_ = now; }
82069a2003-11-26Henrik Grubbström (Grubba) #elif defined(HAVE_MACH_TASK_INFO_H) && defined(TASK_THREAD_TIMES_INFO)
08c53c2003-11-25Jonas Wallden  { static struct timeval last_check = { 0, 0 }; task_thread_times_info_data_t info; mach_msg_type_number_t info_size = TASK_THREAD_TIMES_INFO_COUNT; /* Get user time and test if 50usec has passed since last check. */ if (task_info(mach_task_self(), TASK_THREAD_TIMES_INFO, (task_info_t) &info, &info_size) == 0) { /* Compute difference by converting kernel time_info_t to timeval. */ struct timeval now; struct timeval diff; now.tv_sec = info.user_time.seconds; now.tv_usec = info.user_time.microseconds; timersub(&now, &last_check, &diff); if (diff.tv_usec < 50000 && diff.tv_sec == 0) return; last_check = now; } }
7ee4aa2002-09-14Martin Stjernholm #elif defined (USE_CLOCK_FOR_SLICES) if (clock() - thread_start_clock < (clock_t) (CLOCKS_PER_SEC / 20)) return;
a85ac52001-08-23Per Hedbor #endif
319fb12002-09-14Martin Stjernholm #endif
0a861b1997-09-17Fredrik Hübinette (Hubbe) 
b867f92003-02-16Martin Stjernholm  DEBUG_CHECK_THREAD();
26cd941999-05-07Fredrik Hübinette (Hubbe) 
de413f1998-03-26Per Hedbor  THREADS_ALLOW(); /* Allow other threads to run */
335a552001-11-02Martin Stjernholm  th_yield();
de413f1998-03-26Per Hedbor  THREADS_DISALLOW();
26cd941999-05-07Fredrik Hübinette (Hubbe) 
7ee4aa2002-09-14Martin Stjernholm #ifdef USE_CLOCK_FOR_SLICES /* Must set the base time for the slice here since clock() returns * thread local time. */ thread_start_clock = clock(); #endif
b867f92003-02-16Martin Stjernholm  DEBUG_CHECK_THREAD();
a29e021996-10-15Fredrik Hübinette (Hubbe) }
1d456f2003-02-20Henrik Grubbström (Grubba) struct thread_starter { struct thread_state *thread_state; /* State of the thread. */ struct array *args; /* Arguments passed to the thread. */ #ifdef HAVE_BROKEN_LINUX_THREAD_EUID int euid, egid; #endif /* HAVE_BROKEN_LINUX_THREAD_EUID */ }; /* Thread func starting new Pike-level threads. */
0431312003-02-15Henrik Grubbström (Grubba) TH_RETURN_TYPE new_thread_func(void *data)
07513e1996-10-04Fredrik Hübinette (Hubbe) {
6d1a5e1996-10-07Fredrik Hübinette (Hubbe)  struct thread_starter arg = *(struct thread_starter *)data;
1d456f2003-02-20Henrik Grubbström (Grubba)  struct object *thread_obj; struct thread_state *thread_state;
07513e1996-10-04Fredrik Hübinette (Hubbe)  JMP_BUF back;
b1b51f1996-10-11Fredrik Hübinette (Hubbe) 
b867f92003-02-16Martin Stjernholm  THREADS_FPRINTF(0, (stderr,"new_thread_func(): Thread %p created...\n", arg.thread_state));
c17fed2000-05-20Henrik Grubbström (Grubba) 
222d922000-05-20Henrik Grubbström (Grubba) #ifdef HAVE_BROKEN_LINUX_THREAD_EUID
c17fed2000-05-20Henrik Grubbström (Grubba)  /* Work-around for Linux's pthreads not propagating the * effective uid & gid. */ if (!geteuid()) {
f663a02003-03-05Martin Stjernholm #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) /* The sete?id calls will clear the dumpable state that we might * have set with system.dumpable. */ int current = prctl(PR_GET_DUMPABLE);
a1ee482003-10-06Martin Stjernholm #ifdef PIKE_DEBUG if (current == -1) fprintf (stderr, "%s:%d: Unexpected error from prctl(2). errno=%d\n", __FILE__, __LINE__, errno); #endif
f663a02003-03-05Martin Stjernholm #endif
6617302000-05-22Henrik Grubbström (Grubba)  setegid(arg.egid); seteuid(arg.euid);
f663a02003-03-05Martin Stjernholm #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
a1ee482003-10-06Martin Stjernholm  if (current != -1 && prctl(PR_SET_DUMPABLE, current) == -1) { #if defined(PIKE_DEBUG) fprintf (stderr, "%s:%d: Unexpected error from prctl(2). errno=%d\n", __FILE__, __LINE__, errno); #endif }
f663a02003-03-05Martin Stjernholm #endif
c17fed2000-05-20Henrik Grubbström (Grubba)  }
222d922000-05-20Henrik Grubbström (Grubba) #endif /* HAVE_BROKEN_LINUX_THREAD_EUID */
fe76ce1997-09-08Fredrik Hübinette (Hubbe) 
01185d2003-04-01Martin Stjernholm  mt_lock_interpreter();
b867f92003-02-16Martin Stjernholm  #if defined(PIKE_DEBUG) if(d_flag) { THREAD_T self = th_self(); if( !th_equal(arg.thread_state->id, self) ) Pike_fatal("Current thread is wrong. %lx %lx\n", (long)arg.thread_state->id, (long)self); } #endif arg.thread_state->swapped = 0; Pike_interpreter = arg.thread_state->state;
0612442001-05-16Fredrik Hübinette (Hubbe) #ifdef PROFILING Pike_interpreter.stack_bottom=((char *)&data); #endif
17f08c2000-07-06Fredrik Hübinette (Hubbe)  Pike_interpreter.stack_top=((char *)&data)+ (thread_stack_size-16384) * STACK_DIRECTION; Pike_interpreter.recoveries = NULL;
0431312003-02-15Henrik Grubbström (Grubba) 
1d456f2003-02-20Henrik Grubbström (Grubba)  add_ref(thread_obj = arg.thread_state->thread_obj); INIT_THREAD_STATE(thread_state = arg.thread_state); /* Inform the spawning thread that we are now running. */ co_broadcast(&thread_state->status_change);
f0cd4c1999-03-21Henrik Grubbström (Grubba) 
b867f92003-02-16Martin Stjernholm  DEBUG_CHECK_THREAD();
26cd941999-05-07Fredrik Hübinette (Hubbe) 
97ebb32003-01-09Henrik Grubbström (Grubba)  Pike_interpreter.trace_level = default_t_flag;
07513e1996-10-04Fredrik Hübinette (Hubbe) 
b867f92003-02-16Martin Stjernholm  THREADS_FPRINTF(0, (stderr,"new_thread_func(): Thread %p inited\n", arg.thread_state));
38e1e82001-11-08Fredrik Hübinette (Hubbe) 
07513e1996-10-04Fredrik Hübinette (Hubbe)  if(SETJMP(back)) {
286b312004-12-30Henrik Grubbström (Grubba)  if(throw_severity <= THROW_ERROR)
6697042000-11-20Martin Stjernholm  call_handle_error();
07513e1996-10-04Fredrik Hübinette (Hubbe)  } else {
725ba91996-10-12Fredrik Hübinette (Hubbe)  INT32 args=arg.args->size;
61e9a01998-01-25Fredrik Hübinette (Hubbe)  back.severity=THROW_EXIT;
6d1a5e1996-10-07Fredrik Hübinette (Hubbe)  push_array_items(arg.args); arg.args=0;
97ffe41997-01-26Per Hedbor  f_call_function(args);
5740881998-01-01Fredrik Hübinette (Hubbe) 
b867f92003-02-16Martin Stjernholm  /* copy return value to the arg.thread_state here */ assign_svalue(&arg.thread_state->result, Pike_sp-1);
5740881998-01-01Fredrik Hübinette (Hubbe)  pop_stack();
97258e2008-05-23Martin Stjernholm  throw_severity = THROW_N_A;
07513e1996-10-04Fredrik Hübinette (Hubbe)  }
1d456f2003-02-20Henrik Grubbström (Grubba)  UNSETJMP(back);
b867f92003-02-16Martin Stjernholm  DEBUG_CHECK_THREAD();
38e1e82001-11-08Fredrik Hübinette (Hubbe) 
1d456f2003-02-20Henrik Grubbström (Grubba)  if(thread_state->thread_local != NULL) { free_mapping(thread_state->thread_local); thread_state->thread_local = NULL;
d86cd71998-08-24Marcus Comstedt  }
1d456f2003-02-20Henrik Grubbström (Grubba)  thread_state->status = THREAD_EXITED; co_broadcast(&thread_state->status_change);
07513e1996-10-04Fredrik Hübinette (Hubbe) 
b867f92003-02-16Martin Stjernholm  THREADS_FPRINTF(0, (stderr,"new_thread_func(): Thread %p done\n", arg.thread_state));
b1b51f1996-10-11Fredrik Hübinette (Hubbe) 
1d456f2003-02-20Henrik Grubbström (Grubba)  /* This thread is now officially dead. */
2ef3b92005-01-25Henrik Grubbström (Grubba)  while(Pike_fp) POP_PIKE_FRAME(); reset_evaluator(); low_cleanup_interpret(&thread_state->state);
1d456f2003-02-20Henrik Grubbström (Grubba)  thread_table_delete(thread_state); EXIT_THREAD_STATE(thread_state); Pike_interpreter.thread_state = thread_state = NULL; /* Free ourselves. * NB: This really ought to run in some other thread... */
f1ee642003-03-17Henrik Grubbström (Grubba)  free_object(thread_obj);
1d456f2003-02-20Henrik Grubbström (Grubba)  thread_obj = NULL;
07513e1996-10-04Fredrik Hübinette (Hubbe)  num_threads--;
fe76ce1997-09-08Fredrik Hübinette (Hubbe)  if(!num_threads && threads_evaluator_callback)
a29e021996-10-15Fredrik Hübinette (Hubbe)  { remove_callback(threads_evaluator_callback); threads_evaluator_callback=0; }
0f65e12002-09-14Martin Stjernholm  #ifdef INTERNAL_PROFILING fprintf (stderr, "Thread usage summary:\n"); debug_print_rusage (stderr); #endif
97258e2008-05-23Martin Stjernholm  if (throw_severity == THROW_EXIT) /* Do this after all thread cleanup to avoid false alarms if using * DO_PIKE_CLEANUP. */ pike_do_exit (throw_value.u.integer);
4bc7e42001-11-26Henrik Grubbström (Grubba)  /* FIXME: What about threads_disable? */
c91f892000-04-19Martin Stjernholm  mt_unlock_interpreter();
07513e1996-10-04Fredrik Hübinette (Hubbe)  th_exit(0);
9c8b2d1997-04-20Henrik Grubbström (Grubba)  /* NOT_REACHED, but removes a warning */
0431312003-02-15Henrik Grubbström (Grubba)  return 0;
07513e1996-10-04Fredrik Hübinette (Hubbe) }
97ffe41997-01-26Per Hedbor #ifdef UNIX_THREADS int num_lwps = 1; #endif
b1b51f1996-10-11Fredrik Hübinette (Hubbe) 
e413da2001-02-01Henrik Grubbström (Grubba) /*! @class Thread */
a44a582002-09-29Martin Nilsson /*! @decl void create(function(mixed...:void) f, mixed ... args)
e413da2001-02-01Henrik Grubbström (Grubba)  *! *! This function creates a new thread which will run simultaneously *! to the rest of the program. The new thread will call the function *! @[f] with the arguments @[args]. When @[f] returns the thread will cease *! to exist. *! *! All Pike functions are 'thread safe' meaning that running *! a function at the same time from different threads will not corrupt *! any internal data in the Pike process. *! *! @returns *! The returned value will be the same as the return value of
c7b7dd2001-10-28Martin Nilsson  *! @[this_thread()] for the new thread.
e413da2001-02-01Henrik Grubbström (Grubba)  *! *! @note *! This function is only available on systems with POSIX or UNIX or WIN32 *! threads support. *! *! @seealso *! @[Mutex], @[Condition], @[this_thread()] */
07513e1996-10-04Fredrik Hübinette (Hubbe) void f_thread_create(INT32 args) {
1d456f2003-02-20Henrik Grubbström (Grubba)  struct thread_starter arg;
0431312003-02-15Henrik Grubbström (Grubba)  struct thread_state *thread_state = (struct thread_state *)Pike_fp->current_storage;
07513e1996-10-04Fredrik Hübinette (Hubbe)  int tmp;
0431312003-02-15Henrik Grubbström (Grubba)  if (thread_state->status != THREAD_NOT_STARTED) {
6818b02003-02-20Henrik Grubbström (Grubba)  Pike_error("Threads can not be restarted (status:%d).\n", thread_state->status);
0431312003-02-15Henrik Grubbström (Grubba)  }
1d456f2003-02-20Henrik Grubbström (Grubba)  arg.args = aggregate_array(args); arg.thread_state = thread_state;
b2a0fb1997-02-06Henrik Grubbström (Grubba) 
2ef3b92005-01-25Henrik Grubbström (Grubba)  if (low_init_interpreter(&thread_state->state)) { free_array(arg.args); Pike_error("Out of memory allocating stack.\n"); }
222d922000-05-20Henrik Grubbström (Grubba) #ifdef HAVE_BROKEN_LINUX_THREAD_EUID
1d456f2003-02-20Henrik Grubbström (Grubba)  arg.euid = geteuid(); arg.egid = getegid();
222d922000-05-20Henrik Grubbström (Grubba) #endif /* HAVE_BROKEN_LINUX_THREAD_EUID */
c17fed2000-05-20Henrik Grubbström (Grubba) 
4743f81999-06-02Fredrik Hübinette (Hubbe)  do {
1d456f2003-02-20Henrik Grubbström (Grubba)  tmp = th_create(&thread_state->id,
d40e381999-10-14Henrik Grubbström (Grubba)  new_thread_func,
1d456f2003-02-20Henrik Grubbström (Grubba)  &arg);
700dac2002-02-05Martin Stjernholm  if (tmp == EINTR) check_threads_etc();
4743f81999-06-02Fredrik Hübinette (Hubbe)  } while( tmp == EINTR );
b2a0fb1997-02-06Henrik Grubbström (Grubba) 
6d1a5e1996-10-07Fredrik Hübinette (Hubbe)  if(!tmp) { num_threads++;
1d456f2003-02-20Henrik Grubbström (Grubba)  thread_table_insert(thread_state);
a29e021996-10-15Fredrik Hübinette (Hubbe) 
fe76ce1997-09-08Fredrik Hübinette (Hubbe)  if(!threads_evaluator_callback)
a29e021996-10-15Fredrik Hübinette (Hubbe)  { threads_evaluator_callback=add_to_callback(&evaluator_callbacks, check_threads, 0,0);
424d9c1999-05-02Fredrik Hübinette (Hubbe)  dmalloc_accept_leak(threads_evaluator_callback);
a29e021996-10-15Fredrik Hübinette (Hubbe)  }
0431312003-02-15Henrik Grubbström (Grubba)  /* Wait for the thread to start properly. * so that we can avoid races.
1d456f2003-02-20Henrik Grubbström (Grubba)  * * The main race is the one on current_object, * since it at this point only has one reference. * * We also want the stuff in arg to be copied properly * before we exit the function...
0431312003-02-15Henrik Grubbström (Grubba)  */
b867f92003-02-16Martin Stjernholm  SWAP_OUT_CURRENT_THREAD();
0431312003-02-15Henrik Grubbström (Grubba)  while (thread_state->status == THREAD_NOT_STARTED) {
f72d412004-04-23Henrik Grubbström (Grubba)  THREADS_FPRINTF(0, (stderr, "THREAD_CREATE %p waiting...\n", thread_state));
0431312003-02-15Henrik Grubbström (Grubba)  low_co_wait_interpreter(&thread_state->status_change); }
b867f92003-02-16Martin Stjernholm  SWAP_IN_CURRENT_THREAD();
6d1a5e1996-10-07Fredrik Hübinette (Hubbe)  } else {
2ef3b92005-01-25Henrik Grubbström (Grubba)  low_cleanup_interpret(&thread_state->state);
1d456f2003-02-20Henrik Grubbström (Grubba)  free_array(arg.args);
0431312003-02-15Henrik Grubbström (Grubba)  Pike_error("Failed to create thread (errno = %d).\n", tmp);
6d1a5e1996-10-07Fredrik Hübinette (Hubbe)  }
1d456f2003-02-20Henrik Grubbström (Grubba)  THREADS_FPRINTF(0, (stderr, "THREAD_CREATE -> t:%08x\n", (unsigned int)thread_state)); push_int(0);
6d1a5e1996-10-07Fredrik Hübinette (Hubbe) }
e413da2001-02-01Henrik Grubbström (Grubba) /*! @endclass */
1e4a641997-09-03Martin Stjernholm #ifdef UNIX_THREADS
e413da2001-02-01Henrik Grubbström (Grubba) /*! @decl void thread_set_concurrency(int concurrency)
c7b7dd2001-10-28Martin Nilsson  *! *! @fixme *! Document this function
e413da2001-02-01Henrik Grubbström (Grubba)  */
97ffe41997-01-26Per Hedbor void f_thread_set_concurrency(INT32 args) { int c=1;
d4ecd72003-01-05Martin Nilsson  if(args) c=Pike_sp[-args].u.integer; else SIMPLE_TOO_FEW_ARGS_ERROR("thread_set_concurrency", 1);
97ffe41997-01-26Per Hedbor  pop_n_elems(args);
09dceb1997-09-01Per Hedbor  num_lwps=c;
97ffe41997-01-26Per Hedbor  th_setconcurrency(c); }
1e4a641997-09-03Martin Stjernholm #endif
97ffe41997-01-26Per Hedbor 
e413da2001-02-01Henrik Grubbström (Grubba) /*! @decl Thread.Thread this_thread() *! *! This function returns the object that identifies this thread. *! *! @seealso
c7b7dd2001-10-28Martin Nilsson  *! @[Thread()]
e413da2001-02-01Henrik Grubbström (Grubba)  */
fa8c692000-11-30Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_this_thread(INT32 args)
6d1a5e1996-10-07Fredrik Hübinette (Hubbe) { pop_n_elems(args);
1d456f2003-02-20Henrik Grubbström (Grubba)  if (Pike_interpreter.thread_state) { ref_push_object(Pike_interpreter.thread_state->thread_obj); } else { /* Threads not enabled yet/anylonger */ push_undefined(); }
07513e1996-10-04Fredrik Hübinette (Hubbe) }
60d9872000-03-23Fredrik Hübinette (Hubbe) #define THIS_MUTEX ((struct mutex_storage *)(CURRENT_STORAGE))
5988921996-10-05Fredrik Hübinette (Hubbe)  /* Note: * No reference is kept to the key object, it is destructed if the * mutex is destructed. The key pointer is set to zero by the * key object when the key is destructed. */ struct mutex_storage { COND_T condition; struct object *key;
2702952004-04-21Martin Stjernholm  int num_waiting;
5988921996-10-05Fredrik Hübinette (Hubbe) }; struct key_storage { struct mutex_storage *mut;
33887a2002-10-28Martin Stjernholm  struct object *mutex_obj;
1d456f2003-02-20Henrik Grubbström (Grubba)  struct thread_state *owner; struct object *owner_obj;
4bdad01997-09-01Per Hedbor  int initialized;
5988921996-10-05Fredrik Hübinette (Hubbe) }; #define OB2KEY(X) ((struct key_storage *)((X)->storage))
07513e1996-10-04Fredrik Hübinette (Hubbe) 
e413da2001-02-01Henrik Grubbström (Grubba) /*! @class Mutex *!
c7b7dd2001-10-28Martin Nilsson  *! @[Mutex] is a class that implements mutual exclusion locks.
e413da2001-02-01Henrik Grubbström (Grubba)  *! Mutex locks are used to prevent multiple threads from simultaneously *! execute sections of code which access or change shared data. The basic *! operations for a mutex is locking and unlocking. If a thread attempts *! to lock an already locked mutex the thread will sleep until the mutex *! is unlocked. *! *! @note *! This class is simulated when Pike is compiled without thread support, *! so it's always available. *! *! In POSIX threads, mutex locks can only be unlocked by the same thread *! that locked them. In Pike any thread can unlock a locked mutex. */ /*! @decl MutexKey lock() *! @decl MutexKey lock(int type) *! *! This function attempts to lock the mutex. If the mutex is already *! locked by a different thread the current thread will sleep until the *! mutex is unlocked. The value returned is the 'key' to the lock. When
4f68012002-10-28Martin Stjernholm  *! the key is destructed or has no more references the mutex will
5fba122004-04-26Martin Stjernholm  *! automatically be unlocked.
e413da2001-02-01Henrik Grubbström (Grubba)  *! *! The @[type] argument specifies what @[lock()] should do if the *! mutex is already locked by this thread: *! @int
a9cdcf2001-02-06Henrik Grubbström (Grubba)  *! @value 0
e413da2001-02-01Henrik Grubbström (Grubba)  *! Throw an error. *! @value 1 *! Sleep until the mutex is unlocked. Useful if some *! other thread will unlock it. *! @value 2 *! Return zero. This allows recursion within a locked region of *! code, but in conjunction with other locks it easily leads *! to unspecified locking order and therefore a risk for deadlocks. *! @endint *!
d059be2004-04-23Martin Stjernholm  *! @note
5fba122004-04-26Martin Stjernholm  *! If the mutex is destructed while it's locked or while threads are *! waiting on it, it will continue to exist internally until the last *! thread has stopped waiting and the last @[MutexKey] has *! disappeared, but further calls to the functions in this class will *! fail as is usual for destructed objects.
d059be2004-04-23Martin Stjernholm  *!
d85b4b2004-05-01Martin Stjernholm  *! @note *! Pike 7.4 and earlier destructed any outstanding lock when the *! mutex was destructed, but threads waiting in @[lock] still got *! functioning locks as discussed above. This is inconsistent no *! matter how you look at it, so it was changed in 7.6. The old *! behavior is retained in compatibility mode for applications that *! explicitly destruct mutexes to unlock them. *!
e413da2001-02-01Henrik Grubbström (Grubba)  *! @seealso *! @[trylock()] */
07513e1996-10-04Fredrik Hübinette (Hubbe) void f_mutex_lock(INT32 args) {
5988921996-10-05Fredrik Hübinette (Hubbe)  struct mutex_storage *m;
07513e1996-10-04Fredrik Hübinette (Hubbe)  struct object *o;
a49ee61999-04-02Fredrik Hübinette (Hubbe)  INT_TYPE type;
5988921996-10-05Fredrik Hübinette (Hubbe) 
b867f92003-02-16Martin Stjernholm  DEBUG_CHECK_THREAD();
38e1e82001-11-08Fredrik Hübinette (Hubbe) 
07513e1996-10-04Fredrik Hübinette (Hubbe)  m=THIS_MUTEX;
a49ee61999-04-02Fredrik Hübinette (Hubbe)  if(!args) type=0; else get_all_args("mutex->lock",args,"%i",&type); switch(type) { default:
17f08c2000-07-06Fredrik Hübinette (Hubbe)  bad_arg_error("mutex->lock", Pike_sp-args, args, 2, "int(0..2)", Pike_sp+1-args,
69aa4b2003-01-26Mirar (Pontus Hagland)  "Unknown mutex locking style: %"PRINTPIKEINT"d\n",type);
a49ee61999-04-02Fredrik Hübinette (Hubbe)  case 0: case 2:
1d456f2003-02-20Henrik Grubbström (Grubba)  if(m->key && OB2KEY(m->key)->owner == Pike_interpreter.thread_state)
a49ee61999-04-02Fredrik Hübinette (Hubbe)  { THREADS_FPRINTF(0,
b867f92003-02-16Martin Stjernholm  (stderr, "Recursive LOCK k:%p, m:%p(%p), t:%p\n", OB2KEY(m->key), m, OB2KEY(m->key)->mut, Pike_interpreter.thread_state));
a49ee61999-04-02Fredrik Hübinette (Hubbe) 
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  if(type==0) Pike_error("Recursive mutex locks!\n");
a49ee61999-04-02Fredrik Hübinette (Hubbe)  pop_n_elems(args); push_int(0);
c273692000-02-10Fredrik Hübinette (Hubbe)  return;
a49ee61999-04-02Fredrik Hübinette (Hubbe)  } case 1: break; }
46d7bf1997-09-03Henrik Grubbström (Grubba)  /* Needs to be cloned here, since create() * might use threads. */
f777b72003-02-15Henrik Grubbström (Grubba)  o=fast_clone_object(mutex_key);
4bdad01997-09-01Per Hedbor 
b867f92003-02-16Martin Stjernholm  DEBUG_CHECK_THREAD();
26cd941999-05-07Fredrik Hübinette (Hubbe) 
0a861b1997-09-17Fredrik Hübinette (Hubbe)  if(m->key)
fe76ce1997-09-08Fredrik Hübinette (Hubbe)  {
2702952004-04-21Martin Stjernholm  m->num_waiting++;
adb19b1999-06-30Fredrik Hübinette (Hubbe)  if(threads_disabled) { free_object(o);
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Cannot wait for mutexes when threads are disabled!\n");
adb19b1999-06-30Fredrik Hübinette (Hubbe)  }
b504ed1997-09-21Fredrik Hübinette (Hubbe)  do
0a861b1997-09-17Fredrik Hübinette (Hubbe)  {
b867f92003-02-16Martin Stjernholm  THREADS_FPRINTF(1, (stderr,"WAITING TO LOCK m:%p\n",m));
2702952004-04-21Martin Stjernholm  SWAP_OUT_CURRENT_THREAD();
c91f892000-04-19Martin Stjernholm  co_wait_interpreter(& m->condition);
700dac2002-02-05Martin Stjernholm  SWAP_IN_CURRENT_THREAD(); check_threads_etc();
b504ed1997-09-21Fredrik Hübinette (Hubbe)  }while(m->key);
2702952004-04-21Martin Stjernholm  m->num_waiting--;
fe76ce1997-09-08Fredrik Hübinette (Hubbe)  }
2702952004-04-21Martin Stjernholm  #ifdef PICKY_MUTEX if (!Pike_fp->current_object->prog) { free_object (o); if (!m->num_waiting) co_destroy (&m->condition); Pike_error ("Mutex was destructed while waiting for lock.\n"); } #endif
5988921996-10-05Fredrik Hübinette (Hubbe)  m->key=o;
46d7bf1997-09-03Henrik Grubbström (Grubba)  OB2KEY(o)->mut=m;
33887a2002-10-28Martin Stjernholm  add_ref (OB2KEY(o)->mutex_obj = Pike_fp->current_object);
fe76ce1997-09-08Fredrik Hübinette (Hubbe) 
b867f92003-02-16Martin Stjernholm  DEBUG_CHECK_THREAD(); THREADS_FPRINTF(1, (stderr, "LOCK k:%p, m:%p(%p), t:%p\n", OB2KEY(o), m, OB2KEY(m->key)->mut, Pike_interpreter.thread_state));
65d3c31997-09-08Fredrik Hübinette (Hubbe)  pop_n_elems(args);
07513e1996-10-04Fredrik Hübinette (Hubbe)  push_object(o); }
e413da2001-02-01Henrik Grubbström (Grubba) /*! @decl MutexKey trylock() *! @decl MutexKey trylock(int type) *! *! This function performs the same operation as @[lock()], but if the mutex *! is already locked, it will return zero instead of sleeping until it's *! unlocked. *! *! @seealso *! @[lock()] */
07513e1996-10-04Fredrik Hübinette (Hubbe) void f_mutex_trylock(INT32 args) {
5988921996-10-05Fredrik Hübinette (Hubbe)  struct mutex_storage *m; struct object *o;
65a5492000-08-10Per Hedbor  INT_TYPE type;
5988921996-10-05Fredrik Hübinette (Hubbe)  int i=0;
07513e1996-10-04Fredrik Hübinette (Hubbe) 
46d7bf1997-09-03Henrik Grubbström (Grubba)  /* No reason to release the interpreter lock here * since we aren't calling any functions that take time. */
a49ee61999-04-02Fredrik Hübinette (Hubbe)  m=THIS_MUTEX; if(!args) type=0; else
afcf5f2000-10-04Martin Stjernholm  get_all_args("mutex->trylock",args,"%i",&type);
a49ee61999-04-02Fredrik Hübinette (Hubbe)  switch(type)
65df5c1997-09-01Per Hedbor  {
a49ee61999-04-02Fredrik Hübinette (Hubbe)  default:
17f08c2000-07-06Fredrik Hübinette (Hubbe)  bad_arg_error("mutex->trylock", Pike_sp-args, args, 2, "int(0..2)", Pike_sp+1-args,
69aa4b2003-01-26Mirar (Pontus Hagland)  "Unknown mutex locking style: %"PRINTPIKEINT"d\n",type);
a49ee61999-04-02Fredrik Hübinette (Hubbe)  case 0:
1d456f2003-02-20Henrik Grubbström (Grubba)  if(m->key && OB2KEY(m->key)->owner == Pike_interpreter.thread_state)
a49ee61999-04-02Fredrik Hübinette (Hubbe)  {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Recursive mutex locks!\n");
a49ee61999-04-02Fredrik Hübinette (Hubbe)  } case 2: case 1: break;
65df5c1997-09-01Per Hedbor  }
50fd181997-09-17Fredrik Hübinette (Hubbe) 
a49ee61999-04-02Fredrik Hübinette (Hubbe)  o=clone_object(mutex_key,0);
5988921996-10-05Fredrik Hübinette (Hubbe)  if(!m->key) {
e4293f1997-04-17Fredrik Hübinette (Hubbe)  OB2KEY(o)->mut=m;
33887a2002-10-28Martin Stjernholm  add_ref (OB2KEY(o)->mutex_obj = Pike_fp->current_object);
5988921996-10-05Fredrik Hübinette (Hubbe)  m->key=o; i=1; }
4bdad01997-09-01Per Hedbor 
65d3c31997-09-08Fredrik Hübinette (Hubbe)  pop_n_elems(args);
07513e1996-10-04Fredrik Hübinette (Hubbe)  if(i) { push_object(o); } else {
5988921996-10-05Fredrik Hübinette (Hubbe)  destruct(o); free_object(o);
07513e1996-10-04Fredrik Hübinette (Hubbe)  push_int(0); } }
b9bba02001-08-08Leif Stensson /*! @decl Thread.Thread current_locking_thread() *! *! This mutex method returns the object that identifies the thread that *! has locked the mutex. 0 is returned if the mutex isn't locked. *! *! @seealso
c7b7dd2001-10-28Martin Nilsson  *! @[Thread()]
b9bba02001-08-08Leif Stensson  */ PMOD_EXPORT void f_mutex_locking_thread(INT32 args) { struct mutex_storage *m = THIS_MUTEX; pop_n_elems(args); if (m->key && OB2KEY(m->key)->owner)
1d456f2003-02-20Henrik Grubbström (Grubba)  ref_push_object(OB2KEY(m->key)->owner->thread_obj);
b9bba02001-08-08Leif Stensson  else push_int(0); }
33887a2002-10-28Martin Stjernholm /*! @decl Thread.MutexKey current_locking_key()
b9bba02001-08-08Leif Stensson  *! *! This mutex method returns the key object currently governing *! the lock on this mutex. 0 is returned if the mutex isn't locked. *! *! @seealso
c7b7dd2001-10-28Martin Nilsson  *! @[Thread()]
b9bba02001-08-08Leif Stensson  */ PMOD_EXPORT void f_mutex_locking_key(INT32 args) { struct mutex_storage *m = THIS_MUTEX; pop_n_elems(args); if (m->key) ref_push_object(m->key); else push_int(0); }
5988921996-10-05Fredrik Hübinette (Hubbe) void init_mutex_obj(struct object *o) { co_init(& THIS_MUTEX->condition); THIS_MUTEX->key=0;
2702952004-04-21Martin Stjernholm  THIS_MUTEX->num_waiting = 0;
5988921996-10-05Fredrik Hübinette (Hubbe) }
07513e1996-10-04Fredrik Hübinette (Hubbe) 
5988921996-10-05Fredrik Hübinette (Hubbe) void exit_mutex_obj(struct object *o) {
2702952004-04-21Martin Stjernholm  struct mutex_storage *m = THIS_MUTEX;
f72d412004-04-23Henrik Grubbström (Grubba)  struct object *key = m->key;
2702952004-04-21Martin Stjernholm 
b867f92003-02-16Martin Stjernholm  THREADS_FPRINTF(1, (stderr, "DESTROYING MUTEX m:%p\n", THIS_MUTEX));
2702952004-04-21Martin Stjernholm 
5fba122004-04-26Martin Stjernholm #ifndef PICKY_MUTEX if (key) { /* The last key will destroy m->condition in its exit hook. */ THREADS_FPRINTF(1, (stderr, "Destructed mutex is in use - delaying cleanup\n")); } else { #ifdef PIKE_DEBUG if (m->num_waiting) Pike_error ("key/num_waiting confusion.\n"); #endif co_destroy(& m->condition); } #else
f72d412004-04-23Henrik Grubbström (Grubba)  if(key) {
2702952004-04-21Martin Stjernholm  m->key=0;
5fba122004-04-26Martin Stjernholm  destruct(key); /* Will destroy m->condition if m->num_waiting is zero. */
2702952004-04-21Martin Stjernholm  if(m->num_waiting) {
5fba122004-04-26Martin Stjernholm  THREADS_FPRINTF(1, (stderr, "Destructed mutex is being waited on.\n"));
2702952004-04-21Martin Stjernholm  /* exit_mutex_key_obj has already signalled, but since the * waiting threads will throw an error instead of making a new * lock we need to double it to a broadcast. The last thread * that stops waiting will destroy m->condition. */ co_broadcast (&m->condition); } }
5fba122004-04-26Martin Stjernholm  else co_destroy(& m->condition); #endif
5988921996-10-05Fredrik Hübinette (Hubbe) }
d85b4b2004-05-01Martin Stjernholm void exit_mutex_obj_compat_7_4(struct object *o) { struct mutex_storage *m = THIS_MUTEX; struct object *key = m->key; THREADS_FPRINTF(1, (stderr, "DESTROYING MUTEX m:%p\n", THIS_MUTEX)); if(key) { m->key=0; destruct(key); /* Will destroy m->condition if m->num_waiting is zero. */ } else { #ifdef PIKE_DEBUG if (m->num_waiting) Pike_error ("key/num_waiting confusion.\n"); #endif co_destroy(& m->condition); } }
e413da2001-02-01Henrik Grubbström (Grubba) /*! @endclass */
192ceb2003-11-22Henrik Grubbström (Grubba) /*! @class MutexKey *! *! Objects of this class are returned by @[Mutex()->lock()] *! and @[Mutex()->trylock()]. They are also passed as arguments *! to @[Condition()->wait()]. *! *! As long as they are held, the corresponding mutex will be locked. *! *! The corresponding mutex will be unlocked when the object *! is destructed (eg by not having any references left). *! *! @seealso *! @[Mutex], @[Condition] */
60d9872000-03-23Fredrik Hübinette (Hubbe) #define THIS_KEY ((struct key_storage *)(CURRENT_STORAGE))
5988921996-10-05Fredrik Hübinette (Hubbe) void init_mutex_key_obj(struct object *o) {
b867f92003-02-16Martin Stjernholm  THREADS_FPRINTF(1, (stderr, "KEY k:%p, o:%p\n", THIS_KEY, Pike_interpreter.thread_state));
5988921996-10-05Fredrik Hübinette (Hubbe)  THIS_KEY->mut=0;
33887a2002-10-28Martin Stjernholm  THIS_KEY->mutex_obj = NULL;
1d456f2003-02-20Henrik Grubbström (Grubba)  THIS_KEY->owner = Pike_interpreter.thread_state; add_ref(THIS_KEY->owner_obj = Pike_interpreter.thread_state->thread_obj);
5988921996-10-05Fredrik Hübinette (Hubbe)  THIS_KEY->initialized=1; }
07513e1996-10-04Fredrik Hübinette (Hubbe)  void exit_mutex_key_obj(struct object *o) {
b867f92003-02-16Martin Stjernholm  THREADS_FPRINTF(1, (stderr, "UNLOCK k:%p m:(%p) t:%p o:%p\n", THIS_KEY, THIS_KEY->mut, Pike_interpreter.thread_state, THIS_KEY->owner));
5988921996-10-05Fredrik Hübinette (Hubbe)  if(THIS_KEY->mut)
07513e1996-10-04Fredrik Hübinette (Hubbe)  {
03b1fe1997-09-06Per Hedbor  struct mutex_storage *mut = THIS_KEY->mut;
f72d412004-04-23Henrik Grubbström (Grubba)  struct object *mutex_obj;
c113871997-09-15Henrik Grubbström (Grubba) 
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
f72d412004-04-23Henrik Grubbström (Grubba)  /* Note: mut->key can be NULL if our corresponding mutex * has been destructed. */ if(mut->key && (mut->key != o)) Pike_fatal("Mutex unlock from wrong key %p != %p!\n", THIS_KEY->mut->key, o);
5988921996-10-05Fredrik Hübinette (Hubbe) #endif
03b1fe1997-09-06Per Hedbor  mut->key=0;
46d7bf1997-09-03Henrik Grubbström (Grubba)  if (THIS_KEY->owner) {
1d456f2003-02-20Henrik Grubbström (Grubba)  THIS_KEY->owner = NULL; } if (THIS_KEY->owner_obj) { free_object(THIS_KEY->owner_obj); THIS_KEY->owner_obj=0;
46d7bf1997-09-03Henrik Grubbström (Grubba)  }
5988921996-10-05Fredrik Hübinette (Hubbe)  THIS_KEY->mut=0; THIS_KEY->initialized=0;
f72d412004-04-23Henrik Grubbström (Grubba)  mutex_obj = THIS_KEY->mutex_obj; THIS_KEY->mutex_obj = NULL;
2702952004-04-21Martin Stjernholm  if (mut->num_waiting)
f72d412004-04-23Henrik Grubbström (Grubba)  co_signal(&mut->condition);
73cd0e2005-11-15Henrik Grubbström (Grubba)  else if (mutex_obj && !mutex_obj->prog)
2702952004-04-21Martin Stjernholm  co_destroy (&mut->condition);
73cd0e2005-11-15Henrik Grubbström (Grubba)  if (mutex_obj) free_object(mutex_obj);
07513e1996-10-04Fredrik Hübinette (Hubbe)  } }
192ceb2003-11-22Henrik Grubbström (Grubba) /*! @endclass */
e413da2001-02-01Henrik Grubbström (Grubba) /*! @class Condition *! *! Implementation of condition variables. *! *! Condition variables are used by threaded programs *! to wait for events happening in other threads. *! *! @note *! Condition variables are only available on systems with thread *! support. The Condition class is not simulated otherwise, since that *! can't be done accurately without continuations. *! *! @seealso
c7b7dd2001-10-28Martin Nilsson  *! @[Mutex]
e413da2001-02-01Henrik Grubbström (Grubba)  */
8349b42006-01-29Henrik Grubbström (Grubba) struct pike_cond { COND_T cond; int wait_count; };
b0c72a2006-01-30Henrik Grubbström (Grubba) #define THIS_COND ((struct pike_cond *)(CURRENT_STORAGE))
8349b42006-01-29Henrik Grubbström (Grubba) 
4a59c02002-09-30Henrik Grubbström (Grubba) /*! @decl void wait(Thread.MutexKey mutex_key)
e413da2001-02-01Henrik Grubbström (Grubba)  *!
2ef3b92005-01-25Henrik Grubbström (Grubba)  *! Wait for condition.
e413da2001-02-01Henrik Grubbström (Grubba)  *! *! This function makes the current thread sleep until the condition
2702952004-04-21Martin Stjernholm  *! variable is signalled. The argument should be a @[Thread.MutexKey] *! object for a @[Thread.Mutex]. It will be unlocked atomically *! before waiting for the signal and then relocked atomically when *! the signal is received. *! *! The thread that sends the signal should have the mutex locked *! while sending it. Otherwise it's impossible to avoid races where *! signals are sent while the listener(s) haven't arrived to the *! @[wait] calls yet.
e413da2001-02-01Henrik Grubbström (Grubba)  *!
4a59c02002-09-30Henrik Grubbström (Grubba)  *! @note *! In Pike 7.2 and earlier it was possible to call @[wait()]
2702952004-04-21Martin Stjernholm  *! without arguments. This possibility was removed in later *! versions since it unavoidably leads to programs with races *! and/or deadlocks.
4a59c02002-09-30Henrik Grubbström (Grubba)  *!
8349b42006-01-29Henrik Grubbström (Grubba)  *! @note *! Note also that any threads waiting on the condition will be *! waken up when it gets destructed. *!
e413da2001-02-01Henrik Grubbström (Grubba)  *! @seealso
c7b7dd2001-10-28Martin Nilsson  *! @[Mutex->lock()]
e413da2001-02-01Henrik Grubbström (Grubba)  */
07513e1996-10-04Fredrik Hübinette (Hubbe) void f_cond_wait(INT32 args) {
d059be2004-04-23Martin Stjernholm  struct object *key, *mutex_obj;
4a59c02002-09-30Henrik Grubbström (Grubba)  struct mutex_storage *mut;
8349b42006-01-29Henrik Grubbström (Grubba)  struct pike_cond *c;
07513e1996-10-04Fredrik Hübinette (Hubbe) 
1c3c3d2000-03-24Henrik Grubbström (Grubba)  if(threads_disabled)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Cannot wait for conditions when threads are disabled!\n");
4a59c02002-09-30Henrik Grubbström (Grubba)  get_all_args("condition->wait", args, "%o", &key);
1c3c3d2000-03-24Henrik Grubbström (Grubba) 
4a59c02002-09-30Henrik Grubbström (Grubba)  if ((key->prog != mutex_key) || (!(OB2KEY(key)->initialized)) || (!(mut = OB2KEY(key)->mut))) { Pike_error("Bad argument 1 to condition->wait()\n"); }
1c3c3d2000-03-24Henrik Grubbström (Grubba)  if(args > 1) { pop_n_elems(args - 1); args = 1; }
07513e1996-10-04Fredrik Hübinette (Hubbe) 
4a59c02002-09-30Henrik Grubbström (Grubba)  c = THIS_COND;
368d4a1997-09-03Per Hedbor 
4a59c02002-09-30Henrik Grubbström (Grubba)  /* Unlock mutex */
d059be2004-04-23Martin Stjernholm  mutex_obj = OB2KEY(key)->mutex_obj;
4a59c02002-09-30Henrik Grubbström (Grubba)  mut->key=0; OB2KEY(key)->mut=0;
d059be2004-04-23Martin Stjernholm  OB2KEY(key)->mutex_obj = NULL;
4a59c02002-09-30Henrik Grubbström (Grubba)  co_signal(& mut->condition);
88fe361997-09-04Per Hedbor 
4a59c02002-09-30Henrik Grubbström (Grubba)  /* Wait and allow mutex operations */
1c3c3d2000-03-24Henrik Grubbström (Grubba)  SWAP_OUT_CURRENT_THREAD();
8349b42006-01-29Henrik Grubbström (Grubba)  c->wait_count++; co_wait_interpreter(&(c->cond)); c->wait_count--;
1c3c3d2000-03-24Henrik Grubbström (Grubba)  SWAP_IN_CURRENT_THREAD();
4a59c02002-09-30Henrik Grubbström (Grubba)  /* Lock mutex */
d059be2004-04-23Martin Stjernholm  mut->num_waiting++;
4a59c02002-09-30Henrik Grubbström (Grubba)  while(mut->key) { SWAP_OUT_CURRENT_THREAD(); co_wait_interpreter(& mut->condition); SWAP_IN_CURRENT_THREAD(); check_threads_etc(); } mut->key=key; OB2KEY(key)->mut=mut;
d059be2004-04-23Martin Stjernholm  OB2KEY(key)->mutex_obj = mutex_obj;
f72d412004-04-23Henrik Grubbström (Grubba)  mut->num_waiting--;
d059be2004-04-23Martin Stjernholm  #ifdef PICKY_MUTEX if (!mutex_obj->prog) {
262b8d2004-04-26Martin Stjernholm  if (!mut->num_waiting) co_destroy (&mut->condition);
d059be2004-04-23Martin Stjernholm  Pike_error ("Mutex was destructed while waiting for lock.\n"); } #endif
4a59c02002-09-30Henrik Grubbström (Grubba)  pop_stack(); return;
07513e1996-10-04Fredrik Hübinette (Hubbe) }
e413da2001-02-01Henrik Grubbström (Grubba) /*! @decl void signal() *! *! @[signal()] wakes up one of the threads currently waiting for the *! condition. *!
a9cdcf2001-02-06Henrik Grubbström (Grubba)  *! @note
e413da2001-02-01Henrik Grubbström (Grubba)  *! Sometimes more than one thread is woken up. *! *! @seealso *! @[broadcast()] */
8349b42006-01-29Henrik Grubbström (Grubba) void f_cond_signal(INT32 args) { pop_n_elems(args); co_signal(&(THIS_COND->cond)); }
e413da2001-02-01Henrik Grubbström (Grubba)  /*! @decl void broadcast() *! *! @[broadcast()] wakes up all threads currently waiting for this condition. *! *! @seealso *! @[signal()] */
8349b42006-01-29Henrik Grubbström (Grubba) void f_cond_broadcast(INT32 args) { pop_n_elems(args); co_broadcast(&(THIS_COND->cond)); }
e413da2001-02-01Henrik Grubbström (Grubba) 
8349b42006-01-29Henrik Grubbström (Grubba) void init_cond_obj(struct object *o) { co_init(&(THIS_COND->cond)); THIS_COND->wait_count = 0; }
36e67a2006-01-28Martin Stjernholm  void exit_cond_obj(struct object *o) {
8349b42006-01-29Henrik Grubbström (Grubba)  /* Wake up any threads that might be waiting on this cond. * * Note that we are already destructed (o->prog == NULL), * so wait_count can't increase. * * FIXME: This code wouldn't be needed if exit callbacks were called * only when the ref count reaches zero. * /grubba 2006-01-29 */ while (THIS_COND->wait_count) {
a20b1b2006-04-25David Hedbor  co_broadcast(&(THIS_COND->cond));
8349b42006-01-29Henrik Grubbström (Grubba)  THREADS_ALLOW(); #ifdef HAVE_NO_YIELD sleep(0); #else /* HAVE_NO_YIELD */ th_yield(); #endif /* HAVE_NO_YIELD */ THREADS_DISALLOW(); } co_destroy(&(THIS_COND->cond));
36e67a2006-01-28Martin Stjernholm }
07513e1996-10-04Fredrik Hübinette (Hubbe) 
e413da2001-02-01Henrik Grubbström (Grubba) /*! @endclass */ /*! @class Thread */ /*! @decl array(mixed) backtrace() *! *! Returns the current call stack for the thread. *! *! @returns *! The result has the same format as for @[predef::backtrace()]. *! *! @seealso *! @[predef::backtrace()] */
a7fef41997-09-03Per Hedbor void f_thread_backtrace(INT32 args) {
a8e9892001-09-05Fredrik Hübinette (Hubbe)  void low_backtrace(struct Pike_interpreter *);
17f08c2000-07-06Fredrik Hübinette (Hubbe)  struct thread_state *foo = THIS_THREAD;
a8e9892001-09-05Fredrik Hübinette (Hubbe) 
a7fef41997-09-03Per Hedbor  pop_n_elems(args);
a8e9892001-09-05Fredrik Hübinette (Hubbe) 
1d456f2003-02-20Henrik Grubbström (Grubba)  if(foo == Pike_interpreter.thread_state)
fad4ca2001-09-05Fredrik Hübinette (Hubbe)  { f_backtrace(0); } else if(foo->state.stack_pointer)
a7fef41997-09-03Per Hedbor  {
a8e9892001-09-05Fredrik Hübinette (Hubbe)  low_backtrace(& foo->state);
fad4ca2001-09-05Fredrik Hübinette (Hubbe)  } else {
a7fef41997-09-03Per Hedbor  push_int(0); f_allocate(1); } }
e413da2001-02-01Henrik Grubbström (Grubba) /*! @decl int status()
6f13822006-04-07Martin Stjernholm  *! *! Returns the status of the thread. *! *! @returns *! @int
8678ad2006-08-09Martin Nilsson  *! @value Thread.THREAD_NOT_STARTED *! @value Thread.THREAD_RUNNING *! @value Thread.THREAD_EXITED
6f13822006-04-07Martin Stjernholm  *! @endint
e413da2001-02-01Henrik Grubbström (Grubba)  */
5740881998-01-01Fredrik Hübinette (Hubbe) void f_thread_id_status(INT32 args) { pop_n_elems(args); push_int(THIS_THREAD->status); }
e413da2001-02-01Henrik Grubbström (Grubba) /*! @decl static string _sprintf(int c) *!
5e50ef2001-09-25Henrik Grubbström (Grubba)  *! Returns a string identifying the thread.
e413da2001-02-01Henrik Grubbström (Grubba)  */
9a0d422000-02-06Martin Stjernholm void f_thread_id__sprintf (INT32 args) {
e6dbc22002-11-29Marcus Comstedt  int c = 0; if(args>0 && Pike_sp[-args].type == PIKE_T_INT) c = Pike_sp[-args].u.integer;
9a0d422000-02-06Martin Stjernholm  pop_n_elems (args);
e6dbc22002-11-29Marcus Comstedt  if(c != 'O') { push_undefined(); return; }
9a0d422000-02-06Martin Stjernholm  push_constant_text ("Thread.Thread(");
d2361e2003-06-30Martin Stjernholm  push_int64(PTR_TO_INT(THREAD_T_TO_PTR(THIS_THREAD->id)));
9a0d422000-02-06Martin Stjernholm  push_constant_text (")"); f_add (3); }
5e50ef2001-09-25Henrik Grubbström (Grubba) /*! @decl static int id_number() *! *! Returns an id number identifying the thread.
d685b92001-09-25Henrik Grubbström (Grubba)  *! *! @note *! This function was added in Pike 7.2.204.
5e50ef2001-09-25Henrik Grubbström (Grubba)  */ void f_thread_id_id_number(INT32 args) { pop_n_elems(args);
d2361e2003-06-30Martin Stjernholm  push_int64(PTR_TO_INT(THREAD_T_TO_PTR(THIS_THREAD->id)));
5e50ef2001-09-25Henrik Grubbström (Grubba) }
442abd2004-06-29Alexander Demenshin /*! @decl mixed wait()
e413da2001-02-01Henrik Grubbström (Grubba)  *! *! Waits for the thread to complete, and then returns *! the value returned from the thread function. */
5740881998-01-01Fredrik Hübinette (Hubbe) static void f_thread_id_result(INT32 args) {
17f08c2000-07-06Fredrik Hübinette (Hubbe)  struct thread_state *th=THIS_THREAD;
5740881998-01-01Fredrik Hübinette (Hubbe) 
4bc7e42001-11-26Henrik Grubbström (Grubba)  if (threads_disabled) { Pike_error("Cannot wait for threads when threads are disabled!\n"); }
f72d412004-04-23Henrik Grubbström (Grubba)  THREADS_FPRINTF(0, (stderr,
442abd2004-06-29Alexander Demenshin  "Thread->wait(): Waiting for thread %p (state:%d).\n",
f72d412004-04-23Henrik Grubbström (Grubba)  th, th->status));
700dac2002-02-05Martin Stjernholm  while(th->status != THREAD_EXITED) { SWAP_OUT_CURRENT_THREAD();
c91f892000-04-19Martin Stjernholm  co_wait_interpreter(&th->status_change);
700dac2002-02-05Martin Stjernholm  SWAP_IN_CURRENT_THREAD(); check_threads_etc();
f72d412004-04-23Henrik Grubbström (Grubba)  THREADS_FPRINTF(0, (stderr,
442abd2004-06-29Alexander Demenshin  "Thread->wait(): Waiting for thread %p (state:%d).\n",
f72d412004-04-23Henrik Grubbström (Grubba)  th, th->status));
700dac2002-02-05Martin Stjernholm  }
5740881998-01-01Fredrik Hübinette (Hubbe) 
0431312003-02-15Henrik Grubbström (Grubba)  assign_svalue_no_free(Pike_sp, &th->result);
17f08c2000-07-06Fredrik Hübinette (Hubbe)  Pike_sp++;
50ea682003-03-14Henrik Grubbström (Grubba)  dmalloc_touch_svalue(Pike_sp-1);
5740881998-01-01Fredrik Hübinette (Hubbe) }
9595b92004-08-12Henrik Grubbström (Grubba) static int num_pending_interrupts = 0; static struct callback *thread_interrupt_callback = NULL; static void check_thread_interrupt(struct callback *foo, void *bar, void *gazonk) {
286b312004-12-30Henrik Grubbström (Grubba)  if (Pike_interpreter.thread_state->flags & THREAD_FLAG_SIGNAL_MASK) { if (Pike_interpreter.thread_state->flags & THREAD_FLAG_TERM) { throw_severity = THROW_THREAD_EXIT; } else { throw_severity = THROW_ERROR; } Pike_interpreter.thread_state->flags &= ~THREAD_FLAG_SIGNAL_MASK;
9595b92004-08-12Henrik Grubbström (Grubba)  if (!--num_pending_interrupts) { remove_callback(foo); thread_interrupt_callback = NULL; }
286b312004-12-30Henrik Grubbström (Grubba)  if (throw_severity == THROW_ERROR) { Pike_error("Interrupted.\n"); } else { push_int(-1); assign_svalue(&throw_value, Pike_sp-1); pike_throw(); }
9595b92004-08-12Henrik Grubbström (Grubba)  } } /*! @decl void interrupt() *! @decl void interrupt(string msg) *! *! Interrupt the thread with the message @[msg]. *! *! @fixme *! The argument @[msg] is currently ignored. *! *! @note *! Interrupts are asynchronous, and are currently not queued. */ static void f_thread_id_interrupt(INT32 args) { /* FIXME: The msg argument is not supported yet. */ pop_n_elems(args);
286b312004-12-30Henrik Grubbström (Grubba)  if (!(THIS_THREAD->flags & THREAD_FLAG_SIGNAL_MASK)) {
9595b92004-08-12Henrik Grubbström (Grubba)  THIS_THREAD->flags |= THREAD_FLAG_INTR; num_pending_interrupts++; if (!thread_interrupt_callback) { thread_interrupt_callback = add_to_callback(&evaluator_callbacks, check_thread_interrupt, 0, 0); } /* FIXME: Actually interrupt the thread. */ } push_int(0); }
286b312004-12-30Henrik Grubbström (Grubba) /*! @decl void kill() *! *! Interrupt the thread, and terminate it. *! *! @note *! Interrupts are asynchronous, and are currently not queued. */ static void f_thread_id_kill(INT32 args) { pop_n_elems(args); if (!(THIS_THREAD->flags & THREAD_FLAG_SIGNAL_MASK)) { num_pending_interrupts++; if (!thread_interrupt_callback) { thread_interrupt_callback = add_to_callback(&evaluator_callbacks, check_thread_interrupt, 0, 0); } /* FIXME: Actually interrupt the thread. */ } THIS_THREAD->flags |= THREAD_FLAG_TERM; push_int(0); }
a7fef41997-09-03Per Hedbor void init_thread_obj(struct object *o) {
16479e2002-11-18Martin Stjernholm  MEMSET(&THIS_THREAD->state, 0, sizeof(struct Pike_interpreter));
1d456f2003-02-20Henrik Grubbström (Grubba)  THIS_THREAD->thread_obj = Pike_fp->current_object;
16479e2002-11-18Martin Stjernholm  THIS_THREAD->swapped = 0;
5740881998-01-01Fredrik Hübinette (Hubbe)  THIS_THREAD->status=THREAD_NOT_STARTED;
9595b92004-08-12Henrik Grubbström (Grubba)  THIS_THREAD->flags = 0;
0431312003-02-15Henrik Grubbström (Grubba)  THIS_THREAD->result.type = T_INT; THIS_THREAD->result.subtype = NUMBER_UNDEFINED; THIS_THREAD->result.u.integer = 0;
5740881998-01-01Fredrik Hübinette (Hubbe)  co_init(& THIS_THREAD->status_change);
d86cd71998-08-24Marcus Comstedt  THIS_THREAD->thread_local=NULL;
247f732007-06-10Martin Stjernholm #ifdef CPU_TIME_MIGHT_BE_THREAD_LOCAL
f4a9952003-02-08Martin Stjernholm  THIS_THREAD->auto_gc_time = 0; #endif
5740881998-01-01Fredrik Hübinette (Hubbe) } void exit_thread_obj(struct object *o) {
286b312004-12-30Henrik Grubbström (Grubba)  if (THIS_THREAD->flags & THREAD_FLAG_SIGNAL_MASK) { Pike_interpreter.thread_state->flags &= ~THREAD_FLAG_SIGNAL_MASK;
9595b92004-08-12Henrik Grubbström (Grubba)  if (!--num_pending_interrupts) { remove_callback(thread_interrupt_callback); thread_interrupt_callback = NULL; } }
d86cd71998-08-24Marcus Comstedt  if(THIS_THREAD->thread_local != NULL) { free_mapping(THIS_THREAD->thread_local); THIS_THREAD->thread_local = NULL; }
5740881998-01-01Fredrik Hübinette (Hubbe)  co_destroy(& THIS_THREAD->status_change);
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  th_destroy(& THIS_THREAD->id);
1d456f2003-02-20Henrik Grubbström (Grubba)  THIS_THREAD->thread_obj = NULL;
a7fef41997-09-03Per Hedbor }
a9cdcf2001-02-06Henrik Grubbström (Grubba) /*! @endclass
e413da2001-02-01Henrik Grubbström (Grubba)  */
a5bd2b2000-06-10Martin Stjernholm static void thread_was_recursed(struct object *o)
f6d0171997-10-15Fredrik Hübinette (Hubbe) {
17f08c2000-07-06Fredrik Hübinette (Hubbe)  struct thread_state *tmp=THIS_THREAD;
d86cd71998-08-24Marcus Comstedt  if(tmp->thread_local != NULL)
b102b02000-06-10Martin Stjernholm  gc_recurse_mapping(tmp->thread_local);
d86cd71998-08-24Marcus Comstedt } static void thread_was_checked(struct object *o) {
17f08c2000-07-06Fredrik Hübinette (Hubbe)  struct thread_state *tmp=THIS_THREAD;
d86cd71998-08-24Marcus Comstedt  if(tmp->thread_local != NULL)
e1a35e2003-09-08Martin Stjernholm  debug_gc_check (tmp->thread_local,
d9d6f02001-06-30Martin Stjernholm  " as mapping for thread local values in thread");
1773212000-04-12Fredrik Hübinette (Hubbe)  #ifdef PIKE_DEBUG if(tmp->swapped)
cc2e9f2003-09-24Martin Stjernholm  gc_mark_stack_external (tmp->state.frame_pointer, tmp->state.stack_pointer, tmp->state.evaluator_stack);
1773212000-04-12Fredrik Hübinette (Hubbe) #endif
d86cd71998-08-24Marcus Comstedt }
e413da2001-02-01Henrik Grubbström (Grubba) /*! @class Local *! *! Thread local variable storage. *! *! This class allows you to have variables which are separate for each *! thread that uses it. It has two methods: @[get()] and @[set()]. A value
c7b7dd2001-10-28Martin Nilsson  *! stored in an instance of @[Local] can only be retrieved by that
e413da2001-02-01Henrik Grubbström (Grubba)  *! same thread. *! *! @note *! This class is simulated when Pike is compiled without thread support, *! so it's always available. */
d4e6372001-02-06Henrik Grubbström (Grubba) /* FIXME: Why not use an init callback()? */
0319392001-02-06Per Hedbor void f_thread_local_create( INT32 args )
d86cd71998-08-24Marcus Comstedt { static INT32 thread_local_id = 0;
6b87882001-06-21Martin Stjernholm  ((struct thread_local *)CURRENT_STORAGE)->id =
0319392001-02-06Per Hedbor  thread_local_id++; pop_n_elems(args); push_int(0); }
d86cd71998-08-24Marcus Comstedt 
0319392001-02-06Per Hedbor PMOD_EXPORT void f_thread_local(INT32 args) {
d86cd71998-08-24Marcus Comstedt  struct object *loc = clone_object(thread_local_prog,0); pop_n_elems(args); push_object(loc); }
e413da2001-02-01Henrik Grubbström (Grubba) /*! @decl mixed get() *! *! Get the thread local value. *!
c7b7dd2001-10-28Martin Nilsson  *! This returns the value prevoiusly stored in the @[Local] object by
e413da2001-02-01Henrik Grubbström (Grubba)  *! the @[set()] method by this thread. *! *! @seealso *! @[set()] */
d86cd71998-08-24Marcus Comstedt void f_thread_local_get(INT32 args) { struct svalue key; struct mapping *m;
60d9872000-03-23Fredrik Hübinette (Hubbe)  key.u.integer = ((struct thread_local *)CURRENT_STORAGE)->id;
d86cd71998-08-24Marcus Comstedt  key.type = T_INT; key.subtype = NUMBER_NUMBER; pop_n_elems(args);
0431312003-02-15Henrik Grubbström (Grubba)  if(Pike_interpreter.thread_state != NULL && (m = Pike_interpreter.thread_state->thread_local) != NULL)
17f08c2000-07-06Fredrik Hübinette (Hubbe)  mapping_index_no_free(Pike_sp++, m, &key);
d86cd71998-08-24Marcus Comstedt  else { push_int(0);
17f08c2000-07-06Fredrik Hübinette (Hubbe)  Pike_sp[-1].subtype=NUMBER_UNDEFINED;
d86cd71998-08-24Marcus Comstedt  } }
e413da2001-02-01Henrik Grubbström (Grubba) /*! @decl mixed set(mixed value) *! *! Set the thread local value. *! *! This sets the value returned by the @[get] method. *! *! Calling this method does not affect the value returned by @[get()] when *! it's called by another thread (ie multiple values can be stored at the *! same time, but only one value per thread). *! *! @returns *! This function returns its argument. *! *! @note *! Note that the value set can only be retreived by the same thread. *! *! @seealso *! @[get()] */
d86cd71998-08-24Marcus Comstedt void f_thread_local_set(INT32 args) { struct svalue key; struct mapping *m;
60d9872000-03-23Fredrik Hübinette (Hubbe)  key.u.integer = ((struct thread_local *)CURRENT_STORAGE)->id;
d86cd71998-08-24Marcus Comstedt  key.type = T_INT; key.subtype = NUMBER_NUMBER; if(args>1) pop_n_elems(args-1); else if(args<1)
d4ecd72003-01-05Martin Nilsson  SIMPLE_TOO_FEW_ARGS_ERROR("Thread.Local.set", 1);
d86cd71998-08-24Marcus Comstedt 
1d456f2003-02-20Henrik Grubbström (Grubba)  if(Pike_interpreter.thread_state == NULL)
cd6f7e2000-12-01Martin Stjernholm  Pike_error("Trying to set Thread.Local without thread!\n");
d86cd71998-08-24Marcus Comstedt 
0431312003-02-15Henrik Grubbström (Grubba)  if((m = Pike_interpreter.thread_state->thread_local) == NULL) m = Pike_interpreter.thread_state->thread_local =
d86cd71998-08-24Marcus Comstedt  allocate_mapping(4);
17f08c2000-07-06Fredrik Hübinette (Hubbe)  mapping_insert(m, &key, &Pike_sp[-1]);
d86cd71998-08-24Marcus Comstedt }
f6d0171997-10-15Fredrik Hübinette (Hubbe) 
d9d6f02001-06-30Martin Stjernholm #ifdef PIKE_DEBUG void gc_check_thread_local (struct object *o) { /* Only used by with locate_references. */ if (Pike_in_gc == GC_PASS_LOCATE) { struct svalue key, *val; INT32 x; struct thread_state *s; key.u.integer = ((struct thread_local *)CURRENT_STORAGE)->id; key.type = T_INT; key.subtype = NUMBER_NUMBER;
f2c01e2003-01-08Martin Stjernholm  FOR_EACH_THREAD (s, {
d9d6f02001-06-30Martin Stjernholm  if (s->thread_local && (val = low_mapping_lookup(s->thread_local, &key)))
e1a35e2003-09-08Martin Stjernholm  debug_gc_check_svalues (val, 1,
d9d6f02001-06-30Martin Stjernholm  " as thread local value in Thread.Local object" " (indirect ref)");
f2c01e2003-01-08Martin Stjernholm  });
d9d6f02001-06-30Martin Stjernholm  } } #endif
e413da2001-02-01Henrik Grubbström (Grubba) /*! @endclass */
a9cdcf2001-02-06Henrik Grubbström (Grubba) /*! @endmodule */
64b7b62000-11-02Henrik Grubbström (Grubba) /* Thread farm code by Per * */ static struct farmer { struct farmer *neighbour; void *field; void (*harvest)(void *); THREAD_T me; COND_T harvest_moon; #ifdef HAVE_BROKEN_LINUX_THREAD_EUID int euid, egid; #endif /* HAVE_BROKEN_LINUX_THREAD_EUID */ } *farmers; static MUTEX_T rosie; static int _num_farmers, _num_idle_farmers; static TH_RETURN_TYPE farm(void *_a) { struct farmer *me = (struct farmer *)_a; #ifdef HAVE_BROKEN_LINUX_THREAD_EUID /* Work-around for Linux's pthreads not propagating the * effective uid & gid. */ if (!geteuid()) {
f663a02003-03-05Martin Stjernholm #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) /* The sete?id calls will clear the dumpable state that we might * have set with system.dumpable. */ int current = prctl(PR_GET_DUMPABLE); #endif
64b7b62000-11-02Henrik Grubbström (Grubba)  setegid(me->egid); seteuid(me->euid);
f663a02003-03-05Martin Stjernholm #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) if (prctl(PR_SET_DUMPABLE, current) == -1) Pike_fatal ("Didn't expect prctl to go wrong. errno=%d\n", errno); #endif
64b7b62000-11-02Henrik Grubbström (Grubba)  } #endif /* HAVE_BROKEN_LINUX_THREAD_EUID */ do {
5aad932002-08-15Marcus Comstedt /* if(farmers == me) Pike_fatal("Ouch!\n"); */
64b7b62000-11-02Henrik Grubbström (Grubba) /* fprintf(stderr, "farm_begin %p\n",me ); */ me->harvest( me->field ); /* fprintf(stderr, "farm_end %p\n", me); */ me->harvest = 0; mt_lock( &rosie ); if( ++_num_idle_farmers > 16 ) { --_num_idle_farmers; --_num_farmers; mt_unlock( &rosie ); free( me ); return 0; } me->neighbour = farmers; farmers = me; /* fprintf(stderr, "farm_wait %p\n", me); */ while(!me->harvest) co_wait( &me->harvest_moon, &rosie ); --_num_idle_farmers; mt_unlock( &rosie ); /* fprintf(stderr, "farm_endwait %p\n", me); */ } while(1); /* NOT_REACHED */ return 0;/* Keep the compiler happy. */ } int th_num_idle_farmers(void) { return _num_idle_farmers; } int th_num_farmers(void) { return _num_farmers; } static struct farmer *new_farmer(void (*fun)(void *), void *args) { struct farmer *me = malloc(sizeof(struct farmer)); if (!me) { /* Out of memory */
5aad932002-08-15Marcus Comstedt  Pike_fatal("new_farmer(): Out of memory!\n");
64b7b62000-11-02Henrik Grubbström (Grubba)  } dmalloc_accept_leak(me); _num_farmers++; me->neighbour = 0; me->field = args; me->harvest = fun; co_init( &me->harvest_moon ); #ifdef HAVE_BROKEN_LINUX_THREAD_EUID me->euid = geteuid(); me->egid = getegid(); #endif /* HAVE_BROKEN_LINUX_THREAD_EUID */ th_create_small(&me->me, farm, me); return me; } PMOD_EXPORT void th_farm(void (*fun)(void *), void *here) {
6e00e22003-11-13Martin Stjernholm #ifdef PIKE_DEBUG
5aad932002-08-15Marcus Comstedt  if(!fun) Pike_fatal("The farmers don't known how to handle empty fields\n");
6e00e22003-11-13Martin Stjernholm #endif
64b7b62000-11-02Henrik Grubbström (Grubba)  mt_lock( &rosie ); if(farmers) { struct farmer *f = farmers; farmers = f->neighbour; f->field = here; f->harvest = fun; mt_unlock( &rosie ); co_signal( &f->harvest_moon ); return; } mt_unlock( &rosie ); new_farmer( fun, here ); } /* * Glue code. */
a91ca01998-07-10Henrik Grubbström (Grubba) void low_th_init(void)
07513e1996-10-04Fredrik Hübinette (Hubbe) {
b867f92003-02-16Martin Stjernholm  THREADS_FPRINTF(0, (stderr, "Initializing threads.\n"));
fed8de1997-10-05Henrik Grubbström (Grubba) 
83b1842003-02-08Martin Stjernholm  really_low_th_init();
fed8de1997-10-05Henrik Grubbström (Grubba) 
12ae2f1997-09-05Henrik Grubbström (Grubba)  mt_init( & interpreter_lock);
bc21dc2001-11-01Martin Stjernholm  low_mt_lock_interpreter();
eac2091998-02-27Marcus Comstedt  mt_init( & thread_table_lock);
a91ca01998-07-10Henrik Grubbström (Grubba)  mt_init( & interleave_lock);
64b7b62000-11-02Henrik Grubbström (Grubba)  mt_init( & rosie);
ef1e931998-03-26Henrik Grubbström (Grubba)  co_init( & live_threads_change); co_init( & threads_disabled_change);
eac2091998-02-27Marcus Comstedt  thread_table_init();
864d3c1998-01-29Fredrik Hübinette (Hubbe) 
83b1842003-02-08Martin Stjernholm #ifdef POSIX_THREADS /* FIXME: Why set this only when POSIX_THREADS? /mast */
b32ef12000-04-19Martin Stjernholm  th_running = 1;
e4419e1997-02-06Fredrik Hübinette (Hubbe) #endif
a91ca01998-07-10Henrik Grubbström (Grubba) }
1d456f2003-02-20Henrik Grubbström (Grubba) static struct object *backend_thread_obj = NULL;
a91ca01998-07-10Henrik Grubbström (Grubba) void th_init(void) {
89fc4c2000-08-10Henrik Grubbström (Grubba)  ptrdiff_t mutex_key_offset;
a91ca01998-07-10Henrik Grubbström (Grubba) 
e4419e1997-02-06Fredrik Hübinette (Hubbe) #ifdef UNIX_THREADS
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  ADD_EFUN("thread_set_concurrency",f_thread_set_concurrency,tFunc(tInt,tVoid), OPT_SIDE_EFFECT);
e4419e1997-02-06Fredrik Hübinette (Hubbe) #endif
07513e1996-10-04Fredrik Hübinette (Hubbe) 
3f87be1999-12-14Martin Stjernholm  START_NEW_PROGRAM_ID(THREAD_MUTEX_KEY);
90e9781999-01-31Fredrik Hübinette (Hubbe)  mutex_key_offset = ADD_STORAGE(struct key_storage);
46d7bf1997-09-03Henrik Grubbström (Grubba)  /* This is needed to allow the gc to find the possible circular reference.
e413da2001-02-01Henrik Grubbström (Grubba)  * It also allows a thread to take over ownership of a key.
46d7bf1997-09-03Henrik Grubbström (Grubba)  */
1d456f2003-02-20Henrik Grubbström (Grubba)  PIKE_MAP_VARIABLE("_owner", mutex_key_offset + OFFSETOF(key_storage, owner_obj),
33887a2002-10-28Martin Stjernholm  tObjIs_THREAD_ID, T_OBJECT, 0); PIKE_MAP_VARIABLE("_mutex", mutex_key_offset + OFFSETOF(key_storage, mutex_obj), tObjIs_THREAD_MUTEX, T_OBJECT, ID_STATIC|ID_PRIVATE);
5988921996-10-05Fredrik Hübinette (Hubbe)  set_init_callback(init_mutex_key_obj);
07513e1996-10-04Fredrik Hübinette (Hubbe)  set_exit_callback(exit_mutex_key_obj);
bad5162000-06-23Fredrik Hübinette (Hubbe)  mutex_key=Pike_compiler->new_program;
3f87be1999-12-14Martin Stjernholm  add_ref(mutex_key); end_class("mutex_key", 0);
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  mutex_key->flags|=PROGRAM_DESTRUCT_IMMEDIATE;
07513e1996-10-04Fredrik Hübinette (Hubbe) 
3f87be1999-12-14Martin Stjernholm  START_NEW_PROGRAM_ID(THREAD_MUTEX);
52e4c61999-12-13Martin Stjernholm  ADD_STORAGE(struct mutex_storage);
3f87be1999-12-14Martin Stjernholm  ADD_FUNCTION("lock",f_mutex_lock, tFunc(tOr(tInt02,tVoid),tObjIs_THREAD_MUTEX_KEY),0); ADD_FUNCTION("trylock",f_mutex_trylock, tFunc(tOr(tInt02,tVoid),tObjIs_THREAD_MUTEX_KEY),0);
b9bba02001-08-08Leif Stensson  ADD_FUNCTION("current_locking_thread",f_mutex_locking_thread, tFunc(tNone,tObjIs_THREAD_ID), 0); ADD_FUNCTION("current_locking_key",f_mutex_locking_key, tFunc(tNone,tObjIs_THREAD_MUTEX_KEY), 0);
52e4c61999-12-13Martin Stjernholm  set_init_callback(init_mutex_obj); set_exit_callback(exit_mutex_obj); end_class("mutex", 0);
d85b4b2004-05-01Martin Stjernholm  START_NEW_PROGRAM_ID(THREAD_MUTEX_COMPAT_7_4); ADD_STORAGE(struct mutex_storage); ADD_FUNCTION("lock",f_mutex_lock, tFunc(tOr(tInt02,tVoid),tObjIs_THREAD_MUTEX_KEY),0); ADD_FUNCTION("trylock",f_mutex_trylock, tFunc(tOr(tInt02,tVoid),tObjIs_THREAD_MUTEX_KEY),0); ADD_FUNCTION("current_locking_thread",f_mutex_locking_thread, tFunc(tNone,tObjIs_THREAD_ID), 0); ADD_FUNCTION("current_locking_key",f_mutex_locking_key, tFunc(tNone,tObjIs_THREAD_MUTEX_KEY), 0); set_init_callback(init_mutex_obj); set_exit_callback(exit_mutex_obj_compat_7_4); end_class("mutex_compat_7_4", 0);
3f87be1999-12-14Martin Stjernholm  START_NEW_PROGRAM_ID(THREAD_CONDITION);
8349b42006-01-29Henrik Grubbström (Grubba)  ADD_STORAGE(struct pike_cond);
3f87be1999-12-14Martin Stjernholm  ADD_FUNCTION("wait",f_cond_wait,
4a59c02002-09-30Henrik Grubbström (Grubba)  tFunc(tObjIs_THREAD_MUTEX_KEY,tVoid),0);
b93e6e1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("signal",f_cond_signal,tFunc(tNone,tVoid),0); ADD_FUNCTION("broadcast",f_cond_broadcast,tFunc(tNone,tVoid),0);
07513e1996-10-04Fredrik Hübinette (Hubbe)  set_init_callback(init_cond_obj); set_exit_callback(exit_cond_obj);
b98eb31997-02-11Henrik Grubbström (Grubba)  end_class("condition", 0);
de413f1998-03-26Per Hedbor  { struct program *tmp;
3f87be1999-12-14Martin Stjernholm  START_NEW_PROGRAM_ID(THREAD_DISABLE_THREADS);
de413f1998-03-26Per Hedbor  set_init_callback(init_threads_disable); set_exit_callback(exit_threads_disable);
bad5162000-06-23Fredrik Hübinette (Hubbe)  tmp = Pike_compiler->new_program;
3f87be1999-12-14Martin Stjernholm  add_ref(tmp); end_class("threads_disabled", 0);
de413f1998-03-26Per Hedbor  tmp->flags|=PROGRAM_DESTRUCT_IMMEDIATE; add_global_program("_disable_threads", tmp);
56a6961998-04-05Fredrik Hübinette (Hubbe)  free_program(tmp);
de413f1998-03-26Per Hedbor  }
6d1a5e1996-10-07Fredrik Hübinette (Hubbe) 
3f87be1999-12-14Martin Stjernholm  START_NEW_PROGRAM_ID(THREAD_LOCAL);
90e9781999-01-31Fredrik Hübinette (Hubbe)  ADD_STORAGE(struct thread_local);
b93e6e1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("get",f_thread_local_get,tFunc(tNone,tMix),0);
b21d9e2000-11-06Martin Stjernholm  ADD_FUNCTION("set",f_thread_local_set,tFunc(tSetvar(1,tMix),tVar(1)),0);
d4e6372001-02-06Henrik Grubbström (Grubba)  ADD_FUNCTION("create", f_thread_local_create, tFunc(tVoid,tVoid), ID_STATIC);
d9d6f02001-06-30Martin Stjernholm #ifdef PIKE_DEBUG set_gc_check_callback(gc_check_thread_local); #endif
bad5162000-06-23Fredrik Hübinette (Hubbe)  thread_local_prog=Pike_compiler->new_program;
3f87be1999-12-14Martin Stjernholm  add_ref(thread_local_prog); end_class("thread_local", 0);
d4e6372001-02-06Henrik Grubbström (Grubba)  ADD_EFUN("thread_local", f_thread_local,
3f87be1999-12-14Martin Stjernholm  tFunc(tNone,tObjIs_THREAD_LOCAL),
d4e6372001-02-06Henrik Grubbström (Grubba)  OPT_EXTERNAL_DEPEND);
d86cd71998-08-24Marcus Comstedt 
3f87be1999-12-14Martin Stjernholm  START_NEW_PROGRAM_ID(THREAD_ID);
17f08c2000-07-06Fredrik Hübinette (Hubbe)  thread_storage_offset=ADD_STORAGE(struct thread_state);
0431312003-02-15Henrik Grubbström (Grubba)  PIKE_MAP_VARIABLE("result", OFFSETOF(thread_state, result), tMix, T_MIXED, 0); ADD_FUNCTION("create",f_thread_create, tFuncV(tNone,tMixed,tVoid), ID_STATIC);
b93e6e1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("backtrace",f_thread_backtrace,tFunc(tNone,tArray),0); ADD_FUNCTION("wait",f_thread_id_result,tFunc(tNone,tMix),0); ADD_FUNCTION("status",f_thread_id_status,tFunc(tNone,tInt),0);
9a0d422000-02-06Martin Stjernholm  ADD_FUNCTION("_sprintf",f_thread_id__sprintf,tFunc(tNone,tStr),0);
5e50ef2001-09-25Henrik Grubbström (Grubba)  ADD_FUNCTION("id_number",f_thread_id_id_number,tFunc(tNone,tInt),0);
9595b92004-08-12Henrik Grubbström (Grubba)  ADD_FUNCTION("interrupt", f_thread_id_interrupt, tFunc(tOr(tVoid,tStr), tVoid), 0);
286b312004-12-30Henrik Grubbström (Grubba)  ADD_FUNCTION("kill", f_thread_id_kill, tFunc(tNone, tVoid), 0);
a5bd2b2000-06-10Martin Stjernholm  set_gc_recurse_callback(thread_was_recursed);
d86cd71998-08-24Marcus Comstedt  set_gc_check_callback(thread_was_checked);
a7fef41997-09-03Per Hedbor  set_init_callback(init_thread_obj);
a2db6b1998-01-02Fredrik Hübinette (Hubbe)  set_exit_callback(exit_thread_obj);
bad5162000-06-23Fredrik Hübinette (Hubbe)  thread_id_prog=Pike_compiler->new_program;
95363a2000-04-11Fredrik Hübinette (Hubbe)  thread_id_prog->flags |= PROGRAM_NO_EXPLICIT_DESTRUCT;
3f87be1999-12-14Martin Stjernholm  add_ref(thread_id_prog); end_class("thread_id", 0);
0431312003-02-15Henrik Grubbström (Grubba)  /* Backward compat... */ add_global_program("thread_create", thread_id_prog);
3f87be1999-12-14Martin Stjernholm  ADD_EFUN("this_thread",f_this_thread, tFunc(tNone,tObjIs_THREAD_ID), OPT_EXTERNAL_DEPEND); ADD_EFUN("all_threads",f_all_threads, tFunc(tNone,tArr(tObjIs_THREAD_ID)), OPT_EXTERNAL_DEPEND);
52e4c61999-12-13Martin Stjernholm 
5d2f121998-08-27Henrik Grubbström (Grubba)  /* Some constants... */ add_integer_constant("THREAD_NOT_STARTED", THREAD_NOT_STARTED, 0); add_integer_constant("THREAD_RUNNING", THREAD_RUNNING, 0); add_integer_constant("THREAD_EXITED", THREAD_EXITED, 0);
1d456f2003-02-20Henrik Grubbström (Grubba)  backend_thread_obj = fast_clone_object(thread_id_prog); INIT_THREAD_STATE((struct thread_state *)(backend_thread_obj->storage +
b867f92003-02-16Martin Stjernholm  thread_storage_offset));
0431312003-02-15Henrik Grubbström (Grubba)  thread_table_insert(Pike_interpreter.thread_state);
6d1a5e1996-10-07Fredrik Hübinette (Hubbe) }
be478c1997-08-30Henrik Grubbström (Grubba) void th_cleanup(void)
6d1a5e1996-10-07Fredrik Hübinette (Hubbe) {
b32ef12000-04-19Martin Stjernholm  th_running = 0;
0431312003-02-15Henrik Grubbström (Grubba)  if (Pike_interpreter.thread_state) { thread_table_delete(Pike_interpreter.thread_state); Pike_interpreter.thread_state = NULL; }
1d456f2003-02-20Henrik Grubbström (Grubba)  if(backend_thread_obj)
c3b9952000-02-15Henrik Grubbström (Grubba)  {
1d456f2003-02-20Henrik Grubbström (Grubba)  destruct(backend_thread_obj); free_object(backend_thread_obj); backend_thread_obj = NULL;
56f4f42001-09-18Fredrik Hübinette (Hubbe)  destruct_objects_to_destruct_cb();
c3b9952000-02-15Henrik Grubbström (Grubba)  }
6d1a5e1996-10-07Fredrik Hübinette (Hubbe)  if(mutex_key) { free_program(mutex_key); mutex_key=0; }
d86cd71998-08-24Marcus Comstedt  if(thread_local_prog) { free_program(thread_local_prog); thread_local_prog=0; }
6d1a5e1996-10-07Fredrik Hübinette (Hubbe)  if(thread_id_prog) { free_program(thread_id_prog); thread_id_prog=0; }
58580c2001-11-12Martin Stjernholm  #ifdef PIKE_USE_OWN_ATFORK free_callback_list(&atfork_prepare_callback); free_callback_list(&atfork_parent_callback); free_callback_list(&atfork_child_callback); #endif
07513e1996-10-04Fredrik Hübinette (Hubbe) }
83b1842003-02-08Martin Stjernholm #endif /* !CONFIGURE_TEST */
07513e1996-10-04Fredrik Hübinette (Hubbe) #endif