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 = { ...@@ -151,7 +151,7 @@ V8_EXTRA_FLAGS = {
MKSNAPSHOT_EXTRA_FLAGS = { MKSNAPSHOT_EXTRA_FLAGS = {
'gcc': { 'gcc': {
'os:linux': { 'os:linux': {
'LIBS': ['pthread'], 'LIBS': ['pthread', 'rt'],
}, },
'os:macos': { 'os:macos': {
'LIBS': ['pthread'], 'LIBS': ['pthread'],
...@@ -195,7 +195,7 @@ CCTEST_EXTRA_FLAGS = { ...@@ -195,7 +195,7 @@ CCTEST_EXTRA_FLAGS = {
'LIBPATH': [abspath('.')] 'LIBPATH': [abspath('.')]
}, },
'os:linux': { 'os:linux': {
'LIBS': ['pthread'], 'LIBS': ['pthread', 'rt'],
}, },
'os:macos': { 'os:macos': {
'LIBS': ['pthread'], 'LIBS': ['pthread'],
...@@ -233,7 +233,7 @@ SAMPLE_FLAGS = { ...@@ -233,7 +233,7 @@ SAMPLE_FLAGS = {
'LIBPATH': ['.'] 'LIBPATH': ['.']
}, },
'os:linux': { 'os:linux': {
'LIBS': ['pthread'], 'LIBS': ['pthread', 'rt'],
}, },
'os:macos': { 'os:macos': {
'LIBS': ['pthread'], 'LIBS': ['pthread'],
...@@ -301,7 +301,7 @@ D8_FLAGS = { ...@@ -301,7 +301,7 @@ D8_FLAGS = {
'LIBS': ['readline'] 'LIBS': ['readline']
}, },
'os:linux': { 'os:linux': {
'LIBS': ['pthread'], 'LIBS': ['pthread', 'rt'],
}, },
'os:macos': { 'os:macos': {
'LIBS': ['pthread'], 'LIBS': ['pthread'],
......
...@@ -608,11 +608,13 @@ class FreeBSDSemaphore : public Semaphore { ...@@ -608,11 +608,13 @@ class FreeBSDSemaphore : public Semaphore {
virtual ~FreeBSDSemaphore() { sem_destroy(&sem_); } virtual ~FreeBSDSemaphore() { sem_destroy(&sem_); }
virtual void Wait(); virtual void Wait();
virtual bool Wait(int timeout);
virtual void Signal() { sem_post(&sem_); } virtual void Signal() { sem_post(&sem_); }
private: private:
sem_t sem_; sem_t sem_;
}; };
void FreeBSDSemaphore::Wait() { void FreeBSDSemaphore::Wait() {
while (true) { while (true) {
int result = sem_wait(&sem_); int result = sem_wait(&sem_);
...@@ -621,6 +623,39 @@ void FreeBSDSemaphore::Wait() { ...@@ -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) { Semaphore* OS::CreateSemaphore(int count) {
return new FreeBSDSemaphore(count); return new FreeBSDSemaphore(count);
} }
......
...@@ -592,11 +592,13 @@ class LinuxSemaphore : public Semaphore { ...@@ -592,11 +592,13 @@ class LinuxSemaphore : public Semaphore {
virtual ~LinuxSemaphore() { sem_destroy(&sem_); } virtual ~LinuxSemaphore() { sem_destroy(&sem_); }
virtual void Wait(); virtual void Wait();
virtual bool Wait(int timeout);
virtual void Signal() { sem_post(&sem_); } virtual void Signal() { sem_post(&sem_); }
private: private:
sem_t sem_; sem_t sem_;
}; };
void LinuxSemaphore::Wait() { void LinuxSemaphore::Wait() {
while (true) { while (true) {
int result = sem_wait(&sem_); int result = sem_wait(&sem_);
...@@ -605,6 +607,39 @@ void LinuxSemaphore::Wait() { ...@@ -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) { Semaphore* OS::CreateSemaphore(int count) {
return new LinuxSemaphore(count); return new LinuxSemaphore(count);
} }
......
...@@ -565,6 +565,8 @@ class MacOSSemaphore : public Semaphore { ...@@ -565,6 +565,8 @@ class MacOSSemaphore : public Semaphore {
// platform is not needed here. // platform is not needed here.
void Wait() { semaphore_wait(semaphore_); } void Wait() { semaphore_wait(semaphore_); }
bool Wait(int timeout);
void Signal() { semaphore_signal(semaphore_); } void Signal() { semaphore_signal(semaphore_); }
private: private:
...@@ -572,6 +574,14 @@ class MacOSSemaphore : public Semaphore { ...@@ -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) { Semaphore* OS::CreateSemaphore(int count) {
return new MacOSSemaphore(count); return new MacOSSemaphore(count);
} }
......
...@@ -1538,6 +1538,12 @@ class Win32Semaphore : public Semaphore { ...@@ -1538,6 +1538,12 @@ class Win32Semaphore : public Semaphore {
WaitForSingleObject(sem, INFINITE); 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() { void Signal() {
LONG dummy; LONG dummy;
ReleaseSemaphore(sem, 1, &dummy); ReleaseSemaphore(sem, 1, &dummy);
......
...@@ -410,10 +410,16 @@ class Semaphore { ...@@ -410,10 +410,16 @@ class Semaphore {
public: public:
virtual ~Semaphore() {} 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. // and then decrements the semaphore counter.
virtual void Wait() = 0; 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. // Increments the semaphore counter.
virtual void Signal() = 0; virtual void Signal() = 0;
}; };
......
...@@ -38,3 +38,26 @@ TEST(ShallowLock) { ...@@ -38,3 +38,26 @@ TEST(ShallowLock) {
CHECK_EQ(0, mutex->Unlock()); CHECK_EQ(0, mutex->Unlock());
delete mutex; 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