~alinuxninja/nginx-edge/trunk

« back to all changes in this revision

Viewing changes to debian/modules/ngx_pagespeed/psol/include/pagespeed/kernel/thread/scheduler.h

  • Committer: Vivian
  • Date: 2015-12-04 18:20:11 UTC
  • Revision ID: git-v1:a36f2bc32e884f7473b3a47040e5411306144d7d
* Do not extract psol.tar.gz

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Copyright 2011 Google Inc.
2
 
//
3
 
// Licensed under the Apache License, Version 2.0 (the "License");
4
 
// you may not use this file except in compliance with the License.
5
 
// You may obtain a copy of the License at
6
 
//
7
 
//      http://www.apache.org/licenses/LICENSE-2.0
8
 
//
9
 
// Unless required by applicable law or agreed to in writing, software
10
 
// distributed under the License is distributed on an "AS IS" BASIS,
11
 
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
 
// See the License for the specific language governing permissions and
13
 
// limitations under the License.
14
 
//
15
 
// Author: jmarantz@google.com (Joshua Marantz)
16
 
 
17
 
#ifndef PAGESPEED_KERNEL_THREAD_SCHEDULER_H_
18
 
#define PAGESPEED_KERNEL_THREAD_SCHEDULER_H_
19
 
 
20
 
#include <set>
21
 
 
22
 
#include "pagespeed/kernel/base/basictypes.h"
23
 
#include "pagespeed/kernel/base/condvar.h"
24
 
#include "pagespeed/kernel/base/function.h"
25
 
#include "pagespeed/kernel/base/scoped_ptr.h"
26
 
#include "pagespeed/kernel/base/thread_annotations.h"
27
 
#include "pagespeed/kernel/base/thread_system.h"
28
 
#include "pagespeed/kernel/base/timer.h"
29
 
#include "pagespeed/kernel/thread/queued_worker_pool.h"
30
 
 
31
 
// TODO(jmarantz): The Scheduler should cancel all outstanding operations
32
 
// on destruction.  Deploying this requires further analysis of shutdown
33
 
// ordering.
34
 
#define SCHEDULER_CANCEL_OUTSTANDING_ALARMS_ON_DESTRUCTION 0
35
 
 
36
 
namespace net_instaweb {
37
 
 
38
 
// Implements a simple scheduler that allows a thread to block until either time
39
 
// expires, or a condition variable is signaled.  Also permits various alarms to
40
 
// be scheduled; these are lightweight short-lived callbacks that must be safely
41
 
// runnable from any thread in any lock state in which scheduler invocations
42
 
// occur.  Finally, implements a hybrid between these: a callback that can be
43
 
// run when the condition variable is signaled.
44
 
//
45
 
// This class is designed to be overridden, but only to re-implement its
46
 
// internal notion of blocking to permit time to be mocked by MockScheduler.
47
 
class Scheduler {
48
 
 public:
49
 
  // A callback for a scheduler alarm, with an associated wakeup time (absolute
50
 
  // time after which the callback will be invoked with Run() by the scheduler).
51
 
  // Alarm should be treated as an opaque type.
52
 
  class Alarm;
53
 
 
54
 
  // Sorting comparator for Alarms, so that they can be retrieved in time
55
 
  // order.  For use by std::set, thus public.
56
 
  struct CompareAlarms {
57
 
    bool operator()(const Alarm* a, const Alarm* b) const;
58
 
  };
59
 
 
60
 
  Scheduler(ThreadSystem* thread_system, Timer* timer);
61
 
  virtual ~Scheduler();
62
 
 
63
 
  ThreadSystem::CondvarCapableMutex* mutex() LOCK_RETURNED(mutex_) {
64
 
    return mutex_.get();
65
 
  }
66
 
 
67
 
  // Optionally check that mutex is locked for debugging purposes.
68
 
  void DCheckLocked() EXCLUSIVE_LOCKS_REQUIRED(mutex()) {
69
 
    mutex_->DCheckLocked();
70
 
  }
71
 
 
72
 
  // Condition-style methods: The following three methods provide a simple
73
 
  // condition-variable-style interface that can be used to coordinate the
74
 
  // threads sharing the scheduler.
75
 
 
76
 
  // Wait at most timeout_ms, or until Signal() is called.
77
 
  void BlockingTimedWaitMs(int64 timeout_ms) EXCLUSIVE_LOCKS_REQUIRED(mutex()) {
78
 
    BlockingTimedWaitUs(timeout_ms * Timer::kMsUs);
79
 
  }
80
 
  void BlockingTimedWaitUs(int64 timeout_us) EXCLUSIVE_LOCKS_REQUIRED(mutex());
81
 
 
82
 
  // Non-blocking invocation of callback either when Signal() is called, or
83
 
  // after timeout_ms have passed.  Ownership of callback passes to the
84
 
  // scheduler, which deallocates it after invocation.  mutex() must be held on
85
 
  // the initial call, and is locked for the duration of callback.  Note that
86
 
  // callback may be invoked in a different thread from the calling thread.
87
 
  void TimedWaitMs(int64 timeout_ms, Function* callback)
88
 
      EXCLUSIVE_LOCKS_REQUIRED(mutex());
89
 
 
90
 
  // Signal threads in BlockingTimedWait[Ms,Us] and invoke TimedWaitMs
91
 
  // callbacks.  Performs outstanding work, including any triggered by the
92
 
  // signal, before returning; note that this means it may drop the scheduler
93
 
  // lock internally while doing callback invocation, which is different from
94
 
  // the usual condition variable signal semantics.
95
 
  void Signal() EXCLUSIVE_LOCKS_REQUIRED(mutex());
96
 
 
97
 
  // Alarms.  The following two methods provide a mechanism for scheduling
98
 
  // alarm tasks, each run at a particular time.
99
 
 
100
 
  // Schedules an alarm for absolute time wakeup_time_us, using the passed-in
101
 
  // Function* as the alarm callback.  Returns the created Alarm.  Performs
102
 
  // outstanding work.  The returned alarm will own the callback and will clean
103
 
  // itself and the callback when it is run or cancelled.  NOTE in particular
104
 
  // that calls to CancelAlarm must ensure the callback has not been invoked
105
 
  // yet.  This is why the scheduler mutex must be held for CancelAlarm.
106
 
  Alarm* AddAlarmAtUs(int64 wakeup_time_us, Function* callback);
107
 
 
108
 
  // Cancels an alarm, calling the Cancel() method and deleting the alarm
109
 
  // object.  Scheduler mutex must be held before call to ensure that alarm is
110
 
  // not called back before cancellation occurs.  Doesn't perform outstanding
111
 
  // work.  Returns true if the cancellation occurred.  If false is returned,
112
 
  // the alarm is already being run / has been run in another thread; if the
113
 
  // alarm deletes itself on Cancel(), it may no longer safely be used.
114
 
  //
115
 
  // Note that once the user callback for the alarm returns it's no longer
116
 
  // safe to call this (but this method is safe to call when the scheduler has
117
 
  // committed to running the callback, it will just return false), so it's the
118
 
  // caller's responsibility to properly synchronize between its callback and
119
 
  // its invocation of this.
120
 
  bool CancelAlarm(Alarm* alarm) EXCLUSIVE_LOCKS_REQUIRED(mutex());
121
 
 
122
 
  // Finally, ProcessAlarmsOrWaitUs provides a mechanism to ensure that pending
123
 
  // alarms are executed in the absence of other scheduler activity.
124
 
  // ProcessAlarmsOrWaitUs: handle outstanding alarms, or if there are none wait
125
 
  // until the next wakeup and handle alarms then before relinquishing control.
126
 
  // Idle no longer than timeout_us.  Passing in timeout_us=0 will run without
127
 
  // blocking.
128
 
  void ProcessAlarmsOrWaitUs(int64 timeout_us)
129
 
      EXCLUSIVE_LOCKS_REQUIRED(mutex());
130
 
 
131
 
  // Obtain the timer that the scheduler is using internally.  Important if you
132
 
  // and the scheduler want to agree on the passage of time.
133
 
  Timer* timer() { return timer_; }
134
 
 
135
 
  // Obtain the thread system used by the scheduler.
136
 
  ThreadSystem* thread_system() { return thread_system_; }
137
 
 
138
 
  // Internal method to kick the system because something of interest to the
139
 
  // overridden AwaitWakeup method has happened.  Exported here because C++
140
 
  // naming hates you.
141
 
  void Wakeup() { condvar_->Broadcast(); }
142
 
 
143
 
  // These methods notify the scheduler of work sequences that may run work
144
 
  // on it. They are only used for time simulations in MockScheduler and
145
 
  // are no-ops during normal usage.
146
 
  virtual void RegisterWorker(QueuedWorkerPool::Sequence* w);
147
 
  virtual void UnregisterWorker(QueuedWorkerPool::Sequence* w);
148
 
 
149
 
  // Run any alarms that have reached their deadline.  Returns the time of the
150
 
  // next deadline, or 0 if no further deadlines loom.  Sets *ran_alarms if
151
 
  // non-NULL and any alarms were run, otherwise leaves it untouched.
152
 
  int64 RunAlarms(bool* ran_alarms) EXCLUSIVE_LOCKS_REQUIRED(mutex());
153
 
 
154
 
 protected:
155
 
  // Internal method to await a wakeup event.  Block until wakeup_time_us (an
156
 
  // absolute time since the epoch), or until something interesting (such as a
157
 
  // call to Signal) occurs.  This is virtual to permit us to mock it out (the
158
 
  // mock simply advances time). This maybe called with 0 in case where there
159
 
  // are no timers currently active.
160
 
  virtual void AwaitWakeupUntilUs(int64 wakeup_time_us);
161
 
 
162
 
  bool running_waiting_alarms() const { return running_waiting_alarms_; }
163
 
 
164
 
 private:
165
 
  class CondVarTimeout;
166
 
  class CondVarCallbackTimeout;
167
 
  friend class SchedulerTest;
168
 
 
169
 
  typedef std::set<Alarm*, CompareAlarms> AlarmSet;
170
 
 
171
 
  void AddAlarmMutexHeldUs(int64 wakeup_time_us, Alarm* alarm);
172
 
  void CancelWaiting(Alarm* alarm);
173
 
  bool NoPendingAlarms();
174
 
 
175
 
  ThreadSystem* thread_system_;
176
 
  Timer* timer_;
177
 
  scoped_ptr<ThreadSystem::CondvarCapableMutex> mutex_;
178
 
  // condvar_ tracks whether interesting (next-wakeup decreasing or
179
 
  // signal_count_ increasing) events occur.
180
 
  scoped_ptr<ThreadSystem::Condvar> condvar_;
181
 
  uint32 index_;  // Used to disambiguate alarms with equal deadlines
182
 
  AlarmSet outstanding_alarms_;  // Priority queue of future alarms
183
 
  // An alarm may be deleted iff it is successfully removed from
184
 
  // outstanding_alarms_.
185
 
  int64 signal_count_;           // Number of times Signal has been called
186
 
  AlarmSet waiting_alarms_;      // Alarms waiting for signal_count to change
187
 
  bool running_waiting_alarms_;  // True if we're in process of invoking
188
 
                                 // user callbacks...
189
 
  DISALLOW_COPY_AND_ASSIGN(Scheduler);
190
 
};
191
 
 
192
 
// A simple adapter class that permits blocking until an alarm has been run or
193
 
// cancelled.  Designed for stack allocation.
194
 
//
195
 
// Note that success_ is guarded by the acquire/release semantics of
196
 
// atomic_bool and by monotonicity of done_.  Field order (==initialization
197
 
// order) is important here.
198
 
class SchedulerBlockingFunction : public Function {
199
 
 public:
200
 
  explicit SchedulerBlockingFunction(Scheduler* scheduler);
201
 
  virtual ~SchedulerBlockingFunction();
202
 
  virtual void Run();
203
 
  virtual void Cancel();
204
 
  // Block until called back, returning true for Run and false for Cancel.
205
 
  bool Block();
206
 
 private:
207
 
  Scheduler* scheduler_;
208
 
  bool success_;
209
 
  bool done_;  // protected by scheduler_->mutex()
210
 
  DISALLOW_COPY_AND_ASSIGN(SchedulerBlockingFunction);
211
 
};
212
 
 
213
 
}  // namespace net_instaweb
214
 
 
215
 
#endif  // PAGESPEED_KERNEL_THREAD_SCHEDULER_H_