Ion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
semaphore.cc
Go to the documentation of this file.
1 
18 #include "ion/port/semaphore.h"
19 #include "ion/port/threadutils.h"
20 
21 #if defined(ION_PLATFORM_IOS) || defined(ION_PLATFORM_MAC)
22 #include <mach/mach_init.h>
23 #include <mach/task.h>
24 #include <time.h>
25 #elif defined(ION_PLATFORM_ASMJS)
26 #include <cassert>
27 #elif !defined(ION_PLATFORM_WINDOWS)
28 #include <fcntl.h>
29 #include <sys/stat.h>
30 #include <sys/time.h>
31 #endif
32 
33 namespace ion {
34 namespace port {
35 
37 #if defined(ION_PLATFORM_IOS) || defined(ION_PLATFORM_MAC)
38  semaphore_ = dispatch_semaphore_create(0);
39 #elif defined(ION_PLATFORM_WINDOWS)
40  semaphore_ = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
42  value_.store(0);
43 #elif defined(ION_PLATFORM_ASMJS)
44  value_ = 0;
45 #else
46  sem_init(&semaphore_, 0, 0);
47 #endif
48 }
49 
50 Semaphore::Semaphore(uint32 initial_value) {
51 #if defined(ION_PLATFORM_IOS) || defined(ION_PLATFORM_MAC)
52  semaphore_ = dispatch_semaphore_create(0);
55  while (initial_value--)
56  Post();
57 #elif defined(ION_PLATFORM_WINDOWS)
58  semaphore_ = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
62  value_.store(initial_value);
63 #elif defined(ION_PLATFORM_ASMJS)
64  value_ = initial_value;
68 #else
69  sem_init(&semaphore_, 0, initial_value);
70 #endif
71 }
72 
74 #if defined(ION_PLATFORM_IOS) || defined(ION_PLATFORM_MAC)
75 #elif defined(ION_PLATFORM_WINDOWS)
77  CloseHandle(semaphore_);
78 #elif defined(ION_PLATFORM_ASMJS)
79 #else
81  sem_destroy(&semaphore_);
82 #endif
83 }
84 
86 #if defined(ION_PLATFORM_IOS) || defined(ION_PLATFORM_MAC)
87  return semaphore_
89  ? (dispatch_semaphore_signal(semaphore_) || true)
90  : false;
91 #elif defined(ION_PLATFORM_WINDOWS)
92  if (++value_ > 0) {
94  return true;
95  } else {
97  return ReleaseSemaphore(semaphore_, 1, NULL) != 0;
98  }
99 #elif defined(ION_PLATFORM_ASMJS)
100  ++value_;
101  return true;
102 #else
103  return sem_post(&semaphore_) == 0;
104 #endif
105 }
106 
108 #if defined(ION_PLATFORM_IOS) || defined(ION_PLATFORM_MAC)
109  return semaphore_
111  ? (0 == dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_NOW))
112  : false;
113 #elif defined(ION_PLATFORM_WINDOWS)
114  int val = value_.load(std::memory_order_acquire);
115  while (val > 0) {
123  if (value_.compare_exchange_weak(val, val - 1,
124  std::memory_order_acq_rel,
125  std::memory_order_acquire)) {
126  return true;
127  }
128  }
130  return false;
131 #elif defined(ION_PLATFORM_ASMJS)
132  if (value_ > 0) {
133  --value_;
134  return true;
135  } else {
136  return false;
137  }
138 #else
139  return sem_trywait(&semaphore_) == 0;
140 #endif
141 }
142 
143 bool Semaphore::TimedWaitMs(int64 timeout_in_ms) {
144  if (timeout_in_ms < 0)
145  return Wait();
146 
147 #if defined(ION_PLATFORM_IOS) || defined(ION_PLATFORM_MAC)
148  static const int64 kMsecToNsec = 1000000;
150  const dispatch_time_t deadline = dispatch_time(DISPATCH_TIME_NOW,
151  timeout_in_ms * kMsecToNsec);
153  return semaphore_
154  ? (0 == dispatch_semaphore_wait(semaphore_, deadline))
155  : false;
156 #elif defined(ION_PLATFORM_WINDOWS)
157  if (value_-- > 0) {
159  return true;
160  }
162  if (WaitForSingleObject(semaphore_, timeout_in_ms) == WAIT_OBJECT_0) {
164  return true;
165  } else {
167  ++value_;
168  return false;
169  }
170 #elif defined(ION_PLATFORM_ASMJS)
171  return TryWait();
173 #else
174  static const int64 kMsecToNsec = 1000000;
175  static const int64 kNsecPerSec = 1000000000;
176 
178  timeval now;
179  ::gettimeofday(&now, NULL);
181  const uint64 timeout_in_ns = now.tv_usec * 1000 + timeout_in_ms * kMsecToNsec;
182 
183  timespec timeout;
185  timeout.tv_nsec = static_cast<int32>(timeout_in_ns % kNsecPerSec);
186  timeout.tv_sec = static_cast<int32>(now.tv_sec + timeout_in_ns / kNsecPerSec);
187 #if !defined(ION_PLATFORM_PNACL) && !defined(ION_PLATFORM_NACL)
188  return sem_timedwait(&semaphore_, &timeout) == 0;
189 #else
190  while (!TryWait()) {
192  YieldThread();
193  ::gettimeofday(&now, NULL);
194  if (now.tv_sec > timeout.tv_sec ||
195  (now.tv_sec == timeout.tv_sec &&
196  now.tv_usec * 1000 > timeout.tv_nsec)) {
197  return false;
198  }
199  }
200  return true;
201 #endif
202 #endif
203 }
204 
206 #if defined(ION_PLATFORM_IOS) || defined(ION_PLATFORM_MAC)
207  return semaphore_
209  ? (dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER) || true)
210  : false;
211 #elif defined(ION_PLATFORM_WINDOWS)
212  int spin_count = 2;
214  while (spin_count--) {
215  if (TryWait()) {
217  return true;
218  }
219  }
221  if (value_-- > 0) {
223  return true;
224  } else {
226  if (WaitForSingleObject(semaphore_, INFINITE) == WAIT_OBJECT_0) {
227  return true;
228  } else {
231  ++value_; // COV_NF_LINE
232  return false; // COV_NF_LINE
233  }
234  }
235 #elif defined(ION_PLATFORM_ASMJS)
236  if (value_ > 0) {
237  --value_;
238  return true;
239  } else {
240  assert(false &&
241  "Semaphore::Wait cannot block on a platform without threads.");
242  return false;
243  }
244 #else
245  return sem_wait(&semaphore_) == 0;
246 #endif
247 }
248 } // namespace port
249 } // namespace ion
bool Post()
Wakes a single thread that is Wait()ing, or the next thread to call Wait().
Definition: semaphore.cc:85
bool Wait()
Blocks the calling thread until another thread calls Post().
Definition: semaphore.cc:205
void YieldThread()
Causes the calling thread to relinquish the CPU if there are other threads waiting to execute...
Definition: threadutils.cc:359
bool TimedWaitMs(int64 timeout_in_ms)
Blocks for a maximum of the passed number of milliseconds before returning.
Definition: semaphore.cc:143
Semaphore()
Initializes a semaphore with an internal value of zero.
Definition: semaphore.cc:36
bool TryWait()
Does not block.
Definition: semaphore.cc:107