3d42671999-10-09Fredrik Hübinette (Hubbe) #if constant(thread_create)
23f3361997-02-27Fredrik Hübinette (Hubbe) constant Mutex=__builtin.mutex; constant Condition=__builtin.condition;
609c0f1997-02-27Fredrik Hübinette (Hubbe) 
cb49dd1999-07-20Per Hedbor 
609c0f1997-02-27Fredrik Hübinette (Hubbe) class Fifo {
7f30a61997-02-27Fredrik Hübinette (Hubbe)  inherit Condition : r_cond;
d4bf591999-06-12Henrik Grubbström (Grubba)  inherit Condition : w_cond; inherit Mutex : lock;
609c0f1997-02-27Fredrik Hübinette (Hubbe) 
37d0891998-05-27Fredrik Hübinette (Hubbe)  array buffer;
87e3691997-02-27Fredrik Hübinette (Hubbe)  int ptr, num;
37d0891998-05-27Fredrik Hübinette (Hubbe)  int read_tres, write_tres;
609c0f1997-02-27Fredrik Hübinette (Hubbe) 
87e3691997-02-27Fredrik Hübinette (Hubbe)  int size() { return num; }
609c0f1997-02-27Fredrik Hübinette (Hubbe)  mixed read()
d4bf591999-06-12Henrik Grubbström (Grubba)  { mixed tmp; object key=lock::lock(); while(!num) r_cond::wait(key); tmp=buffer[ptr]; buffer[ptr++] = 0; // Throw away any references. ptr%=sizeof(buffer); if(read_tres < sizeof(buffer))
609c0f1997-02-27Fredrik Hübinette (Hubbe)  {
d4bf591999-06-12Henrik Grubbström (Grubba)  if(num-- == read_tres) w_cond::broadcast(); }else{ num--; w_cond::signal();
609c0f1997-02-27Fredrik Hübinette (Hubbe)  }
d4bf591999-06-12Henrik Grubbström (Grubba)  return tmp; }
37d0891998-05-27Fredrik Hübinette (Hubbe)  array read_array() { array ret; object key=lock::lock(); while(!num) r_cond::wait(key); if(num==1) { ret=buffer[ptr..ptr]; buffer[ptr++] = 0; // Throw away any references. ptr%=sizeof(buffer); num--; }else{ ret=buffer[ptr..]+buffer[..num-sizeof(ret)-1]; ptr=num=0; buffer=allocate(sizeof(buffer)); // Throw away any references. }
dc731d1999-06-19Fredrik Hübinette (Hubbe)  w_cond::broadcast();
37d0891998-05-27Fredrik Hübinette (Hubbe)  return ret; }
609c0f1997-02-27Fredrik Hübinette (Hubbe)  void write(mixed v)
d4bf591999-06-12Henrik Grubbström (Grubba)  { object key=lock::lock(); while(num == sizeof(buffer)) w_cond::wait(key); buffer[(ptr + num) % sizeof(buffer)]=v; if(write_tres)
609c0f1997-02-27Fredrik Hübinette (Hubbe)  {
d4bf591999-06-12Henrik Grubbström (Grubba)  if(num++ == write_tres) r_cond::broadcast(); }else{ num++; r_cond::signal();
609c0f1997-02-27Fredrik Hübinette (Hubbe)  }
d4bf591999-06-12Henrik Grubbström (Grubba)  }
37d0891998-05-27Fredrik Hübinette (Hubbe) 
8d49101998-01-21Fredrik Hübinette (Hubbe)  void create(int|void size)
d4bf591999-06-12Henrik Grubbström (Grubba)  { write_tres=0; buffer=allocate(read_tres=size || 128); }
609c0f1997-02-27Fredrik Hübinette (Hubbe) }; class Queue {
d4bf591999-06-12Henrik Grubbström (Grubba)  inherit Condition : r_cond; inherit Mutex : lock;
609c0f1997-02-27Fredrik Hübinette (Hubbe)  mixed *buffer=allocate(16); int r_ptr, w_ptr; int size() { return w_ptr - r_ptr; } mixed read()
d4bf591999-06-12Henrik Grubbström (Grubba)  { mixed tmp; object key=lock::lock(); while(!size()) r_cond::wait(key); tmp=buffer[r_ptr]; buffer[r_ptr++] = 0; // Throw away any references. key=0; return tmp; }
609c0f1997-02-27Fredrik Hübinette (Hubbe)  void write(mixed v)
d4bf591999-06-12Henrik Grubbström (Grubba)  { object key=lock::lock(); if(w_ptr >= sizeof(buffer))
609c0f1997-02-27Fredrik Hübinette (Hubbe)  {
d4bf591999-06-12Henrik Grubbström (Grubba)  buffer=buffer[r_ptr..]; buffer+=allocate(sizeof(buffer)+1); w_ptr-=r_ptr; r_ptr=0;
609c0f1997-02-27Fredrik Hübinette (Hubbe)  }
d4bf591999-06-12Henrik Grubbström (Grubba)  buffer[w_ptr]=v; w_ptr++; key=0; // Must free this one _before_ the signal... r_cond::signal(); }
cb49dd1999-07-20Per Hedbor } class Farm { class Result { int ready; mixed value; function done_cb; int status() { return ready; } mixed result() { return value; } mixed `()() { while(!ready) ft_cond->wait(); if( ready < 0 ) throw( value ); return value; } void set_done_cb( function to ) { if( ready ) to( value, ready<0 ); else done_cb = to; } void provide_error( mixed what ) { value = what; ready = -1; if( done_cb ) done_cb( what, 1 ); } void provide( mixed what ) { ready = 1; value = what; if( done_cb ) done_cb( what, 0 ); } }
f08d361999-08-04Per Hedbor  static class Handler
cb49dd1999-07-20Per Hedbor  { Condition cond = Condition(); array job; object thread; float total_time; int handled, max_time; static int ready; void handler() { array q; while( 1 ) { ready = 1; cond->wait(); if( q = job ) { mixed res, err; int st = gethrtime(); if( err = catch(res = q[1][0]( @q[1][1] )) && q[0]) q[0]->provide_error( err ); else if( q[0] ) q[0]->provide( res ); object lock = mutex->lock(); free_threads += ({ this_object() }); lock = 0; st = gethrtime()-st; total_time += st/1000.0; handled++; job = 0; if( st > max_time ) max_time = st; ft_cond->broadcast();
f08d361999-08-04Per Hedbor  } else { object lock = mutex->lock(); threads -= ({ this_object() }); free_threads -= ({ this_object() }); lock = 0; destruct(); return;
cb49dd1999-07-20Per Hedbor  } } } void run( array what, object|void resobj ) { while(!ready) sleep(0.1); job = ({ resobj, what }); cond->signal(); } string debug_status() { return ("Thread:\n" " Handled works: "+handled+"\n"+ (handled? " Average time: "+((int)(total_time / handled))+"ms\n" " Max time: "+sprintf("%2.2fms\n", max_time/1000.0):"")+ " Status: "+(job?"Working":"Idle" )+"\n"+ (job? (" "+ replace( describe_backtrace(thread->backtrace()), "\n", "\n ")):"") +"\n\n"); } void create() { thread = thread_create( handler ); } }
f08d361999-08-04Per Hedbor  static Mutex mutex = Mutex(); static Condition ft_cond = Condition(); static Queue job_queue = Queue();
cb49dd1999-07-20Per Hedbor  static array(Handler) threads = ({});
f08d361999-08-04Per Hedbor  static array(Handler) free_threads = ({}); static int max_num_threads = 20;
cb49dd1999-07-20Per Hedbor  static Handler aquire_thread() { object lock = mutex->lock(); while( !sizeof(free_threads) ) { if( sizeof(threads) < max_num_threads ) { threads += ({ Handler() }); free_threads += ({ threads[-1] }); } else { lock = 0; ft_cond->wait( ); mutex->lock(); } } object t = free_threads[0]; free_threads = free_threads[1..]; return t; }
f08d361999-08-04Per Hedbor  static void dispatcher()
cb49dd1999-07-20Per Hedbor  { while( array q = job_queue->read() ) aquire_thread()->run( q[1], q[0] ); }
f08d361999-08-04Per Hedbor  static class ValueAdjuster
cb49dd1999-07-20Per Hedbor  { object r, r2; mapping v; int i; void go(mixed vn, int err) { r->value[ i ] = vn; if( err ) r->provide_error( err ); if( !--v->num_left ) r->provide( r->value ); destruct(); } void create( object _1,object _2,int _3,mapping _4 ) { r = _1; r2 = _2; i=_3; v=_4; } } object run_multiple( array fun_args ) { Result r = Result(); // private result.. r->value = allocate( sizeof( fun_args ) ); mapping nl = ([ "num_left":sizeof( fun_args ) ]); for( int i=0; i<sizeof( fun_args ); i++ ) { Result r2 = Result(); r2->set_done_cb( ValueAdjuster( r, r2, i, nl )->go ); job_queue->write( ({ r2, fun_args[i] }) ); } return r; }
f08d361999-08-04Per Hedbor  void run_multiple_async( array fun_args ) { for( int i=0; i<sizeof( fun_args ); i++ ) job_queue->write( ({ 0, fun_args[i] }) ); } object run( function f, mixed ... args ) { object ro = Result(); job_queue->write( ({ 0, ({f, args }) }) ); return ro; }
cb49dd1999-07-20Per Hedbor  void run_async( function f, mixed ... args ) { job_queue->write( ({ 0, ({f, args }) }) ); } int set_max_num_threads( int to ) { int omnt = max_num_threads;
f08d361999-08-04Per Hedbor  if( to <= 0 ) error("Illegal argument 1 to set_max_num_threads," "num_threads must be > 0\n");
cb49dd1999-07-20Per Hedbor  max_num_threads = to;
f08d361999-08-04Per Hedbor  while( sizeof( threads ) > max_num_threads ) { object key = mutex->lock(); while( sizeof( free_threads ) ) free_threads[0]->cond->signal(); key = 0; if( sizeof( threads ) > max_num_threads) ft_cond->wait(); }
cb49dd1999-07-20Per Hedbor  ft_cond->broadcast( ); return omnt; } string debug_status() { string res = sprintf("Thread farm\n" " Max threads = %d\n" " Current threads = %d\n" " Working threads = %d\n" " Jobs in queue = %d\n\n", max_num_threads, sizeof(threads), (sizeof(threads)-sizeof(free_threads)), job_queue->size() ); foreach( threads, Handler t ) res += t->debug_status(); return res; } void create() { thread_create( dispatcher ); } }
3d42671999-10-09Fredrik Hübinette (Hubbe) #endif /* constant(thread_create) */