Commit d7f99924 authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

Added a wait with timeout to the platform semaphore class.

The code has been compiled and tested on Windows, Linux and Mac OS.

The FreeBSD version is a copy of the Linux version which should work on FreeBSD as well. According to the FreeBSD documentation clock_gettime is part of the standard C library so the assumption is that no additional link libraries is required for FreeBSD.
Review URL: http://codereview.chromium.org/48123

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1526 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 89f46665
......@@ -151,7 +151,7 @@ V8_EXTRA_FLAGS = {
MKSNAPSHOT_EXTRA_FLAGS = {
'gcc': {
'os:linux': {
'LIBS': ['pthread'],
'LIBS': ['pthread', 'rt'],
},
'os:macos': {
'LIBS': ['pthread'],
......@@ -195,7 +195,7 @@ CCTEST_EXTRA_FLAGS = {
'LIBPATH': [abspath('.')]
},
'os:linux': {
'LIBS': ['pthread'],
'LIBS': ['pthread', 'rt'],
},
'os:macos': {
'LIBS': ['pthread'],
......@@ -233,7 +233,7 @@ SAMPLE_FLAGS = {
'LIBPATH': ['.']
},
'os:linux': {
'LIBS': ['pthread'],
'LIBS': ['pthread', 'rt'],
},
'os:macos': {
'LIBS': ['pthread'],
......@@ -301,7 +301,7 @@ D8_FLAGS = {
'LIBS': ['readline']
},
'os:linux': {
'LIBS': ['pthread'],
'LIBS': ['pthread', 'rt'],
},
'os:macos': {
'LIBS': ['pthread'],
......
......@@ -608,11 +608,13 @@ class FreeBSDSemaphore : public Semaphore {
virtual ~FreeBSDSemaphore() { sem_destroy(&sem_); }
virtual void Wait();
virtual bool Wait(int timeout);
virtual void Signal() { sem_post(&sem_); }
private:
sem_t sem_;
};
void FreeBSDSemaphore::Wait() {
while (true) {
int result = sem_wait(&sem_);
......@@ -621,6 +623,39 @@ void FreeBSDSemaphore::Wait() {
}
}
bool FreeBSDSemaphore::Wait(int timeout) {
const long kOneSecondMicros = 1000000; // NOLINT
const long kOneSecondNanos = 1000000000; // NOLINT
// Split timeout into second and nanosecond parts.
long nanos = (timeout % kOneSecondMicros) * 1000; // NOLINT
time_t secs = timeout / kOneSecondMicros;
// Get the current real time clock.
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
return false;
}
// Calculate realtime for end of timeout.
ts.tv_nsec += nanos;
if (ts.tv_nsec >= kOneSecondNanos) {
ts.tv_nsec -= kOneSecondNanos;
ts.tv_nsec++;
}
ts.tv_sec += secs;
// Wait for semaphore signalled or timeout.
while (true) {
int result = sem_timedwait(&sem_, &ts);
if (result == 0) return true; // Successfully got semaphore.
if (result == -1 && errno == ETIMEDOUT) return false; // Timeout.
CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
}
}
Semaphore* OS::CreateSemaphore(int count) {
return new FreeBSDSemaphore(count);
}
......
......@@ -592,11 +592,13 @@ class LinuxSemaphore : public Semaphore {
virtual ~LinuxSemaphore() { sem_destroy(&sem_); }
virtual void Wait();
virtual bool Wait(int timeout);
virtual void Signal() { sem_post(&sem_); }
private:
sem_t sem_;
};
void LinuxSemaphore::Wait() {
while (true) {
int result = sem_wait(&sem_);
......@@ -605,6 +607,39 @@ void LinuxSemaphore::Wait() {
}
}
bool LinuxSemaphore::Wait(int timeout) {
const long kOneSecondMicros = 1000000; // NOLINT
const long kOneSecondNanos = 1000000000; // NOLINT
// Split timeout into second and nanosecond parts.
long nanos = (timeout % kOneSecondMicros) * 1000; // NOLINT
time_t secs = timeout / kOneSecondMicros;
// Get the current realtime clock.
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
return false;
}
// Calculate real time for end of timeout.
ts.tv_nsec += nanos;
if (ts.tv_nsec >= kOneSecondNanos) {
ts.tv_nsec -= kOneSecondNanos;
ts.tv_nsec++;
}
ts.tv_sec += secs;
// Wait for semaphore signalled or timeout.
while (true) {
int result = sem_timedwait(&sem_, &ts);
if (result == 0) return true; // Successfully got semaphore.
if (result == -1 && errno == ETIMEDOUT) return false; // Timeout.
CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
}
}
Semaphore* OS::CreateSemaphore(int count) {
return new LinuxSemaphore(count);
}
......
......@@ -565,6 +565,8 @@ class MacOSSemaphore : public Semaphore {
// platform is not needed here.
void Wait() { semaphore_wait(semaphore_); }
bool Wait(int timeout);
void Signal() { semaphore_signal(semaphore_); }
private:
......@@ -572,6 +574,14 @@ class MacOSSemaphore : public Semaphore {
};
bool MacOSSemaphore::Wait(int timeout) {
mach_timespec_t ts;
ts.tv_sec = timeout / 1000000;
ts.tv_nsec = (timeout % 1000000) * 1000;
return semaphore_timedwait(semaphore_, ts) != KERN_OPERATION_TIMED_OUT;
}
Semaphore* OS::CreateSemaphore(int count) {
return new MacOSSemaphore(count);
}
......
......@@ -1538,6 +1538,12 @@ class Win32Semaphore : public Semaphore {
WaitForSingleObject(sem, INFINITE);
}
bool Wait(int timeout) {
// Timeout in Windows API is in milliseconds.
DWORD millis_timeout = timeout / 1000;
return WaitForSingleObject(sem, millis_timeout) != WAIT_TIMEOUT;
}
void Signal() {
LONG dummy;
ReleaseSemaphore(sem, 1, &dummy);
......
......@@ -410,10 +410,16 @@ class Semaphore {
public:
virtual ~Semaphore() {}
// Suspends the calling thread until the counter is non zero
// Suspends the calling thread until the semaphore counter is non zero
// and then decrements the semaphore counter.
virtual void Wait() = 0;
// Suspends the calling thread until the counter is non zero or the timeout
// time has passsed. If timeout happens the return value is false and the
// counter is unchanged. Otherwise the semaphore counter is decremented and
// true is returned. The timeout value is specified in microseconds.
virtual bool Wait(int timeout) = 0;
// Increments the semaphore counter.
virtual void Signal() = 0;
};
......
......@@ -38,3 +38,26 @@ TEST(ShallowLock) {
CHECK_EQ(0, mutex->Unlock());
delete mutex;
}
TEST(SemaphoreTimeout) {
bool ok;
Semaphore* sem = OS::CreateSemaphore(0);
// Semaphore not signalled - timeout.
ok = sem->Wait(0);
CHECK(!ok);
ok = sem->Wait(100);
CHECK(!ok);
ok = sem->Wait(1000);
CHECK(!ok);
// Semaphore signalled - no timeout.
sem->Signal();
ok = sem->Wait(0);
sem->Signal();
ok = sem->Wait(100);
sem->Signal();
ok = sem->Wait(1000);
CHECK(ok);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment