blob: 28702e49a7a280f41733e33d54d178d3d2534934 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
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
90namespace rtc {
91
92// Executes a sequence of steps
93class Task : public TaskParent {
94 public:
95 Task(TaskParent *parent);
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000096 ~Task() override;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000097
Peter Boström0c4e06b2015-10-07 12:23:21 +020098 int32_t unique_id() { return unique_id_; }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000099
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_; }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200106 int64_t ElapsedTime();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000107
108 // Called from outside to stop task without any more callbacks
109 void Abort(bool nowake = false);
110
111 bool TimedOut();
112
Peter Boström0c4e06b2015-10-07 12:23:21 +0200113 int64_t timeout_time() const { return timeout_time_; }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000114 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
Peter Boström0c4e06b2015-10-07 12:23:21 +0200137 int64_t CurrentTime();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000138
139 virtual std::string GetStateName(int state) const;
140 virtual int Process(int state);
141 virtual void Stop();
142 virtual int ProcessStart() = 0;
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000143 virtual int ProcessResponse();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000144
145 void ResetTimeout();
146 void ClearTimeout();
147
148 void SuspendTimeout();
149 void ResumeTimeout();
150
151 protected:
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000152 virtual int OnTimeout();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000153
154 private:
155 void Done();
156
157 int state_;
158 bool blocked_;
159 bool done_;
160 bool aborted_;
161 bool busy_;
162 bool error_;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200163 int64_t start_time_;
164 int64_t timeout_time_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000165 int timeout_seconds_;
166 bool timeout_suspended_;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200167 int32_t unique_id_;
168
169 static int32_t unique_id_seed_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000170};
171
172} // namespace rtc
173
174#endif // WEBRTC_BASE_TASK_H__