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