android5.1\external\chromium_org\v8\src\base\platform\semaphore.h
// Copyright 2013 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_BASE_PLATFORM_SEMAPHORE_H_
#define V8_BASE_PLATFORM_SEMAPHORE_H_
#include "src/base/lazy-instance.h"
#if V8_OS_WIN
#include "src/base/win32-headers.h"
#endif
#if V8_OS_MACOSX
#include <mach/semaphore.h> // NOLINT
#elif V8_OS_POSIX
#include <semaphore.h> // NOLINT
#endif
namespace v8 {
namespace base {
// Forward declarations.
class TimeDelta;
// ----------------------------------------------------------------------------
// Semaphore
//
// A semaphore object is a synchronization object that maintains a count. The
// count is decremented each time a thread completes a wait for the semaphore
// object and incremented each time a thread signals the semaphore. When the
// count reaches zero, threads waiting for the semaphore blocks until the
// count becomes non-zero.
class Semaphore FINAL {
public:
explicit Semaphore(int count);
~Semaphore();
// Increments the semaphore counter.
void Signal();
// Suspends the calling thread until the semaphore counter is non zero
// and then decrements the semaphore counter.
void Wait();
// Suspends the calling thread until the counter is non zero or the timeout
// time has passed. If timeout happens the return value is false and the
// counter is unchanged. Otherwise the semaphore counter is decremented and
// true is returned.
bool WaitFor(const TimeDelta& rel_time) WARN_UNUSED_RESULT;
#if V8_OS_MACOSX
typedef semaphore_t NativeHandle;
#elif V8_OS_POSIX
typedef sem_t NativeHandle;
#elif V8_OS_WIN
typedef HANDLE NativeHandle;
#endif
NativeHandle& native_handle() {
return native_handle_;
}
const NativeHandle& native_handle() const {
return native_handle_;
}
private:
NativeHandle native_handle_;
DISALLOW_COPY_AND_ASSIGN(Semaphore);
};
// POD Semaphore initialized lazily (i.e. the first time Pointer() is called).
// Usage:
// // The following semaphore starts at 0.
// static LazySemaphore<0>::type my_semaphore = LAZY_SEMAPHORE_INITIALIZER;
//
// void my_function() {
// // Do something with my_semaphore.Pointer().
// }
//
template <int N>
struct CreateSemaphoreTrait {
static Semaphore* Create() {
return new Semaphore(N);
}
};
template <int N>
struct LazySemaphore {
typedef typename LazyDynamicInstance<Semaphore, CreateSemaphoreTrait<N>,
ThreadSafeInitOnceTrait>::type type;
};
#define LAZY_SEMAPHORE_INITIALIZER LAZY_DYNAMIC_INSTANCE_INITIALIZER
} } // namespace v8::base
#endif // V8_BASE_PLATFORM_SEMAPHORE_H_
android5.1\external\chromium_org\v8\src\base\platform\semaphore.cc
// Copyright 2013 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/base/platform/semaphore.h"
#if V8_OS_MACOSX
#include <mach/mach_init.h>
#include <mach/task.h>
#endif
#include <errno.h>
#include "src/base/logging.h"
#include "src/base/platform/elapsed-timer.h"
#include "src/base/platform/time.h"
namespace v8 {
namespace base {
#if V8_OS_MACOSX
Semaphore::Semaphore(int count) {
kern_return_t result = semaphore_create(
mach_task_self(), &native_handle_, SYNC_POLICY_FIFO, count);
DCHECK_EQ(KERN_SUCCESS, result);
USE(result);
}
Semaphore::~Semaphore() {
kern_return_t result = semaphore_destroy(mach_task_self(), native_handle_);
DCHECK_EQ(KERN_SUCCESS, result);
USE(result);
}
void Semaphore::Signal() {
kern_return_t result = semaphore_signal(native_handle_);
DCHECK_EQ(KERN_SUCCESS, result);
USE(result);
}
void Semaphore::Wait() {
while (true) {
kern_return_t result = semaphore_wait(native_handle_);
if (result == KERN_SUCCESS) return; // Semaphore was signalled.
DCHECK_EQ(KERN_ABORTED, result);
}
}
bool Semaphore::WaitFor(const TimeDelta& rel_time) {
TimeTicks now = TimeTicks::Now();
TimeTicks end = now + rel_time;
while (true) {
mach_timespec_t ts;
if (now >= end) {
// Return immediately if semaphore was not signalled.
ts.tv_sec = 0;
ts.tv_nsec = 0;
} else {
ts = (end - now).ToMachTimespec();
}
kern_return_t result = semaphore_timedwait(native_handle_, ts);
if (result == KERN_SUCCESS) return true; // Semaphore was signalled.
if (result == KERN_OPERATION_TIMED_OUT) return false; // Timeout.
DCHECK_EQ(KERN_ABORTED, result);
now = TimeTicks::Now();
}
}
#elif V8_OS_POSIX
Semaphore::Semaphore(int count) {
DCHECK(count >= 0);
int result = sem_init(&native_handle_, 0, count);
DCHECK_EQ(0, result);
USE(result);
}
Semaphore::~Semaphore() {
int result = sem_destroy(&native_handle_);
DCHECK_EQ(0, result);
USE(result);
}
void Semaphore::Signal() {
int result = sem_post(&native_handle_);
DCHECK_EQ(0, result);
USE(result);
}
void Semaphore::Wait() {
while (true) {
int result = sem_wait(&native_handle_);
if (result == 0) return; // Semaphore was signalled.
// Signal caused spurious wakeup.
DCHECK_EQ(-1, result);
DCHECK_EQ(EINTR, errno);
}
}
bool Semaphore::WaitFor(const TimeDelta& rel_time) {
#if V8_OS_NACL
// PNaCL doesn't support sem_timedwait, do ugly busy waiting.
ElapsedTimer timer;
timer.Start();
do {
int result = sem_trywait(&native_handle_);
if (result == 0) return true;
DCHECK(errno == EAGAIN || errno == EINTR);
} while (!timer.HasExpired(rel_time));
return false;
#else
// Compute the time for end of timeout.
const Time time = Time::NowFromSystemTime() + rel_time;
const struct timespec ts = time.ToTimespec();
// Wait for semaphore signalled or timeout.
while (true) {
int result = sem_timedwait(&native_handle_, &ts);
if (result == 0) return true; // Semaphore was signalled.
#if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
if (result > 0) {
// sem_timedwait in glibc prior to 2.3.4 returns the errno instead of -1.
errno = result;
result = -1;
}
#endif
if (result == -1 && errno == ETIMEDOUT) {
// Timed out while waiting for semaphore.
return false;
}
// Signal caused spurious wakeup.
DCHECK_EQ(-1, result);
DCHECK_EQ(EINTR, errno);
}
#endif
}
#elif V8_OS_WIN
Semaphore::Semaphore(int count) {
DCHECK(count >= 0);
native_handle_ = ::CreateSemaphoreA(NULL, count, 0x7fffffff, NULL);
DCHECK(native_handle_ != NULL);
}
Semaphore::~Semaphore() {
BOOL result = CloseHandle(native_handle_);
DCHECK(result);
USE(result);
}
void Semaphore::Signal() {
LONG dummy;
BOOL result = ReleaseSemaphore(native_handle_, 1, &dummy);
DCHECK(result);
USE(result);
}
void Semaphore::Wait() {
DWORD result = WaitForSingleObject(native_handle_, INFINITE);
DCHECK(result == WAIT_OBJECT_0);
USE(result);
}
bool Semaphore::WaitFor(const TimeDelta& rel_time) {
TimeTicks now = TimeTicks::Now();
TimeTicks end = now + rel_time;
while (true) {
int64_t msec = (end - now).InMilliseconds();
if (msec >= static_cast<int64_t>(INFINITE)) {
DWORD result = WaitForSingleObject(native_handle_, INFINITE - 1);
if (result == WAIT_OBJECT_0) {
return true;
}
DCHECK(result == WAIT_TIMEOUT);
now = TimeTicks::Now();
} else {
DWORD result = WaitForSingleObject(
native_handle_, (msec < 0) ? 0 : static_cast<DWORD>(msec));
if (result == WAIT_TIMEOUT) {
return false;
}
DCHECK(result == WAIT_OBJECT_0);
return true;
}
}
}
#endif // V8_OS_MACOSX
} } // namespace v8::base
单元测试
android5.1\external\chromium_org\v8\src\base\platform\semaphore-unittest.cc
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <cstring>
#include "src/base/platform/platform.h"
#include "src/base/platform/semaphore.h"
#include "src/base/platform/time.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace v8 {
namespace base {
namespace {
static const char kAlphabet[] = "XKOAD";
static const size_t kAlphabetSize = sizeof(kAlphabet) - 1;
static const size_t kBufferSize = 987; // GCD(buffer size, alphabet size) = 1
static const size_t kDataSize = kBufferSize * kAlphabetSize * 10;
class ProducerThread FINAL : public Thread {
public:
ProducerThread(char* buffer, Semaphore* free_space, Semaphore* used_space)
: Thread(Options("ProducerThread")),
buffer_(buffer),
free_space_(free_space),
used_space_(used_space) {}
virtual ~ProducerThread() {}
virtual void Run() OVERRIDE {
for (size_t n = 0; n < kDataSize; ++n) {
free_space_->Wait();
buffer_[n % kBufferSize] = kAlphabet[n % kAlphabetSize];
used_space_->Signal();
}
}
private:
char* buffer_;
Semaphore* const free_space_;
Semaphore* const used_space_;
};
class ConsumerThread FINAL : public Thread {
public:
ConsumerThread(const char* buffer, Semaphore* free_space,
Semaphore* used_space)
: Thread(Options("ConsumerThread")),
buffer_(buffer),
free_space_(free_space),
used_space_(used_space) {}
virtual ~ConsumerThread() {}
virtual void Run() OVERRIDE {
for (size_t n = 0; n < kDataSize; ++n) {
used_space_->Wait();
EXPECT_EQ(kAlphabet[n % kAlphabetSize], buffer_[n % kBufferSize]);
free_space_->Signal();
}
}
private:
const char* buffer_;
Semaphore* const free_space_;
Semaphore* const used_space_;
};
class WaitAndSignalThread FINAL : public Thread {
public:
explicit WaitAndSignalThread(Semaphore* semaphore)
: Thread(Options("WaitAndSignalThread")), semaphore_(semaphore) {}
virtual ~WaitAndSignalThread() {}
virtual void Run() OVERRIDE {
for (int n = 0; n < 100; ++n) {
semaphore_->Wait();
ASSERT_FALSE(semaphore_->WaitFor(TimeDelta::FromMicroseconds(1)));
semaphore_->Signal();
}
}
private:
Semaphore* const semaphore_;
};
} // namespace
TEST(Semaphore, ProducerConsumer) {
char buffer[kBufferSize];
std::memset(buffer, 0, sizeof(buffer));
Semaphore free_space(kBufferSize);
Semaphore used_space(0);
ProducerThread producer_thread(buffer, &free_space, &used_space);
ConsumerThread consumer_thread(buffer, &free_space, &used_space);
producer_thread.Start();
consumer_thread.Start();
producer_thread.Join();
consumer_thread.Join();
}
TEST(Semaphore, WaitAndSignal) {
Semaphore semaphore(0);
WaitAndSignalThread t1(&semaphore);
WaitAndSignalThread t2(&semaphore);
t1.Start();
t2.Start();
// Make something available.
semaphore.Signal();
t1.Join();
t2.Join();
semaphore.Wait();
EXPECT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(1)));
}
TEST(Semaphore, WaitFor) {
Semaphore semaphore(0);
// Semaphore not signalled - timeout.
ASSERT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(0)));
ASSERT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(100)));
ASSERT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(1000)));
// Semaphore signalled - no timeout.
semaphore.Signal();
ASSERT_TRUE(semaphore.WaitFor(TimeDelta::FromMicroseconds(0)));
semaphore.Signal();
ASSERT_TRUE(semaphore.WaitFor(TimeDelta::FromMicroseconds(100)));
semaphore.Signal();
ASSERT_TRUE(semaphore.WaitFor(TimeDelta::FromMicroseconds(1000)));
}
} // namespace base
} // namespace v8
硬件中使用的Semaphore
android5.1\hardware\ti\omap4-aah\libtiutils\Semaphore.cpp
/*
* Copyright (C) Texas Instruments - http://www.ti.com/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Semaphore.h"
#include "ErrorUtils.h"
#include <utils/Log.h>
#include <time.h>
namespace Ti {
namespace Utils {
/**
@brief Constructor for the semaphore class
@param none
@return none
*/
Semaphore::Semaphore()
{
///Initialize the semaphore to NULL
mSemaphore = NULL;
}
/**
@brief Destructor of the semaphore class
@param none
@return none
*/
Semaphore::~Semaphore()
{
Release();
}
/**
@brief: Releases semaphore
@param count >=0
@return NO_ERROR On Success
@return One of the android error codes based on semaphore de-initialization
*/
status_t Semaphore::Release()
{
int status = 0;
///Destroy only if the semaphore has been created
if(mSemaphore)
{
status = sem_destroy(mSemaphore);
free(mSemaphore);
mSemaphore = NULL;
}
///Initialize the semaphore and return the status
return ErrorUtils::posixToAndroidError(status);
}
/**
@brief Create the semaphore with initial count value
@param count >=0
@return NO_ERROR On Success
@return NO_MEMORY If unable to allocate memory for the semaphore
@return BAD_VALUE If an invalid count value is passed (<0)
@return One of the android error codes based on semaphore initialization
*/
status_t Semaphore::Create(int count)
{
status_t ret = NO_ERROR;
///count cannot be less than zero
if(count<0)
{
return BAD_VALUE;
}
ret = Release();
if ( NO_ERROR != ret )
{
return ret;
}
///allocate memory for the semaphore
mSemaphore = (sem_t*)malloc(sizeof(sem_t)) ;
///if memory is unavailable, return error
if(!mSemaphore)
{
return NO_MEMORY;
}
///Initialize the semaphore and return the status
return ErrorUtils::posixToAndroidError(sem_init(mSemaphore, 0x00, count));
}
/**
@brief Wait operation
@param none
@return BAD_VALUE if the semaphore is not initialized
@return NO_ERROR On success
@return One of the android error codes based on semaphore wait operation
*/
status_t Semaphore::Wait()
{
///semaphore should have been created first
if(!mSemaphore)
{
return BAD_VALUE;
}
///Wait and return the status after signalling
return ErrorUtils::posixToAndroidError(sem_wait(mSemaphore));
}
/**
@brief Signal operation
@param none
@return BAD_VALUE if the semaphore is not initialized
@return NO_ERROR On success
@return One of the android error codes based on semaphore signal operation
*/
status_t Semaphore::Signal()
{
///semaphore should have been created first
if(!mSemaphore)
{
return BAD_VALUE;
}
///Post to the semaphore
return ErrorUtils::posixToAndroidError(sem_post(mSemaphore));
}
/**
@brief Current semaphore count
@param none
@return Current count value of the semaphore
*/
int Semaphore::Count()
{
int val;
///semaphore should have been created first
if(!mSemaphore)
{
return BAD_VALUE;
}
///get the value of the semaphore
sem_getvalue(mSemaphore, &val);
return val;
}
/**
@brief Wait operation with a timeout
@param timeoutMicroSecs The timeout period in micro seconds
@return BAD_VALUE if the semaphore is not initialized
@return NO_ERROR On success
@return One of the android error codes based on semaphore wait operation
*/
status_t Semaphore::WaitTimeout(int timeoutMicroSecs)
{
status_t ret = NO_ERROR;
struct timespec timeSpec;
struct timeval currentTime;
///semaphore should have been created first
if( NULL == mSemaphore)
{
ret = BAD_VALUE;
}
if ( NO_ERROR == ret )
{
///setup the timeout values - timeout is specified in seconds and nanoseconds
gettimeofday(¤tTime, NULL);
timeSpec.tv_sec = currentTime.tv_sec;
timeSpec.tv_nsec = currentTime.tv_usec * 1000;
timeSpec.tv_sec += ( timeoutMicroSecs / 1000000 );
timeSpec.tv_nsec += ( timeoutMicroSecs % 1000000) * 1000;
///Wait for the timeout or signal and return the result based on whichever event occurred first
ret = sem_timedwait(mSemaphore, &timeSpec);
}
if ( NO_ERROR != ret )
{
Signal();
Create(0);
}
return ret;
}
} // namespace Utils
} // namespace Ti