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 unique_id()98 int32_t unique_id() { return unique_id_; } 99 100 void Start(); 101 void Step(); GetState()102 int GetState() const { return state_; } HasError()103 bool HasError() const { return (GetState() == STATE_ERROR); } Blocked()104 bool Blocked() const { return blocked_; } IsDone()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 timeout_time()113 int64_t timeout_time() const { return timeout_time_; } timeout_seconds()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