1e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// Copyright 2013 the V8 project authors. All rights reserved.
23484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org// Use of this source code is governed by a BSD-style license that can be
33484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org// found in the LICENSE file.
4e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
55de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org#include "src/base/platform/semaphore.h"
6e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
7e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org#if V8_OS_MACOSX
8e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org#include <mach/mach_init.h>
9e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org#include <mach/task.h>
10e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org#endif
11e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
12e31286d471eb2e656a1809383fa16b76053dd673machenbach@chromium.org#include <errno.h>
13e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
145de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org#include "src/base/logging.h"
15d4f11c0cf476dd854eaebec1cbacb1afc7bea18emachenbach@chromium.org#include "src/base/platform/elapsed-timer.h"
165de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org#include "src/base/platform/time.h"
17e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
18e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgnamespace v8 {
195de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.orgnamespace base {
20e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
21e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org#if V8_OS_MACOSX
22e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
23e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgSemaphore::Semaphore(int count) {
24e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  kern_return_t result = semaphore_create(
25e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org      mach_task_self(), &native_handle_, SYNC_POLICY_FIFO, count);
26e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org  DCHECK_EQ(KERN_SUCCESS, result);
27e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  USE(result);
28e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org}
29e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
30e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
31e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgSemaphore::~Semaphore() {
32e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  kern_return_t result = semaphore_destroy(mach_task_self(), native_handle_);
33e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org  DCHECK_EQ(KERN_SUCCESS, result);
34e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  USE(result);
35e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org}
36e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
37e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
38e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgvoid Semaphore::Signal() {
39e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  kern_return_t result = semaphore_signal(native_handle_);
40e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org  DCHECK_EQ(KERN_SUCCESS, result);
41e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  USE(result);
42e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org}
43e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
44e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
45e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgvoid Semaphore::Wait() {
46e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  while (true) {
47e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    kern_return_t result = semaphore_wait(native_handle_);
48e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    if (result == KERN_SUCCESS) return;  // Semaphore was signalled.
49e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org    DCHECK_EQ(KERN_ABORTED, result);
50e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  }
51e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org}
52e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
53e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
54e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgbool Semaphore::WaitFor(const TimeDelta& rel_time) {
55e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  TimeTicks now = TimeTicks::Now();
56e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  TimeTicks end = now + rel_time;
57e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  while (true) {
58e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    mach_timespec_t ts;
59e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    if (now >= end) {
60e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org      // Return immediately if semaphore was not signalled.
61e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org      ts.tv_sec = 0;
62e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org      ts.tv_nsec = 0;
63e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    } else {
64e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org      ts = (end - now).ToMachTimespec();
65e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    }
66e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    kern_return_t result = semaphore_timedwait(native_handle_, ts);
67e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    if (result == KERN_SUCCESS) return true;  // Semaphore was signalled.
68e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    if (result == KERN_OPERATION_TIMED_OUT) return false;  // Timeout.
69e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org    DCHECK_EQ(KERN_ABORTED, result);
70e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    now = TimeTicks::Now();
71e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  }
72e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org}
73e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
74e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org#elif V8_OS_POSIX
75e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
76e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgSemaphore::Semaphore(int count) {
77e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org  DCHECK(count >= 0);
78e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  int result = sem_init(&native_handle_, 0, count);
79e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org  DCHECK_EQ(0, result);
80e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  USE(result);
81e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org}
82e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
83e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
84e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgSemaphore::~Semaphore() {
85e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  int result = sem_destroy(&native_handle_);
86e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org  DCHECK_EQ(0, result);
87e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  USE(result);
88e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org}
89e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
90e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
91e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgvoid Semaphore::Signal() {
92e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  int result = sem_post(&native_handle_);
93e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org  DCHECK_EQ(0, result);
94e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  USE(result);
95e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org}
96e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
97e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
98e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgvoid Semaphore::Wait() {
99e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  while (true) {
100e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    int result = sem_wait(&native_handle_);
101e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    if (result == 0) return;  // Semaphore was signalled.
102e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    // Signal caused spurious wakeup.
103e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org    DCHECK_EQ(-1, result);
104e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org    DCHECK_EQ(EINTR, errno);
105e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  }
106e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org}
107e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
108e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
109e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgbool Semaphore::WaitFor(const TimeDelta& rel_time) {
110d4f11c0cf476dd854eaebec1cbacb1afc7bea18emachenbach@chromium.org#if V8_OS_NACL
111d4f11c0cf476dd854eaebec1cbacb1afc7bea18emachenbach@chromium.org  // PNaCL doesn't support sem_timedwait, do ugly busy waiting.
112d4f11c0cf476dd854eaebec1cbacb1afc7bea18emachenbach@chromium.org  ElapsedTimer timer;
113d4f11c0cf476dd854eaebec1cbacb1afc7bea18emachenbach@chromium.org  timer.Start();
114d4f11c0cf476dd854eaebec1cbacb1afc7bea18emachenbach@chromium.org  do {
115d4f11c0cf476dd854eaebec1cbacb1afc7bea18emachenbach@chromium.org    int result = sem_trywait(&native_handle_);
116d4f11c0cf476dd854eaebec1cbacb1afc7bea18emachenbach@chromium.org    if (result == 0) return true;
11721d700eedcdd6570eff22ece724b63a5eefe78cbmachenbach@chromium.org    DCHECK(errno == EAGAIN || errno == EINTR);
118d4f11c0cf476dd854eaebec1cbacb1afc7bea18emachenbach@chromium.org  } while (!timer.HasExpired(rel_time));
119d4f11c0cf476dd854eaebec1cbacb1afc7bea18emachenbach@chromium.org  return false;
120d4f11c0cf476dd854eaebec1cbacb1afc7bea18emachenbach@chromium.org#else
121e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  // Compute the time for end of timeout.
122e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  const Time time = Time::NowFromSystemTime() + rel_time;
123e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  const struct timespec ts = time.ToTimespec();
124e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
125e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  // Wait for semaphore signalled or timeout.
126e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  while (true) {
127e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    int result = sem_timedwait(&native_handle_, &ts);
128e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    if (result == 0) return true;  // Semaphore was signalled.
129e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org#if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
130e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    if (result > 0) {
131e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org      // sem_timedwait in glibc prior to 2.3.4 returns the errno instead of -1.
132e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org      errno = result;
133e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org      result = -1;
134e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    }
135e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org#endif
136e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    if (result == -1 && errno == ETIMEDOUT) {
137e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org      // Timed out while waiting for semaphore.
138e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org      return false;
139e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    }
140e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    // Signal caused spurious wakeup.
141e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org    DCHECK_EQ(-1, result);
142e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org    DCHECK_EQ(EINTR, errno);
143e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  }
144d4f11c0cf476dd854eaebec1cbacb1afc7bea18emachenbach@chromium.org#endif
145e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org}
146e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
147e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org#elif V8_OS_WIN
148e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
149e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgSemaphore::Semaphore(int count) {
150e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org  DCHECK(count >= 0);
151e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  native_handle_ = ::CreateSemaphoreA(NULL, count, 0x7fffffff, NULL);
152e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org  DCHECK(native_handle_ != NULL);
153e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org}
154e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
155e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
156e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgSemaphore::~Semaphore() {
157e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  BOOL result = CloseHandle(native_handle_);
158e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org  DCHECK(result);
159e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  USE(result);
160e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org}
161e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
162e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
163e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgvoid Semaphore::Signal() {
164e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  LONG dummy;
165e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  BOOL result = ReleaseSemaphore(native_handle_, 1, &dummy);
166e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org  DCHECK(result);
167e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  USE(result);
168e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org}
169e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
170e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
171e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgvoid Semaphore::Wait() {
172e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  DWORD result = WaitForSingleObject(native_handle_, INFINITE);
173e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org  DCHECK(result == WAIT_OBJECT_0);
174e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  USE(result);
175e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org}
176e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
177e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
178e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgbool Semaphore::WaitFor(const TimeDelta& rel_time) {
179e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  TimeTicks now = TimeTicks::Now();
180e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  TimeTicks end = now + rel_time;
181e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  while (true) {
182e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    int64_t msec = (end - now).InMilliseconds();
183e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    if (msec >= static_cast<int64_t>(INFINITE)) {
184e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org      DWORD result = WaitForSingleObject(native_handle_, INFINITE - 1);
185e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org      if (result == WAIT_OBJECT_0) {
186e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org        return true;
187e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org      }
188e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org      DCHECK(result == WAIT_TIMEOUT);
189e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org      now = TimeTicks::Now();
190e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    } else {
191e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org      DWORD result = WaitForSingleObject(
192e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org          native_handle_, (msec < 0) ? 0 : static_cast<DWORD>(msec));
193e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org      if (result == WAIT_TIMEOUT) {
194e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org        return false;
195e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org      }
196e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org      DCHECK(result == WAIT_OBJECT_0);
197e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org      return true;
198e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org    }
199e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org  }
200e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org}
201e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
202e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org#endif  // V8_OS_MACOSX
203e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org
2045de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org} }  // namespace v8::base
205