pike.git / lib / modules / Thread.pmod

version» Context lines:

pike.git/lib/modules/Thread.pmod:1:   #pike __REAL_VERSION__      #if constant(__builtin.thread_id)   constant Thread=__builtin.thread_id;    - optional constant MutexKey=__builtin.mutex_key; - optional constant Mutex=__builtin.mutex; - optional constant Condition=__builtin.condition; - optional constant _Disabled=__builtin.threads_disabled; - optional constant Local=__builtin.thread_local; + constant MutexKey=__builtin.mutex_key; + constant Mutex=__builtin.mutex; + constant Condition=__builtin.condition; + constant _Disabled=__builtin.threads_disabled; + constant Local=__builtin.thread_local;    - optional constant thread_create = predef::thread_create; - optional constant this_thread = predef::this_thread; - optional constant all_threads = predef::all_threads; - optional constant get_thread_quanta = predef::get_thread_quanta; - optional constant set_thread_quatna = predef::set_thread_quanta; + constant thread_create = predef::thread_create; + constant this_thread = predef::this_thread; + constant all_threads = predef::all_threads; + constant get_thread_quanta = predef::get_thread_quanta; + constant set_thread_quatna = predef::set_thread_quanta;      constant THREAD_NOT_STARTED = __builtin.THREAD_NOT_STARTED;   constant THREAD_RUNNING = __builtin.THREAD_RUNNING;   constant THREAD_EXITED = __builtin.THREAD_EXITED;         //! @[Fifo] implements a fixed length first-in, first-out queue.   //! A fifo is a queue of values and is often used as a stream of data   //! between two threads.   //!   //! @seealso   //! @[Queue]   //! - optional class Fifo { + class Fifo {    inherit Condition : r_cond;    inherit Condition : w_cond;    inherit Mutex : lock;       array buffer;    int ptr, num;    int read_tres, write_tres;       //! This function returns the number of elements currently in the fifo.    //!
pike.git/lib/modules/Thread.pmod:231: Inside #if constant(__builtin.thread_id)
  //! @[Queue] implements a queue, or a pipeline. The main difference   //! between @[Queue] and @[Fifo] is that @[Queue]   //! will never block in write(), only allocate more memory.   //!   //! @fixme   //! Ought to be made API-compatible with @[ADT.Queue].   //!   //! @seealso   //! @[Fifo], @[ADT.Queue]   //! - optional class Queue { + class Queue {    inherit Condition : r_cond;    inherit Mutex : lock;       array buffer=allocate(16);    int r_ptr, w_ptr;       //! This function returns the number of elements currently in the queue.    //!    //! @seealso    //! @[read()], @[write()]
pike.git/lib/modules/Thread.pmod:390: Inside #if constant(__builtin.thread_id)
   }       protected string _sprintf( int f )    {    return f=='O' && sprintf( "%O(%d)", this_program, size() );    }   }         //! A thread farm. - optional class Farm + class Farm   {    protected Mutex mutex = Mutex();    protected Condition ft_cond = Condition();    protected Queue job_queue = Queue();    protected object dispatcher_thread;    protected function(object, string:void) thread_name_cb;    protected string thread_name_prefix;       //! An asynchronous result. -  +  //! +  //! @fixme +  //! This class ought to be made @[Concurrent.Future]-compatible.    class Result    {    int ready;    mixed value;    function done_cb;       //! @returns    //! @int    //! @value 1    //! Returns @expr{1@} when the result is available.
pike.git/lib/modules/Thread.pmod:430: Inside #if constant(__builtin.thread_id)
      //! @returns    //! Returns the result if available, a backtrace on failure,    //! and @expr{0@} (zero) otherwise.    mixed result()    {    return value;    }       //! Wait for completion. -  mixed `()() +  protected mixed `()()    {    object key = mutex->lock();    while(!ready) ft_cond->wait(key);    key = 0;    if( ready < 0 ) throw( value );    return value;    }       //! Register a callback to be called when    //! the result is available.
pike.git/lib/modules/Thread.pmod:493: Inside #if constant(__builtin.thread_id)
   switch( f )    {    case 't':    return "Thread.Farm().Result";    case 'O':    return sprintf( "%t(%d %O)", this, ready, value );    }    }    }    +  protected void report_errors(mixed err, int is_err) +  { +  if (!is_err) return; +  master()->handle_error(err); +  } +  +  //! A wrapper for an asynchronous result. +  //! +  //! @note +  //! This wrapper is used to detect when the +  //! user discards the values returned from +  //! @[run()] or @[run_multiple()], so that +  //! any errors thrown aren't lost. +  protected class ResultWrapper(Result ro) +  { +  protected int(0..1) value_fetched; +  int `ready() { return ro->ready; } +  mixed `value() { +  value_fetched = 1; +  return ro->value; +  } +  function `done_cb() { return ro->done_cb; } +  void `done_cb=(function cb) { +  if (cb) value_fetched = 1; +  ro->done_cb = cb; +  } +  +  //! @returns +  //! @int +  //! @value 1 +  //! Returns @expr{1@} when the result is available. +  //! @value 0 +  //! Returns @expr{0@} (zero) when the result hasn't +  //! arrived yet. +  //! @value -1 +  //! Returns negative on failure. +  //! @endint +  function(:int) `status() { return ro->status; } +  +  //! @returns +  //! Returns the result if available, a backtrace on failure, +  //! and @expr{0@} (zero) otherwise. +  function(:mixed) `result() { return ro->result; } +  +  //! Wait for completion. +  protected mixed `()() +  { +  return ro(); +  } +  +  //! Register a callback to be called when +  //! the result is available. +  //! +  //! @param to +  //! Callback to be called. The first +  //! argument to the callback will be +  //! the result or the failure backtrace, +  //! and the second @expr{0@} (zero) on +  //! success, and @expr{1@} on failure. +  void set_done_cb(function cb) { +  if (cb) value_fetched = 1; +  ro->set_done_cb(cb); +  } +  +  //! Register a failure. +  //! +  //! @param what +  //! The corresponding backtrace. +  function(mixed:void) `provide_error() { return ro->provide_error; } +  +  //! Register a completed result. +  //! +  //! @param what +  //! The result to register. +  function(mixed:void) `provide() { return ro->provide; } +  +  protected void _destruct() +  { +  if (ro && !value_fetched && !ro->done_cb) { +  // Make sure that any errors aren't lost. +  ro->done_cb = report_errors; +  if (ro->ready < 0) { +  report_errors(ro->value, 1); +  } +  } +  } +  +  protected string _sprintf( int f ) +  { +  switch( f ) +  { +  case 't': +  return "Thread.Farm().ResultWrapper"; +  case 'O': +  return sprintf("%t(%O)", this, ro); +  } +  } +  } +     //! A worker thread.    protected class Handler    {    Mutex job_mutex = Mutex();    Condition cond = Condition();    array(object|array(function|array)) job;    object thread;       float total_time;    int handled, max_time;
pike.git/lib/modules/Thread.pmod:683: Inside #if constant(__builtin.thread_id)
   //! If any of the functions in @[fun_args] throws    //! and error, all of the accumulated results    //! (if any) will be dropped from the result, and    //! the first backtrace be provided.    //!    //! @seealso    //! @[run_multiple_async()]    Result run_multiple( array(array(function|array)) fun_args )    {    Result r = Result(); // private result.. +  ResultWrapper rw = ResultWrapper(r);    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; +  return rw;    }          //! Register multiple jobs where the return values    //! are to be ignored.    //!    //! @param fun_args    //! An array of arrays where the first element    //! is a function to call, and the second is    //! a corresponding array of arguments.
pike.git/lib/modules/Thread.pmod:738: Inside #if constant(__builtin.thread_id)
   //! @note    //! In Pike 7.8 and earlier this function    //! was broken and returned a @[Result]    //! object that wasn't connected to the job.    //!    //! @seealso    //! @[run_async()]    Result run( function f, mixed ... args )    {    Result ro = Result(); +  ResultWrapper rw = ResultWrapper(ro);    job_queue->write( ({ ro, ({f, args }) }) ); -  return ro; +  return rw;    }       //! Register a job for the thread farm    //! where the return value from @[f] is    //! ignored.    //!    //! @param f    //! Function to call with @@@[args] to    //! perform the job.    //!
pike.git/lib/modules/Thread.pmod:853: Inside #if constant(__builtin.thread_id)
   dispatcher_thread = thread_create( dispatcher );    }   }      //! When this key is destroyed, the corresponding resource counter   //! will be decremented.   //!   //! @seealso   //! @[ResourceCount], @[MutexKey]   //! - optional class ResourceCountKey { + class ResourceCountKey {       private inherit __builtin.DestructImmediate;       /*semi*/private ResourceCount parent;    -  /*semi*/private void create(ResourceCount _parent) { +  protected void create(ResourceCount _parent) +  {    parent = _parent;    }    -  /*semi*/private void _destruct() { +  protected void _destruct() +  {    MutexKey key = parent->_mutex->lock();    --parent->_count;    parent->_cond->signal();    }   }      //! Implements an inverted-semaphore-like resource   //! counter. A thread can poll or perform a blocking wait for the   //! resource-count to drop below a certain @ref{level@}.   //!   //! @seealso   //! @[ResourceCountKey], @[Condition], @[Mutex] - optional class ResourceCount { + class ResourceCount {    /*semi*/final int _count;    /*semi*/final Condition _cond = Condition();    /*semi*/final Mutex _mutex = Mutex();       //! @param level    //! The maximum level that is considered drained.    //!    //! @returns    //! True if the resource counter drops to equal or below @ref{level@}.    /*semi*/final int(0..1) drained(void|int level) {
pike.git/lib/modules/Thread.pmod:909: Inside #if constant(__builtin.thread_id)
      //! Increments the resource-counter.    //! @returns    //! A @[ResourceCountKey] to decrement the resource-counter again.    /*semi*/final ResourceCountKey acquire() {    MutexKey key = _mutex->lock();    _count++;    return ResourceCountKey(this);    }    -  /*semi*/private string _sprintf(int type) { +  protected string _sprintf(int type) +  {    string res = UNDEFINED;    switch(type) {    case 'O':    res = sprintf("Count: %d", _count);    break;    case 'd':    res = sprintf("%d", _count);    break;    }    return res;    }   }      #else /* !constant(thread_create) */      // Simulations of some of the classes for nonthreaded use.      /* Fallback implementation of Thread.Local */ - optional class Local + class Local   {    protected mixed data;    mixed get() {return data;}    mixed set (mixed val) {return data = val;}   }      /* Fallback implementation of Thread.MutexKey */ - optional class MutexKey (protected function(:void) dec_locks) + class MutexKey (protected function(:void) dec_locks)   { -  +  inherit Builtin.DestructImmediate; +     int `!()    {    // Should be destructed when the mutex is, but we can't pull that    // off. Try to simulate it as well as possible.    if (dec_locks) return 0;    destruct (this);    return 1;    }       protected void _destruct()    {    if (dec_locks) dec_locks();    }   }      /* Fallback implementation of Thread.Mutex */ - optional class Mutex + class Mutex   {    protected int locks = 0;    protected void dec_locks() {locks--;}       MutexKey lock (int|void type)    {    switch (type) {    default:    error ("Unknown mutex locking style: %d\n", type);    case 0:
pike.git/lib/modules/Thread.pmod:998:    case 1:    case 2:    }    if (locks) return 0;    locks++;    return MutexKey (dec_locks);    }   }      // Fallback implementation of Thread.Fifo. - optional class Fifo + class Fifo   {    array buffer;    int ptr, num;    int read_tres, write_tres;       int size() { return num; }       mixed read()    {    if (!num) error ("Deadlock detected - fifo empty.\n");
pike.git/lib/modules/Thread.pmod:1083:    }       protected string _sprintf( int f )    {    return f=='O' && sprintf( "%O(%d / %d)", this_program,    size(), read_tres );    }   }      // Fallback implementation of Thread.Queue. - optional class Queue + class Queue   {    array buffer=allocate(16);    int r_ptr, w_ptr;       int size() { return w_ptr - r_ptr; }       mixed read()    {    if (w_ptr == r_ptr) error ("Deadlock detected - queue empty.\n");    return try_read();