RCFProto
 All Classes Functions Typedefs
win_event.hpp
1 
2 //******************************************************************************
3 // RCF - Remote Call Framework
4 //
5 // Copyright (c) 2005 - 2013, Delta V Software. All rights reserved.
6 // http://www.deltavsoft.com
7 //
8 // RCF is distributed under dual licenses - closed source or GPL.
9 // Consult your particular license for conditions of use.
10 //
11 // If you have not purchased a commercial license, you are using RCF
12 // under GPL terms.
13 //
14 // Version: 2.0
15 // Contact: support <at> deltavsoft.com
16 //
17 //******************************************************************************
18 
19 //
20 // detail/win_event.hpp
21 // ~~~~~~~~~~~~~~~~~~~~
22 //
23 // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
24 //
25 // Distributed under the Boost Software License, Version 1.0. (See accompanying
26 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
27 //
28 
29 #ifndef RCF_DETAIL_WIN_EVENT_HPP
30 #define RCF_DETAIL_WIN_EVENT_HPP
31 
32 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
33 # pragma once
34 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
35 
36 #if defined(BOOST_WINDOWS)
37 
38 #include <boost/assert.hpp>
39 
40 #include <RCF/thread/push_options.hpp>
41 
42 #include <RCF/thread/mutex.hpp>
43 
44 namespace RCF {
45 namespace detail {
46 
47 class RCF_EXPORT win_event
48  : private noncopyable
49 {
50 public:
51  // Constructor.
52  win_event();
53 
54  // Destructor.
55  ~win_event()
56  {
57  ::CloseHandle(event_);
58  }
59 
60  // Signal the event.
61  template <typename Lock>
62  void signal_all(Lock& lock)
63  {
64  BOOST_ASSERT(lock.locked());
65  (void)lock;
66  if (mWaitCount > 0)
67  {
68  ::SetEvent(event_);
69  }
70  }
71 
72  // Reset the event.
73  template <typename Lock>
74  void clear(Lock& lock)
75  {
76  BOOST_ASSERT(lock.locked());
77  (void)lock;
78  ::ResetEvent(event_);
79  }
80 
81  // Wait for the event to become signalled.
82  template <typename Lock>
83  void wait(Lock& lock)
84  {
85  BOOST_ASSERT(lock.locked());
86  lock.unlock();
87 
88  {
89  mutex::scoped_lock waitLock(mWaitCountMutex);
90  ++mWaitCount;
91  }
92 
93  ::WaitForSingleObject(event_, INFINITE);
94 
95  {
96  mutex::scoped_lock waitLock(mWaitCountMutex);
97  --mWaitCount;
98  if (mWaitCount == 0)
99  {
100  // Set signalled state back to false.
101  ::ResetEvent(event_);
102  }
103  }
104 
105  lock.lock();
106 
107  }
108 
109  // Wait for the event to become signalled.
110  template <typename Lock>
111  bool timed_wait(Lock& lock, boost::uint32_t waitMs)
112  {
113  BOOST_ASSERT(lock.locked());
114 
115  lock.unlock();
116 
117  {
118  mutex::scoped_lock waitLock(mWaitCountMutex);
119  ++mWaitCount;
120  }
121 
122  DWORD ret = ::WaitForSingleObject(event_, waitMs);
123  assert(ret != WAIT_ABANDONED && ret != WAIT_FAILED);
124 
125  {
126  mutex::scoped_lock waitLock(mWaitCountMutex);
127  --mWaitCount;
128  if (ret != WAIT_TIMEOUT && mWaitCount == 0)
129  {
130  // Set signalled state back to false.
131  ::ResetEvent(event_);
132  }
133  }
134 
135  lock.lock();
136  if (ret == WAIT_TIMEOUT)
137  {
138  return false;
139  }
140 
141  return true;
142  }
143 
144  // Signal the event.
145  template <typename Lock>
146  void notify_all(Lock& lock)
147  {
148  signal_all(lock);
149  }
150 
151 protected:
152 
153  // Newer versions of Windows have built in condition variables (InitializeConditionVariable() etc)
154  // but they are not supported in XP, Server 2003, and older. So for now we use
155  // events instead, with the mWatiCount workaround below for resetting the event.
156  HANDLE event_;
157 
158  // Number of threads waiting on the event. When the threads are signalled,
159  // the counter is decremented, and the thread that decrements the counter
160  // to zero will reset the event. The event is a "manual reset" event, as
161  // an "auto reset" event only releases 1 thread at a time.
162  mutex mWaitCountMutex;
163  int mWaitCount;
164 };
165 
166 } // namespace detail
167 } // namespace RCF
168 
169 #include <RCF/thread/pop_options.hpp>
170 
171 #endif // defined(BOOST_WINDOWS)
172 
173 #endif // RCF_DETAIL_WIN_EVENT_HPP