Home | History | Annotate | Download | only in base
      1 /*
      2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #ifndef WEBRTC_BASE_TASK_H__
     12 #define WEBRTC_BASE_TASK_H__
     13 
     14 #include <string>
     15 #include "webrtc/base/basictypes.h"
     16 #include "webrtc/base/scoped_ptr.h"
     17 #include "webrtc/base/sigslot.h"
     18 #include "webrtc/base/taskparent.h"
     19 
     20 /////////////////////////////////////////////////////////////////////
     21 //
     22 // TASK
     23 //
     24 /////////////////////////////////////////////////////////////////////
     25 //
     26 // Task is a state machine infrastructure.  States are pushed forward by
     27 // pushing forwards a TaskRunner that holds on to all Tasks.  The purpose
     28 // of Task is threefold:
     29 //
     30 // (1) It manages ongoing work on the UI thread.  Multitasking without
     31 // threads, keeping it easy, keeping it real. :-)  It does this by
     32 // organizing a set of states for each task.  When you return from your
     33 // Process*() function, you return an integer for the next state.  You do
     34 // not go onto the next state yourself.  Every time you enter a state,
     35 // you check to see if you can do anything yet.  If not, you return
     36 // STATE_BLOCKED.  If you _could_ do anything, do not return
     37 // STATE_BLOCKED - even if you end up in the same state, return
     38 // STATE_mysamestate.  When you are done, return STATE_DONE and then the
     39 // task will self-delete sometime afterwards.
     40 //
     41 // (2) It helps you avoid all those reentrancy problems when you chain
     42 // too many triggers on one thread.  Basically if you want to tell a task
     43 // to process something for you, you feed your task some information and
     44 // then you Wake() it.  Don't tell it to process it right away.  If it
     45 // might be working on something as you send it information, you may want
     46 // to have a queue in the task.
     47 //
     48 // (3) Finally it helps manage parent tasks and children.  If a parent
     49 // task gets aborted, all the children tasks are too.  The nice thing
     50 // about this, for example, is if you have one parent task that
     51 // represents, say, and Xmpp connection, then you can spawn a whole bunch
     52 // of infinite lifetime child tasks and now worry about cleaning them up.
     53 //  When the parent task goes to STATE_DONE, the task engine will make
     54 // sure all those children are aborted and get deleted.
     55 //
     56 // Notice that Task has a few built-in states, e.g.,
     57 //
     58 // STATE_INIT - the task isn't running yet
     59 // STATE_START - the task is in its first state
     60 // STATE_RESPONSE - the task is in its second state
     61 // STATE_DONE - the task is done
     62 //
     63 // STATE_ERROR - indicates an error - we should audit the error code in
     64 // light of any usage of it to see if it should be improved.  When I
     65 // first put down the task stuff I didn't have a good sense of what was
     66 // needed for Abort and Error, and now the subclasses of Task will ground
     67 // the design in a stronger way.
     68 //
     69 // STATE_NEXT - the first undefined state number.  (like WM_USER) - you
     70 // can start defining more task states there.
     71 //
     72 // When you define more task states, just override Process(int state) and
     73 // add your own switch statement.  If you want to delegate to
     74 // Task::Process, you can effectively delegate to its switch statement.
     75 // No fancy method pointers or such - this is all just pretty low tech,
     76 // easy to debug, and fast.
     77 //
     78 // Also notice that Task has some primitive built-in timeout functionality.
     79 //
     80 // A timeout is defined as "the task stays in STATE_BLOCKED longer than
     81 // timeout_seconds_."
     82 //
     83 // Descendant classes can override this behavior by calling the
     84 // various protected methods to change the timeout behavior.  For
     85 // instance, a descendand might call SuspendTimeout() when it knows
     86 // that it isn't waiting for anything that might timeout, but isn't
     87 // yet in the STATE_DONE state.
     88 //
     89 
     90 namespace rtc {
     91 
     92 // Executes a sequence of steps
     93 class Task : public TaskParent {
     94  public:
     95   Task(TaskParent *parent);
     96   ~Task() override;
     97 
     98   int32_t unique_id() { return unique_id_; }
     99 
    100   void Start();
    101   void Step();
    102   int GetState() const { return state_; }
    103   bool HasError() const { return (GetState() == STATE_ERROR); }
    104   bool Blocked() const { return blocked_; }
    105   bool IsDone() const { return done_; }
    106   int64_t ElapsedTime();
    107 
    108   // Called from outside to stop task without any more callbacks
    109   void Abort(bool nowake = false);
    110 
    111   bool TimedOut();
    112 
    113   int64_t timeout_time() const { return timeout_time_; }
    114   int timeout_seconds() const { return timeout_seconds_; }
    115   void set_timeout_seconds(int timeout_seconds);
    116 
    117   sigslot::signal0<> SignalTimeout;
    118 
    119   // Called inside the task to signal that the task may be unblocked
    120   void Wake();
    121 
    122  protected:
    123 
    124   enum {
    125     STATE_BLOCKED = -1,
    126     STATE_INIT = 0,
    127     STATE_START = 1,
    128     STATE_DONE = 2,
    129     STATE_ERROR = 3,
    130     STATE_RESPONSE = 4,
    131     STATE_NEXT = 5,  // Subclasses which need more states start here and higher
    132   };
    133 
    134   // Called inside to advise that the task should wake and signal an error
    135   void Error();
    136 
    137   int64_t CurrentTime();
    138 
    139   virtual std::string GetStateName(int state) const;
    140   virtual int Process(int state);
    141   virtual void Stop();
    142   virtual int ProcessStart() = 0;
    143   virtual int ProcessResponse();
    144 
    145   void ResetTimeout();
    146   void ClearTimeout();
    147 
    148   void SuspendTimeout();
    149   void ResumeTimeout();
    150 
    151  protected:
    152   virtual int OnTimeout();
    153 
    154  private:
    155   void Done();
    156 
    157   int state_;
    158   bool blocked_;
    159   bool done_;
    160   bool aborted_;
    161   bool busy_;
    162   bool error_;
    163   int64_t start_time_;
    164   int64_t timeout_time_;
    165   int timeout_seconds_;
    166   bool timeout_suspended_;
    167   int32_t unique_id_;
    168 
    169   static int32_t unique_id_seed_;
    170 };
    171 
    172 }  // namespace rtc
    173 
    174 #endif  // WEBRTC_BASE_TASK_H__
    175