1 : /*
2 : * Copyright (c) 2011 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 :
8 : // ConditionVariable is a reasonable attempt at simulating
9 : // the newer Posix and Vista-only construct for condition variable
10 : // synchronization. This functionality is very helpful for having several
11 : // threads wait for an event, as is common with a thread pool
12 : // managed by a master. The meaning of such an event in the
13 : // (worker) thread pool scenario is that additional tasks are
14 : // now available for processing. It is used in Chrome in the
15 : // DNS prefetching system to notify worker threads that a queue
16 : // now has items (tasks) which need to be tended to.
17 : // A related use would have a pool manager waiting on a
18 : // ConditionVariable, waiting for a thread in the pool to announce
19 : // (signal) that there is now more room in a (bounded size) communications
20 : // queue for the manager to deposit tasks, or, as a second example, that
21 : // the queue of tasks is completely empty and all workers are waiting.
22 :
23 : // USAGE NOTE 1: spurious signal events are possible with this and
24 : // most implementations of condition variables. As a result, be
25 : // *sure* to retest your condition before proceeding. The following
26 : // is a good example of doing this correctly:
27 :
28 : // while (!work_to_be_done()) Wait(...);
29 :
30 : // In contrast do NOT do the following:
31 :
32 : // if (!work_to_be_done()) Wait(...); // Don't do this.
33 :
34 : // Especially avoid the above if you are relying on some other thread only
35 : // issuing a signal up *if* there is work-to-do. There can/will
36 : // be spurious signals. Recheck state on waiting thread before
37 : // assuming the signal was intentional. Caveat caller ;-).
38 :
39 : // USAGE NOTE 2: Broadcast() frees up all waiting threads at once,
40 : // which leads to contention for the locks they all held when they
41 : // called Wait(). This results in POOR performance. A much better
42 : // approach to getting a lot of threads out of Wait() is to have each
43 : // thread (upon exiting Wait()) call Signal() to free up another
44 : // Wait'ing thread. Look at condition_variable_unittest.cc for
45 : // both examples.
46 :
47 : // Broadcast() can be used nicely during teardown, as it gets the job
48 : // done, and leaves no sleeping threads... and performance is less
49 : // critical at that point.
50 :
51 : // The semantics of Broadcast() are carefully crafted so that *all*
52 : // threads that were waiting when the request was made will indeed
53 : // get signaled. Some implementations mess up, and don't signal them
54 : // all, while others allow the wait to be effectively turned off (for
55 : // for a while while waiting threads come around). This implementation
56 : // appears correct, as it will not "lose" any signals, and will guarantee
57 : // that all threads get signaled by Broadcast().
58 :
59 : // This implementation offers support for "performance" in its selection of
60 : // which thread to revive. Performance, in direct contrast with "fairness,"
61 : // assures that the thread that most recently began to Wait() is selected by
62 : // Signal to revive. Fairness would (if publicly supported) assure that the
63 : // thread that has Wait()ed the longest is selected. The default policy
64 : // may improve performance, as the selected thread may have a greater chance of
65 : // having some of its stack data in various CPU caches. Although not publicly
66 : // available, internal support for "fairness" is used by the UnitTest harness
67 : // only on Windows to more thoroughly test the implementation.
68 :
69 : // For many very subtle implementation details, see the condition_variable.cc.
70 :
71 : // NOTE(gregoryd): changed the interface to allow providing the Lock reference
72 : // in Wait functions instead of the constructor.
73 :
74 : #ifndef NATIVE_CLIENT_SRC_TRUSTED_PLATFORM_WIN_CONDITION_VARIABLE_H_
75 : #define NATIVE_CLIENT_SRC_TRUSTED_PLATFORM_WIN_CONDITION_VARIABLE_H_
76 :
77 :
78 : #include "native_client/src/shared/platform/win/time.h"
79 : #include "native_client/src/shared/platform/win/condition_variable_events.h"
80 : #include "native_client/src/shared/platform/win/lock.h"
81 :
82 : namespace NaCl {
83 :
84 : class Lock;
85 :
86 : class ConditionVariable {
87 : public:
88 : // Construct a cv (our version allows to use the cv with different locks).
89 : ConditionVariable();
90 :
91 : ~ConditionVariable();
92 :
93 : // Wait() releases the caller's critical section atomically as it starts to
94 : // sleep, and the re-acquires it when it is signaled.
95 : // We provide two variants of TimedWait:
96 : // the first one takes relative time as an argument.
97 : int TimedWaitRel(Lock& user_lock, TimeDelta max_time);
98 : // The second TimedWait takes absolute time
99 : int TimedWaitAbs(Lock& user_lock, TimeTicks abs_time);
100 2 : void Wait(Lock& user_lock) {
101 : // Default to "wait forever" timing, which means have to get a Signal()
102 : // or Broadcast() to come out of this wait state.
103 2 : TimedWaitRel(user_lock, TimeDelta::FromMilliseconds(INFINITE));
104 2 : }
105 :
106 : // Broadcast() revives all waiting threads.
107 : void Broadcast();
108 : // Signal() revives one waiting thread.
109 : void Signal();
110 :
111 : private:
112 : enum RunState { RUNNING = 64213, SHUTDOWN = 0 };
113 :
114 : // Internal implementation methods supporting Wait().
115 : ConditionVariableEvent* GetEventForWaiting();
116 : void RecycleEvent(ConditionVariableEvent* used_event);
117 :
118 : // Note that RUNNING is an unlikely number to have in RAM by accident.
119 : // This helps with defensive destructor coding in the face of user error.
120 : RunState run_state_;
121 :
122 : // Private critical section for access to member data.
123 : Lock internal_lock_;
124 : // Lock that is acquired before calling Wait().
125 : // NOTE(gregoryd): Lock& user_lock_;-removed, see the note at top of file
126 :
127 : // Events that threads are blocked on.
128 : ConditionVariableEvent waiting_list_;
129 :
130 : // Free list for old events.
131 : ConditionVariableEvent recycling_list_;
132 : int recycling_list_size_;
133 :
134 : // The number of allocated, but not yet deleted events.
135 : int allocation_counter_;
136 :
137 : NACL_DISALLOW_COPY_AND_ASSIGN(ConditionVariable);
138 : };
139 :
140 : } // namespace NaCl
141 :
142 : #endif // NATIVE_CLIENT_SRC_TRUSTED_PLATFORM_WIN_CONDITION_VARIABLE_H_
|