07513e1996-10-04Fredrik Hübinette (Hubbe) #include "global.h"
3f87be1999-12-14Martin Stjernholm RCSID("$Id: threads.c,v 1.106 1999/12/14 19:49:51 mast Exp $");
a29e021996-10-15Fredrik Hübinette (Hubbe)  int num_threads = 1; int threads_disabled = 0; #ifdef _REENTRANT
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"
07513e1996-10-04Fredrik Hübinette (Hubbe) 
cd11fa1999-05-13Henrik Grubbström (Grubba) #include <errno.h>
ef1e931998-03-26Henrik Grubbström (Grubba) int live_threads = 0; COND_T live_threads_change; COND_T threads_disabled_change;
4908871998-08-10Fredrik Hübinette (Hubbe) size_t thread_stack_size=1024 * 1204;
ef1e931998-03-26Henrik Grubbström (Grubba) 
71ac9e1999-08-29Fredrik Hübinette (Hubbe) #ifndef HAVE_PTHREAD_ATFORK #include "callback.h" 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
dc7cc91998-01-14Fredrik Hübinette (Hubbe) #ifdef __NT__
cd67ac1999-05-11Fredrik Hübinette (Hubbe) int low_nt_create_thread(unsigned stack_size, unsigned (TH_STDCALL *fun)(void *), void *arg, unsigned *id) { HANDLE h=_beginthreadex(NULL, stack_size, fun, arg, 0, id); if(h) { CloseHandle(h); return 0; } else { return 1; } }
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
dc7cc91998-01-14Fredrik Hübinette (Hubbe) static int IsValidHandle(HANDLE h) { __try { HANDLE ret; if(DuplicateHandle(GetCurrentProcess(), h, GetCurrentProcess(), &ret,
b93e6e1999-06-19Fredrik Hübinette (Hubbe)  0,
dc7cc91998-01-14Fredrik Hübinette (Hubbe)  0, DUPLICATE_SAME_ACCESS)) { CloseHandle(ret); } } __except (1) { return 0; } return 1; }
cd67ac1999-05-11Fredrik Hübinette (Hubbe) HANDLE CheckValidHandle(HANDLE h)
dc7cc91998-01-14Fredrik Hübinette (Hubbe) {
cd67ac1999-05-11Fredrik Hübinette (Hubbe)  if(!IsValidHandle(h))
dc7cc91998-01-14Fredrik Hübinette (Hubbe)  fatal("Invalid handle!\n");
cd67ac1999-05-11Fredrik Hübinette (Hubbe)  return h;
dc7cc91998-01-14Fredrik Hübinette (Hubbe) } #endif #endif
e42eaf1998-01-02Fredrik Hübinette (Hubbe) #ifdef SIMULATE_COND_WITH_EVENT int co_wait(COND_T *c, MUTEX_T *m) { 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) fatal("Wait on event return prematurely!!\n"); #endif
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  return 0; } int co_signal(COND_T *c) { 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; } int co_broadcast(COND_T *c) { 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; } int co_destroy(COND_T *c) { 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
5740881998-01-01Fredrik Hübinette (Hubbe) #define THIS_THREAD ((struct thread_state *)fp->current_storage)
6d1a5e1996-10-07Fredrik Hübinette (Hubbe) struct object *thread_id;
a29e021996-10-15Fredrik Hübinette (Hubbe) static struct callback *threads_evaluator_callback=0;
5740881998-01-01Fredrik Hübinette (Hubbe) int thread_id_result_variable;
07513e1996-10-04Fredrik Hübinette (Hubbe) 
a91ca01998-07-10Henrik Grubbström (Grubba) MUTEX_T interpreter_lock, thread_table_lock, interleave_lock;
07513e1996-10-04Fredrik Hübinette (Hubbe) struct program *mutex_key = 0;
6d1a5e1996-10-07Fredrik Hübinette (Hubbe) struct program *thread_id_prog = 0;
d86cd71998-08-24Marcus Comstedt struct program *thread_local_prog = 0;
97ffe41997-01-26Per Hedbor #ifdef POSIX_THREADS
07513e1996-10-04Fredrik Hübinette (Hubbe) pthread_attr_t pattr;
864d3c1998-01-29Fredrik Hübinette (Hubbe) pthread_attr_t small_pattr;
97ffe41997-01-26Per Hedbor #endif
9b92d31999-01-31Fredrik Hübinette (Hubbe) int thread_storage_offset;
07513e1996-10-04Fredrik Hübinette (Hubbe) 
6d1a5e1996-10-07Fredrik Hübinette (Hubbe) struct thread_starter { struct object *id; struct array *args; };
d86cd71998-08-24Marcus Comstedt struct thread_local { INT32 id; };
a91ca01998-07-10Henrik Grubbström (Grubba) static volatile IMUTEX_T *interleave_list = NULL;
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)  if (thread_id) {
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; } 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) 
f328f11998-07-17Henrik Grubbström (Grubba) void init_threads_disable(struct object *o) { low_init_threads_disable(); 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)); co_wait(&live_threads_change, &interpreter_lock);
16df701998-07-16Fredrik Hübinette (Hubbe)  }
f328f11998-07-17Henrik Grubbström (Grubba)  SWAP_IN_CURRENT_THREAD();
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, "exit_threads_disable(): Unlocking IM 0x%08p\n", im)); mt_unlock(&(im->lock)); im = im->next; } mt_unlock(&interleave_lock); THREADS_FPRINTF(0, (stderr, "_exit_threads_disable(): Wake up!\n"));
2202fe1998-04-23Fredrik Hübinette (Hubbe)  co_broadcast(&threads_disabled_change);
40e9491998-07-05Henrik Grubbström (Grubba)  }
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
40e9491998-07-05Henrik Grubbström (Grubba)  } else { 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, "init_interleave_mutex(): Locking IM 0x%08p\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 */ #define THREAD_TABLE_SIZE 127 /* Totally arbitrary prime */ static struct thread_state *thread_table_chains[THREAD_TABLE_SIZE];
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 static void dumpmem(char *desc, void *x, int size) { int e; unsigned char *tmp=(unsigned char *)x; fprintf(stderr,"%s: ",desc); for(e=0;e<size;e++) fprintf(stderr,"%02x",tmp[e]); fprintf(stderr,"\n"); } #endif
eac2091998-02-27Marcus Comstedt void thread_table_insert(struct object *o) {
9b92d31999-01-31Fredrik Hübinette (Hubbe)  struct thread_state *s = OBJ2THREAD(o);
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) 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) fatal("Registring thread twice!\n"); else fatal("Forgot to unregister thread!\n"); }
26cd941999-05-07Fredrik Hübinette (Hubbe) /* 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 ); 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 ); } void thread_table_delete(struct object *o) {
9b92d31999-01-31Fredrik Hübinette (Hubbe)  struct thread_state *s = OBJ2THREAD(o);
26cd941999-05-07Fredrik Hübinette (Hubbe) /* dumpmem("thread_table_delete",&s->id, sizeof(THREAD_T)); */
eac2091998-02-27Marcus Comstedt  mt_lock( & thread_table_lock ); if(s->hashlink != NULL) s->hashlink->backlink = s->backlink; *(s->backlink) = s->hashlink; mt_unlock( & thread_table_lock ); } struct thread_state *thread_state_for_id(THREAD_T tid) { unsigned INT32 h = thread_table_hash(&tid); 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) fatal("thread_table_hash failed miserably!\n"); #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) { /* Move the thread_state to the head of the chain, in case 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() */ } struct object *thread_for_id(THREAD_T tid) { 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. */ } void f_all_threads(INT32 args) { /* Return an unordered array containing all threads that was running at the time this function was invoked */ INT32 x; struct svalue *oldsp; struct thread_state *s; pop_n_elems(args); oldsp = sp; mt_lock( & thread_table_lock ); for(x=0; x<THREAD_TABLE_SIZE; x++) for(s=thread_table_chains[x]; s; s=s->hashlink) {
26cd941999-05-07Fredrik Hübinette (Hubbe)  struct object *o = THREADSTATE2OBJ(s);
d6ac731998-04-20Henrik Grubbström (Grubba)  ref_push_object(o);
eac2091998-02-27Marcus Comstedt  } mt_unlock( & thread_table_lock ); f_aggregate(sp-oldsp); }
9ef9a31996-11-16Fredrik Hübinette (Hubbe) static void check_threads(struct callback *cb, void *arg, void * arg2)
a29e021996-10-15Fredrik Hübinette (Hubbe) {
0a861b1997-09-17Fredrik Hübinette (Hubbe)  static int div_; if(div_++ & 255) return;
26cd941999-05-07Fredrik Hübinette (Hubbe) #ifdef DEBUG if(thread_for_id(th_self()) != thread_id) fatal("thread_for_id() (or thread_id) failed!\n") #endif
de413f1998-03-26Per Hedbor  THREADS_ALLOW(); /* Allow other threads to run */ THREADS_DISALLOW();
26cd941999-05-07Fredrik Hübinette (Hubbe)  #ifdef DEBUG if(thread_for_id(th_self()) != thread_id) fatal("thread_for_id() (or thread_id) failed!\n") #endif
a29e021996-10-15Fredrik Hübinette (Hubbe) }
26cd941999-05-07Fredrik Hübinette (Hubbe) 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;
07513e1996-10-04Fredrik Hübinette (Hubbe)  JMP_BUF back;
725ba91996-10-12Fredrik Hübinette (Hubbe)  INT32 tmp;
b1b51f1996-10-11Fredrik Hübinette (Hubbe) 
a91ca01998-07-10Henrik Grubbström (Grubba)  THREADS_FPRINTF(0, (stderr,"THREADS_DISALLOW() Thread %08x created...\n", (unsigned int)arg.id));
fe76ce1997-09-08Fredrik Hübinette (Hubbe) 
9c6f7d1997-04-15Fredrik Hübinette (Hubbe)  if((tmp=mt_lock( & interpreter_lock)))
cd67ac1999-05-11Fredrik Hübinette (Hubbe)  fatal("Failed to lock interpreter, return value=%d, errno=%d\n",tmp, #ifdef __NT__ GetLastError() #else errno #endif );
07513e1996-10-04Fredrik Hübinette (Hubbe)  init_interpreter();
6d1a5e1996-10-07Fredrik Hübinette (Hubbe)  thread_id=arg.id;
9b92d31999-01-31Fredrik Hübinette (Hubbe)  SWAP_OUT_THREAD(OBJ2THREAD(thread_id)); /* Init struct */ OBJ2THREAD(thread_id)->swapped=0;
f0cd4c1999-03-21Henrik Grubbström (Grubba)  stack_top=((char *)&data)+ (thread_stack_size-16384) * STACK_DIRECTION; recoveries = NULL;
26cd941999-05-07Fredrik Hübinette (Hubbe) #if defined(PIKE_DEBUG) if(d_flag) {
f469831999-05-08Henrik Grubbström (Grubba)  THREAD_T self = th_self(); if( thread_id && !th_equal( OBJ2THREAD(thread_id)->id, self) ) fatal("Current thread is wrong. %x %x\n", OBJ2THREAD(thread_id)->id, self);
26cd941999-05-07Fredrik Hübinette (Hubbe)  if(thread_for_id(th_self()) != thread_id)
f469831999-05-08Henrik Grubbström (Grubba)  fatal("thread_for_id() (or thread_id) failed in new_thread_func! " "%p != %p\n", thread_for_id(self), thread_id); }
26cd941999-05-07Fredrik Hübinette (Hubbe) #endif
78112c1998-04-13Henrik Grubbström (Grubba) #ifdef THREAD_TRACE { t_flag = default_t_flag; } #endif /* THREAD_TRACE */
07513e1996-10-04Fredrik Hübinette (Hubbe) 
a91ca01998-07-10Henrik Grubbström (Grubba)  THREADS_FPRINTF(0, (stderr,"THREAD %08x INITED\n",(unsigned int)thread_id));
07513e1996-10-04Fredrik Hübinette (Hubbe)  if(SETJMP(back)) {
61e9a01998-01-25Fredrik Hübinette (Hubbe)  if(throw_severity < THROW_EXIT) { ONERROR tmp; SET_ONERROR(tmp,exit_on_error,"Error in handle_error in master object!"); assign_svalue_no_free(sp++, & throw_value); APPLY_MASTER("handle_error", 1); pop_stack(); UNSET_ONERROR(tmp); } if(throw_severity == THROW_EXIT) {
d40e381999-10-14Henrik Grubbström (Grubba)  free((char *) data);
61e9a01998-01-25Fredrik Hübinette (Hubbe)  do_exit(throw_value.u.integer); }
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)  /* copy return value to the thread_id here */ object_low_set_index(thread_id, thread_id_result_variable, sp-1); pop_stack();
07513e1996-10-04Fredrik Hübinette (Hubbe)  }
9b92d31999-01-31Fredrik Hübinette (Hubbe)  if(OBJ2THREAD(thread_id)->thread_local != NULL) { free_mapping(OBJ2THREAD(thread_id)->thread_local); OBJ2THREAD(thread_id)->thread_local = NULL;
d86cd71998-08-24Marcus Comstedt  }
9b92d31999-01-31Fredrik Hübinette (Hubbe)  OBJ2THREAD(thread_id)->status=THREAD_EXITED; co_broadcast(& OBJ2THREAD(thread_id)->status_change);
5740881998-01-01Fredrik Hübinette (Hubbe) 
4bdad01997-09-01Per Hedbor  free((char *)data); /* Moved by per, to avoid some bugs.... */
07513e1996-10-04Fredrik Hübinette (Hubbe)  UNSETJMP(back);
a91ca01998-07-10Henrik Grubbström (Grubba)  THREADS_FPRINTF(0, (stderr,"THREADS_ALLOW() Thread %08x done\n", (unsigned int)thread_id));
b1b51f1996-10-11Fredrik Hübinette (Hubbe) 
eac2091998-02-27Marcus Comstedt  thread_table_delete(thread_id);
6d1a5e1996-10-07Fredrik Hübinette (Hubbe)  free_object(thread_id); thread_id=0;
07513e1996-10-04Fredrik Hübinette (Hubbe)  cleanup_interpret(); 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; }
6d1a5e1996-10-07Fredrik Hübinette (Hubbe)  mt_unlock(& interpreter_lock);
07513e1996-10-04Fredrik Hübinette (Hubbe)  th_exit(0);
9c8b2d1997-04-20Henrik Grubbström (Grubba)  /* NOT_REACHED, but removes a warning */ return(NULL);
07513e1996-10-04Fredrik Hübinette (Hubbe) }
97ffe41997-01-26Per Hedbor #ifdef UNIX_THREADS int num_lwps = 1; #endif
b1b51f1996-10-11Fredrik Hübinette (Hubbe) 
07513e1996-10-04Fredrik Hübinette (Hubbe) void f_thread_create(INT32 args) {
97ffe41997-01-26Per Hedbor  THREAD_T dummy;
b1b51f1996-10-11Fredrik Hübinette (Hubbe)  struct thread_starter *arg;
07513e1996-10-04Fredrik Hübinette (Hubbe)  int tmp;
d40e381999-10-14Henrik Grubbström (Grubba)  arg = ALLOC_STRUCT(thread_starter);
6d1a5e1996-10-07Fredrik Hübinette (Hubbe)  arg->args=aggregate_array(args);
e709751997-03-12Fredrik Hübinette (Hubbe)  arg->id=clone_object(thread_id_prog,0);
9b92d31999-01-31Fredrik Hübinette (Hubbe)  OBJ2THREAD(arg->id)->status=THREAD_RUNNING;
b2a0fb1997-02-06Henrik Grubbström (Grubba) 
4743f81999-06-02Fredrik Hübinette (Hubbe)  do {
d40e381999-10-14Henrik Grubbström (Grubba)  tmp = th_create(& OBJ2THREAD(arg->id)->id, new_thread_func, arg);
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++;
eac2091998-02-27Marcus Comstedt  thread_table_insert(arg->id);
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)  }
d6ac731998-04-20Henrik Grubbström (Grubba)  ref_push_object(arg->id);
a91ca01998-07-10Henrik Grubbström (Grubba)  THREADS_FPRINTF(0, (stderr, "THREAD_CREATE -> t:%08x\n", (unsigned int)arg->id));
6d1a5e1996-10-07Fredrik Hübinette (Hubbe)  } else { free_object(arg->id); free_array(arg->args); free((char *)arg);
70d5f81998-03-25Henrik Grubbström (Grubba)  error("Failed to create thread (errno = %d).\n",tmp);
6d1a5e1996-10-07Fredrik Hübinette (Hubbe)  } }
1e4a641997-09-03Martin Stjernholm #ifdef UNIX_THREADS
97ffe41997-01-26Per Hedbor void f_thread_set_concurrency(INT32 args) { int c=1; if(args) c=sp[-args].u.integer; else error("No argument to thread_set_concurrency(int concurrency);\n"); 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 
6d1a5e1996-10-07Fredrik Hübinette (Hubbe) void f_this_thread(INT32 args) { pop_n_elems(args);
d6ac731998-04-20Henrik Grubbström (Grubba)  ref_push_object(thread_id);
07513e1996-10-04Fredrik Hübinette (Hubbe) }
5988921996-10-05Fredrik Hübinette (Hubbe) #define THIS_MUTEX ((struct mutex_storage *)(fp->current_storage)) /* 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; }; struct key_storage { struct mutex_storage *mut;
09dceb1997-09-01Per Hedbor  struct object *owner;
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)  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) 
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: bad_arg_error("mutex->lock", sp-args, args, 2, "int(0..2)", sp+1-args, "Unknown mutex locking style: %d\n",type); case 0: case 2: if(m->key && OB2KEY(m->key)->owner == thread_id) { THREADS_FPRINTF(0, (stderr, "Recursive LOCK k:%08x, m:%08x(%08x), t:%08x\n", (unsigned int)OB2KEY(m->key), (unsigned int)m, (unsigned int)OB2KEY(m->key)->mut, (unsigned int) thread_id)); if(type==0) error("Recursive mutex locks!\n"); pop_n_elems(args); push_int(0); } case 1: break; }
46d7bf1997-09-03Henrik Grubbström (Grubba)  /* Needs to be cloned here, since create() * might use threads. */
65df5c1997-09-01Per Hedbor  o=clone_object(mutex_key,0);
4bdad01997-09-01Per Hedbor 
26cd941999-05-07Fredrik Hübinette (Hubbe)  DO_IF_DEBUG( if(thread_for_id(th_self()) != thread_id) fatal("thread_for_id() (or thread_id) failed! %p != %p\n",thread_for_id(th_self()),thread_id) ; )
0a861b1997-09-17Fredrik Hübinette (Hubbe)  if(m->key)
fe76ce1997-09-08Fredrik Hübinette (Hubbe)  {
adb19b1999-06-30Fredrik Hübinette (Hubbe)  if(threads_disabled) { free_object(o); error("Cannot wait for mutexes when threads are disabled!\n"); }
b504ed1997-09-21Fredrik Hübinette (Hubbe)  SWAP_OUT_CURRENT_THREAD(); do
0a861b1997-09-17Fredrik Hübinette (Hubbe)  {
a91ca01998-07-10Henrik Grubbström (Grubba)  THREADS_FPRINTF(1, (stderr,"WAITING TO LOCK m:%08x\n",(unsigned int)m));
b504ed1997-09-21Fredrik Hübinette (Hubbe)  co_wait(& m->condition, & interpreter_lock); }while(m->key); SWAP_IN_CURRENT_THREAD();
fe76ce1997-09-08Fredrik Hübinette (Hubbe)  }
5988921996-10-05Fredrik Hübinette (Hubbe)  m->key=o;
46d7bf1997-09-03Henrik Grubbström (Grubba)  OB2KEY(o)->mut=m;
fe76ce1997-09-08Fredrik Hübinette (Hubbe) 
26cd941999-05-07Fredrik Hübinette (Hubbe)  DO_IF_DEBUG( if(thread_for_id(th_self()) != thread_id) fatal("thread_for_id() (or thread_id) failed! %p != %p\n",thread_for_id(th_self()),thread_id) ; )
a91ca01998-07-10Henrik Grubbström (Grubba)  THREADS_FPRINTF(1, (stderr, "LOCK k:%08x, m:%08x(%08x), t:%08x\n", (unsigned int)OB2KEY(o), (unsigned int)m, (unsigned int)OB2KEY(m->key)->mut, (unsigned int)thread_id));
65d3c31997-09-08Fredrik Hübinette (Hubbe)  pop_n_elems(args);
07513e1996-10-04Fredrik Hübinette (Hubbe)  push_object(o); } void f_mutex_trylock(INT32 args) {
5988921996-10-05Fredrik Hübinette (Hubbe)  struct mutex_storage *m; struct object *o;
a49ee61999-04-02Fredrik Hübinette (Hubbe)  int 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 get_all_args("mutex->lock",args,"%i",&type); switch(type)
65df5c1997-09-01Per Hedbor  {
a49ee61999-04-02Fredrik Hübinette (Hubbe)  default: bad_arg_error("mutex->trylock", sp-args, args, 2, "int(0..2)", sp+1-args, "Unknown mutex locking style: %d\n",type); case 0: if(m->key && OB2KEY(m->key)->owner == thread_id) { error("Recursive mutex locks!\n"); } 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;
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); } }
5988921996-10-05Fredrik Hübinette (Hubbe) void init_mutex_obj(struct object *o) { co_init(& THIS_MUTEX->condition); THIS_MUTEX->key=0; }
07513e1996-10-04Fredrik Hübinette (Hubbe) 
5988921996-10-05Fredrik Hübinette (Hubbe) void exit_mutex_obj(struct object *o) {
a91ca01998-07-10Henrik Grubbström (Grubba)  THREADS_FPRINTF(1, (stderr, "DESTROYING MUTEX m:%08x\n", (unsigned int)THIS_MUTEX));
5988921996-10-05Fredrik Hübinette (Hubbe)  if(THIS_MUTEX->key) destruct(THIS_MUTEX->key);
88fe361997-09-04Per Hedbor  THIS_MUTEX->key=0;
5988921996-10-05Fredrik Hübinette (Hubbe)  co_destroy(& THIS_MUTEX->condition); } #define THIS_KEY ((struct key_storage *)(fp->current_storage)) void init_mutex_key_obj(struct object *o) {
a91ca01998-07-10Henrik Grubbström (Grubba)  THREADS_FPRINTF(1, (stderr, "KEY k:%08x, o:%08x\n", (unsigned int)THIS_KEY, (unsigned int)thread_id));
5988921996-10-05Fredrik Hübinette (Hubbe)  THIS_KEY->mut=0;
d6ac731998-04-20Henrik Grubbström (Grubba)  add_ref(THIS_KEY->owner=thread_id);
5988921996-10-05Fredrik Hübinette (Hubbe)  THIS_KEY->initialized=1; }
07513e1996-10-04Fredrik Hübinette (Hubbe)  void exit_mutex_key_obj(struct object *o) {
a91ca01998-07-10Henrik Grubbström (Grubba)  THREADS_FPRINTF(1, (stderr, "UNLOCK k:%08x m:(%08x) t:%08x o:%08x\n", (unsigned int)THIS_KEY, (unsigned int)THIS_KEY->mut, (unsigned int)thread_id, (unsigned int)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;
c113871997-09-15Henrik Grubbström (Grubba) 
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
03b1fe1997-09-06Per Hedbor  if(mut->key != o) 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) { free_object(THIS_KEY->owner); THIS_KEY->owner=0; }
5988921996-10-05Fredrik Hübinette (Hubbe)  THIS_KEY->mut=0; THIS_KEY->initialized=0;
c113871997-09-15Henrik Grubbström (Grubba)  co_signal(& mut->condition);
07513e1996-10-04Fredrik Hübinette (Hubbe)  } } #define THIS_COND ((COND_T *)(fp->current_storage)) void f_cond_wait(INT32 args) { COND_T *c;
5988921996-10-05Fredrik Hübinette (Hubbe)  struct object *key;
07513e1996-10-04Fredrik Hübinette (Hubbe)  if(args > 1) pop_n_elems(args - 1);
5988921996-10-05Fredrik Hübinette (Hubbe)  c=THIS_COND; if(args > 0)
07513e1996-10-04Fredrik Hübinette (Hubbe)  {
5988921996-10-05Fredrik Hübinette (Hubbe)  struct mutex_storage *mut; if(sp[-1].type != T_OBJECT)
07513e1996-10-04Fredrik Hübinette (Hubbe)  error("Bad argument 1 to condition->wait()\n");
5988921996-10-05Fredrik Hübinette (Hubbe)  key=sp[-1].u.object; if(key->prog != mutex_key) error("Bad argument 1 to condition->wait()\n"); mut=OB2KEY(key)->mut;
88fe361997-09-04Per Hedbor  if(!mut) error("Bad argument 1 to condition->wait()\n");
368d4a1997-09-03Per Hedbor 
adb19b1999-06-30Fredrik Hübinette (Hubbe)  if(threads_disabled) error("Cannot wait for conditions when threads are disabled!\n");
5988921996-10-05Fredrik Hübinette (Hubbe)  /* Unlock mutex */ mut->key=0; OB2KEY(key)->mut=0; co_signal(& mut->condition);
88fe361997-09-04Per Hedbor 
5988921996-10-05Fredrik Hübinette (Hubbe)  /* Wait and allow mutex operations */
fe76ce1997-09-08Fredrik Hübinette (Hubbe)  SWAP_OUT_CURRENT_THREAD(); co_wait(c, &interpreter_lock);
88fe361997-09-04Per Hedbor 
5988921996-10-05Fredrik Hübinette (Hubbe)  if(OB2KEY(key)->initialized) { /* Lock mutex */
fe76ce1997-09-08Fredrik Hübinette (Hubbe)  while(mut->key) co_wait(& mut->condition, &interpreter_lock);
5988921996-10-05Fredrik Hübinette (Hubbe)  mut->key=key; OB2KEY(key)->mut=mut; }
fe76ce1997-09-08Fredrik Hübinette (Hubbe)  SWAP_IN_CURRENT_THREAD();
07513e1996-10-04Fredrik Hübinette (Hubbe)  pop_stack();
5988921996-10-05Fredrik Hübinette (Hubbe)  } else {
fe76ce1997-09-08Fredrik Hübinette (Hubbe)  SWAP_OUT_CURRENT_THREAD(); co_wait(c, &interpreter_lock); SWAP_IN_CURRENT_THREAD();
07513e1996-10-04Fredrik Hübinette (Hubbe)  } } void f_cond_signal(INT32 args) { pop_n_elems(args); co_signal(THIS_COND); } void f_cond_broadcast(INT32 args) { pop_n_elems(args); co_broadcast(THIS_COND); } void init_cond_obj(struct object *o) { co_init(THIS_COND); } void exit_cond_obj(struct object *o) { co_destroy(THIS_COND); }
a7fef41997-09-03Per Hedbor void f_thread_backtrace(INT32 args) {
9b92d31999-01-31Fredrik Hübinette (Hubbe)  struct thread_state *foo = THIS_THREAD; struct thread_state *bar = OBJ2THREAD( thread_id );
a7fef41997-09-03Per Hedbor  struct svalue *osp = sp; pop_n_elems(args); if(foo->sp) { SWAP_OUT_THREAD(bar); SWAP_IN_THREAD(foo); sp=osp; f_backtrace(0); osp=sp; sp=foo->sp; SWAP_OUT_THREAD(foo); SWAP_IN_THREAD(bar); sp=osp; } else { push_int(0); f_allocate(1); } }
5740881998-01-01Fredrik Hübinette (Hubbe) void f_thread_id_status(INT32 args) { pop_n_elems(args); push_int(THIS_THREAD->status); } static void f_thread_id_result(INT32 args) { struct thread_state *th=THIS_THREAD; SWAP_OUT_CURRENT_THREAD(); while(th->status != THREAD_EXITED) co_wait(&th->status_change, &interpreter_lock); SWAP_IN_CURRENT_THREAD(); low_object_index_no_free(sp, fp->current_object, thread_id_result_variable); sp++; }
a7fef41997-09-03Per Hedbor void init_thread_obj(struct object *o) {
9b92d31999-01-31Fredrik Hübinette (Hubbe)  MEMSET(THIS_THREAD, 0, sizeof(struct thread_state));
5740881998-01-01Fredrik Hübinette (Hubbe)  THIS_THREAD->status=THREAD_NOT_STARTED; co_init(& THIS_THREAD->status_change);
d86cd71998-08-24Marcus Comstedt  THIS_THREAD->thread_local=NULL;
5740881998-01-01Fredrik Hübinette (Hubbe) } void exit_thread_obj(struct object *o) {
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);
a7fef41997-09-03Per Hedbor }
f6d0171997-10-15Fredrik Hübinette (Hubbe) static void thread_was_marked(struct object *o) {
9b92d31999-01-31Fredrik Hübinette (Hubbe)  struct thread_state *tmp=THIS_THREAD;
d86cd71998-08-24Marcus Comstedt  if(tmp->thread_local != NULL) gc_mark_mapping_as_referenced(tmp->thread_local);
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
f6d0171997-10-15Fredrik Hübinette (Hubbe)  if(tmp->swapped) {
4694111997-11-07Fredrik Hübinette (Hubbe)  debug_gc_xmark_svalues(tmp->evaluator_stack,tmp->sp-tmp->evaluator_stack-1,"idle thread stack");
f6d0171997-10-15Fredrik Hübinette (Hubbe)  } #endif
d86cd71998-08-24Marcus Comstedt } static void thread_was_checked(struct object *o) {
9b92d31999-01-31Fredrik Hübinette (Hubbe)  struct thread_state *tmp=THIS_THREAD;
d86cd71998-08-24Marcus Comstedt  if(tmp->thread_local != NULL) gc_check(tmp->thread_local); } void f_thread_local(INT32 args) { static INT32 thread_local_id = 0; struct object *loc = clone_object(thread_local_prog,0); ((struct thread_local *)loc->storage)->id = thread_local_id++; pop_n_elems(args); push_object(loc); } void f_thread_local_get(INT32 args) { struct svalue key; struct mapping *m; key.u.integer = ((struct thread_local *)fp->current_storage)->id; key.type = T_INT; key.subtype = NUMBER_NUMBER; pop_n_elems(args); if(thread_id != NULL &&
9b92d31999-01-31Fredrik Hübinette (Hubbe)  (m = OBJ2THREAD(thread_id)->thread_local) != NULL)
d86cd71998-08-24Marcus Comstedt  mapping_index_no_free(sp++, m, &key); else { push_int(0); sp[-1].subtype=NUMBER_UNDEFINED; } } void f_thread_local_set(INT32 args) { struct svalue key; struct mapping *m; key.u.integer = ((struct thread_local *)fp->current_storage)->id; key.type = T_INT; key.subtype = NUMBER_NUMBER; if(args>1) pop_n_elems(args-1); else if(args<1) error("Too few arguments to thread_local->set()\n"); if(thread_id == NULL) error("Trying to set thread_local without thread!\n");
9b92d31999-01-31Fredrik Hübinette (Hubbe)  if((m = OBJ2THREAD(thread_id)->thread_local) == NULL) m = OBJ2THREAD(thread_id)->thread_local =
d86cd71998-08-24Marcus Comstedt  allocate_mapping(4); mapping_insert(m, &key, &sp[-1]); }
f6d0171997-10-15Fredrik Hübinette (Hubbe) 
a91ca01998-07-10Henrik Grubbström (Grubba) void low_th_init(void)
07513e1996-10-04Fredrik Hübinette (Hubbe) {
e4419e1997-02-06Fredrik Hübinette (Hubbe) #ifdef SGI_SPROC_THREADS #error /* Need to specify a filename */ us_cookie = usinit(""); #endif /* SGI_SPROC_THREADS */
a91ca01998-07-10Henrik Grubbström (Grubba)  THREADS_FPRINTF(0, (stderr, "THREADS_DISALLOW() Initializing threads.\n"));
fed8de1997-10-05Henrik Grubbström (Grubba)  #ifdef POSIX_THREADS #ifdef HAVE_PTHREAD_INIT pthread_init(); #endif /* HAVE_PTHREAD_INIT */ #endif /* POSIX_THREADS */
12ae2f1997-09-05Henrik Grubbström (Grubba)  mt_init( & interpreter_lock);
e4419e1997-02-06Fredrik Hübinette (Hubbe)  mt_lock( & interpreter_lock);
eac2091998-02-27Marcus Comstedt  mt_init( & thread_table_lock);
a91ca01998-07-10Henrik Grubbström (Grubba)  mt_init( & interleave_lock);
ef1e931998-03-26Henrik Grubbström (Grubba)  co_init( & live_threads_change); co_init( & threads_disabled_change);
eac2091998-02-27Marcus Comstedt  thread_table_init();
e4419e1997-02-06Fredrik Hübinette (Hubbe) #ifdef POSIX_THREADS pthread_attr_init(&pattr); #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
4908871998-08-10Fredrik Hübinette (Hubbe)  pthread_attr_setstacksize(&pattr, thread_stack_size);
e4419e1997-02-06Fredrik Hübinette (Hubbe) #endif pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED);
864d3c1998-01-29Fredrik Hübinette (Hubbe)  pthread_attr_init(&small_pattr); #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
26cd941999-05-07Fredrik Hübinette (Hubbe)  pthread_attr_setstacksize(&small_pattr, 4096*sizeof(char *));
864d3c1998-01-29Fredrik Hübinette (Hubbe) #endif pthread_attr_setdetachstate(&small_pattr, PTHREAD_CREATE_DETACHED);
e4419e1997-02-06Fredrik Hübinette (Hubbe) #endif
a91ca01998-07-10Henrik Grubbström (Grubba) } void th_init(void) { struct program *tmp; INT32 mutex_key_offset;
e4419e1997-02-06Fredrik Hübinette (Hubbe) #ifdef UNIX_THREADS
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(int:void) */ 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. * It also allows a process to take over ownership of a key. */ map_variable("_owner", "object", 0, mutex_key_offset + OFFSETOF(key_storage, owner), T_OBJECT);
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);
3f87be1999-12-14Martin Stjernholm  mutex_key=new_program; add_ref(mutex_key); end_class("mutex_key", 0);
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  mutex_key->flags|=PROGRAM_DESTRUCT_IMMEDIATE;
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
f839fa1997-02-28Fredrik Hübinette (Hubbe)  if(!mutex_key) fatal("Failed to initialize mutex_key program!\n");
e45f661998-03-20Fredrik Hübinette (Hubbe) #endif
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); /* function(int(0..2)|void:object(mutex_key)) */
3f87be1999-12-14Martin Stjernholm  ADD_FUNCTION("lock",f_mutex_lock, tFunc(tOr(tInt02,tVoid),tObjIs_THREAD_MUTEX_KEY),0);
52e4c61999-12-13Martin Stjernholm  /* function(int(0..2)|void:object(mutex_key)) */
3f87be1999-12-14Martin Stjernholm  ADD_FUNCTION("trylock",f_mutex_trylock, tFunc(tOr(tInt02,tVoid),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);
3f87be1999-12-14Martin Stjernholm  START_NEW_PROGRAM_ID(THREAD_CONDITION);
90e9781999-01-31Fredrik Hübinette (Hubbe)  ADD_STORAGE(COND_T);
52e4c61999-12-13Martin Stjernholm  /* function(void|object(mutex_key):void) */
3f87be1999-12-14Martin Stjernholm  ADD_FUNCTION("wait",f_cond_wait, tFunc(tOr(tVoid,tObjIs_THREAD_MUTEX_KEY),tVoid),0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(:void) */
b93e6e1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("signal",f_cond_signal,tFunc(tNone,tVoid),0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(:void) */
b93e6e1999-06-19Fredrik Hübinette (Hubbe)  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);
3f87be1999-12-14Martin Stjernholm  tmp = new_program; 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);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(:mixed) */
b93e6e1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("get",f_thread_local_get,tFunc(tNone,tMix),0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(mixed:mixed) */ ADD_FUNCTION("set",f_thread_local_set,tFunc(tMix,tMix),0);
3f87be1999-12-14Martin Stjernholm  thread_local_prog=new_program; add_ref(thread_local_prog); end_class("thread_local", 0);
d86cd71998-08-24Marcus Comstedt  if(!thread_local_prog) fatal("Failed to initialize thread_local program!\n");
3f87be1999-12-14Martin Stjernholm  /* function(:object(thread_local)) */ ADD_EFUN("thread_local",f_thread_local, tFunc(tNone,tObjIs_THREAD_LOCAL), OPT_SIDE_EFFECT);
d86cd71998-08-24Marcus Comstedt 
3f87be1999-12-14Martin Stjernholm  START_NEW_PROGRAM_ID(THREAD_ID);
9b92d31999-01-31Fredrik Hübinette (Hubbe)  thread_storage_offset=ADD_STORAGE(struct thread_state);
5740881998-01-01Fredrik Hübinette (Hubbe)  thread_id_result_variable=simple_add_variable("result","mixed",0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(:array) */
b93e6e1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("backtrace",f_thread_backtrace,tFunc(tNone,tArray),0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(:mixed) */
b93e6e1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("wait",f_thread_id_result,tFunc(tNone,tMix),0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(:int) */
b93e6e1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("status",f_thread_id_status,tFunc(tNone,tInt),0);
f6d0171997-10-15Fredrik Hübinette (Hubbe)  set_gc_mark_callback(thread_was_marked);
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);
3f87be1999-12-14Martin Stjernholm  thread_id_prog=new_program; add_ref(thread_id_prog); end_class("thread_id", 0); /* function(mixed ...:object(thread_id)) */ ADD_EFUN("thread_create",f_thread_create, tFuncV(tNone,tMixed,tObjIs_THREAD_ID), OPT_SIDE_EFFECT); /* function(:object(thread_id)) */ ADD_EFUN("this_thread",f_this_thread, tFunc(tNone,tObjIs_THREAD_ID), OPT_EXTERNAL_DEPEND); /* function(:array(object(thread_id))) */ 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);
f839fa1997-02-28Fredrik Hübinette (Hubbe)  if(!mutex_key) fatal("Failed to initialize thread program!\n");
6d1a5e1996-10-07Fredrik Hübinette (Hubbe) 
e709751997-03-12Fredrik Hübinette (Hubbe)  thread_id=clone_object(thread_id_prog,0);
9b92d31999-01-31Fredrik Hübinette (Hubbe)  SWAP_OUT_THREAD(OBJ2THREAD(thread_id)); /* Init struct */ OBJ2THREAD(thread_id)->swapped=0; OBJ2THREAD(thread_id)->id=th_self();
eac2091998-02-27Marcus Comstedt  thread_table_insert(thread_id);
6d1a5e1996-10-07Fredrik Hübinette (Hubbe) }
be478c1997-08-30Henrik Grubbström (Grubba) void th_cleanup(void)
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; } if(thread_id) { destruct(thread_id); free_object(thread_id); thread_id=0; }
07513e1996-10-04Fredrik Hübinette (Hubbe) }
063fe31998-03-10Per Hedbor /* Thread farm code by Per * */ static struct farmer { struct farmer *neighbour; void *field; void (*harvest)(void *); THREAD_T me; COND_T harvest_moon; } *farmers; static MUTEX_T rosie;
26cd941999-05-07Fredrik Hübinette (Hubbe) static TH_RETURN_TYPE farm(void *_a)
063fe31998-03-10Per Hedbor { struct farmer *me = (struct farmer *)_a; do { /* if(farmers == me) fatal("Ouch!\n"); */ /* fprintf(stderr, "farm_begin %p\n",me ); */ me->harvest( me->field ); /* fprintf(stderr, "farm_end %p\n", me); */ me->harvest = 0; mt_lock( &rosie ); me->neighbour = farmers; farmers = me; /* fprintf(stderr, "farm_wait %p\n", me); */ while(!me->harvest) co_wait( &me->harvest_moon, &rosie ); mt_unlock( &rosie ); /* fprintf(stderr, "farm_endwait %p\n", me); */ } while(1);
3d09c71998-05-01Henrik Grubbström (Grubba)  /* NOT_REACHED */ return NULL; /* Keep the compiler happy. */
063fe31998-03-10Per Hedbor }
22ca071998-04-08Fredrik Hübinette (Hubbe) int th_num_idle_farmers(void)
063fe31998-03-10Per Hedbor { int q = 0; struct farmer *f = farmers; while(f) { f = f->neighbour; q++; } return q; } static int _num_farmers; int th_num_farmers() { return _num_farmers; } static struct farmer *new_farmer(void (*fun)(void *), void *args) { struct farmer *me = malloc(sizeof(struct farmer));
beb0d61999-08-17Henrik Grubbström (Grubba)  if (!me) { /* Out of memory */ fatal("new_farmer(): Out of memory!\n"); } dmalloc_accept_leak(me);
063fe31998-03-10Per Hedbor  _num_farmers++; me->neighbour = 0; me->field = args; me->harvest = fun; co_init( &me->harvest_moon ); th_create_small(&me->me, farm, me);
a2a8801998-03-18Per Hedbor  return me;
063fe31998-03-10Per Hedbor } void th_farm(void (*fun)(void *), void *here) { if(!fun) fatal("The farmers don't known how to handle empty fields\n"); mt_lock( &rosie ); if(farmers) { struct farmer *f = farmers; farmers = f->neighbour; mt_unlock( &rosie ); f->field = here; f->harvest = fun; co_signal( &f->harvest_moon ); return; } mt_unlock( &rosie ); new_farmer( fun, here ); }
07513e1996-10-04Fredrik Hübinette (Hubbe) #endif