|
Packit |
807167 |
/*************************************************************************************************
|
|
Packit |
807167 |
* Threading devices
|
|
Packit |
807167 |
* Copyright (C) 2009-2012 FAL Labs
|
|
Packit |
807167 |
* This file is part of Kyoto Cabinet.
|
|
Packit |
807167 |
* This program is free software: you can redistribute it and/or modify it under the terms of
|
|
Packit |
807167 |
* the GNU General Public License as published by the Free Software Foundation, either version
|
|
Packit |
807167 |
* 3 of the License, or any later version.
|
|
Packit |
807167 |
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
Packit |
807167 |
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
Packit |
807167 |
* See the GNU General Public License for more details.
|
|
Packit |
807167 |
* You should have received a copy of the GNU General Public License along with this program.
|
|
Packit |
807167 |
* If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
807167 |
*************************************************************************************************/
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
#include "kcthread.h"
|
|
Packit |
807167 |
#include "myconf.h"
|
|
Packit |
807167 |
|
|
Packit |
807167 |
namespace kyotocabinet { // common namespace
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Constants for implementation.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
namespace {
|
|
Packit |
807167 |
const uint32_t LOCKBUSYLOOP = 8192; ///< threshold of busy loop and sleep for locking
|
|
Packit |
807167 |
const size_t LOCKSEMNUM = 256; ///< number of semaphores for locking
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Thread internal.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
struct ThreadCore {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
::HANDLE th; ///< handle
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
::pthread_t th; ///< identifier
|
|
Packit |
807167 |
bool alive; ///< alive flag
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
};
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* CondVar internal.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
struct CondVarCore {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
::CRITICAL_SECTION mutex; ///< mutex
|
|
Packit |
807167 |
uint32_t wait; ///< wait count
|
|
Packit |
807167 |
uint32_t wake; ///< wake count
|
|
Packit |
807167 |
::HANDLE sev; ///< signal event handle
|
|
Packit |
807167 |
::HANDLE fev; ///< finish event handle
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
::pthread_cond_t cond; ///< condition
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
};
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Call the running thread.
|
|
Packit |
807167 |
* @param arg the thread.
|
|
Packit |
807167 |
* @return always NULL.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
static ::DWORD threadrun(::LPVOID arg);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
static void* threadrun(void* arg);
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Default constructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
Thread::Thread() : opq_(NULL) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
ThreadCore* core = new ThreadCore;
|
|
Packit |
807167 |
core->th = NULL;
|
|
Packit |
807167 |
opq_ = (void*)core;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
ThreadCore* core = new ThreadCore;
|
|
Packit |
807167 |
core->alive = false;
|
|
Packit |
807167 |
opq_ = (void*)core;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Destructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
Thread::~Thread() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
ThreadCore* core = (ThreadCore*)opq_;
|
|
Packit |
807167 |
if (core->th) join();
|
|
Packit |
807167 |
delete core;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
ThreadCore* core = (ThreadCore*)opq_;
|
|
Packit |
807167 |
if (core->alive) join();
|
|
Packit |
807167 |
delete core;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Start the thread.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void Thread::start() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
ThreadCore* core = (ThreadCore*)opq_;
|
|
Packit |
807167 |
if (core->th) throw std::invalid_argument("already started");
|
|
Packit |
807167 |
::DWORD id;
|
|
Packit |
807167 |
core->th = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadrun, this, 0, &id;;
|
|
Packit |
807167 |
if (!core->th) throw std::runtime_error("CreateThread");
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
ThreadCore* core = (ThreadCore*)opq_;
|
|
Packit |
807167 |
if (core->alive) throw std::invalid_argument("already started");
|
|
Packit |
807167 |
if (::pthread_create(&core->th, NULL, threadrun, this) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_create");
|
|
Packit |
807167 |
core->alive = true;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Wait for the thread to finish.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void Thread::join() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
ThreadCore* core = (ThreadCore*)opq_;
|
|
Packit |
807167 |
if (!core->th) throw std::invalid_argument("not alive");
|
|
Packit |
807167 |
if (::WaitForSingleObject(core->th, INFINITE) == WAIT_FAILED)
|
|
Packit |
807167 |
throw std::runtime_error("WaitForSingleObject");
|
|
Packit |
807167 |
::CloseHandle(core->th);
|
|
Packit |
807167 |
core->th = NULL;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
ThreadCore* core = (ThreadCore*)opq_;
|
|
Packit |
807167 |
if (!core->alive) throw std::invalid_argument("not alive");
|
|
Packit |
807167 |
core->alive = false;
|
|
Packit |
807167 |
if (::pthread_join(core->th, NULL) != 0) throw std::runtime_error("pthread_join");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Put the thread in the detached state.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void Thread::detach() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
ThreadCore* core = (ThreadCore*)opq_;
|
|
Packit |
807167 |
if (!core->alive) throw std::invalid_argument("not alive");
|
|
Packit |
807167 |
core->alive = false;
|
|
Packit |
807167 |
if (::pthread_detach(core->th) != 0) throw std::runtime_error("pthread_detach");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Terminate the running thread.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void Thread::exit() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::ExitThread(0);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_exit(NULL);
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Yield the processor from the current thread.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void Thread::yield() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::Sleep(0);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::sched_yield();
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Chill the processor by suspending execution for a quick moment.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void Thread::chill() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::Sleep(21);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
struct ::timespec req;
|
|
Packit |
807167 |
req.tv_sec = 0;
|
|
Packit |
807167 |
req.tv_nsec = 21 * 1000 * 1000;
|
|
Packit |
807167 |
::nanosleep(&req, NULL);
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Suspend execution of the current thread.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
bool Thread::sleep(double sec) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(sec >= 0.0);
|
|
Packit |
807167 |
if (sec <= 0.0) {
|
|
Packit |
807167 |
yield();
|
|
Packit |
807167 |
return true;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
if (sec > INT32MAX) sec = INT32MAX;
|
|
Packit |
807167 |
::Sleep(sec * 1000);
|
|
Packit |
807167 |
return true;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(sec >= 0.0);
|
|
Packit |
807167 |
if (sec <= 0.0) {
|
|
Packit |
807167 |
yield();
|
|
Packit |
807167 |
return true;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
if (sec > INT32MAX) sec = INT32MAX;
|
|
Packit |
807167 |
double integ, fract;
|
|
Packit |
807167 |
fract = std::modf(sec, &integ);
|
|
Packit |
807167 |
struct ::timespec req, rem;
|
|
Packit |
807167 |
req.tv_sec = (time_t)integ;
|
|
Packit |
807167 |
req.tv_nsec = (long)(fract * 999999000);
|
|
Packit |
807167 |
while (::nanosleep(&req, &rem) != 0) {
|
|
Packit |
807167 |
if (errno != EINTR) return false;
|
|
Packit |
807167 |
req = rem;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
return true;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get the hash value of the current thread.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
int64_t Thread::hash() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
return ::GetCurrentThreadId();
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
pthread_t tid = pthread_self();
|
|
Packit |
807167 |
int64_t num;
|
|
Packit |
807167 |
if (sizeof(tid) == sizeof(num)) {
|
|
Packit |
807167 |
std::memcpy(&num, &tid, sizeof(num));
|
|
Packit |
807167 |
} else if (sizeof(tid) == sizeof(int32_t)) {
|
|
Packit |
807167 |
uint32_t inum;
|
|
Packit |
807167 |
std::memcpy(&inum, &tid, sizeof(inum));
|
|
Packit |
807167 |
num = inum;
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
num = hashmurmur(&tid, sizeof(tid));
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
return num & INT64MAX;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Call the running thread.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
static ::DWORD threadrun(::LPVOID arg) {
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
Thread* thread = (Thread*)arg;
|
|
Packit |
807167 |
thread->run();
|
|
Packit |
807167 |
return NULL;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
static void* threadrun(void* arg) {
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
Thread* thread = (Thread*)arg;
|
|
Packit |
807167 |
thread->run();
|
|
Packit |
807167 |
return NULL;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Default constructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
Mutex::Mutex() : opq_(NULL) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::CRITICAL_SECTION* mutex = new ::CRITICAL_SECTION;
|
|
Packit |
807167 |
::InitializeCriticalSection(mutex);
|
|
Packit |
807167 |
opq_ = (void*)mutex;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_mutex_t* mutex = new ::pthread_mutex_t;
|
|
Packit |
807167 |
if (::pthread_mutex_init(mutex, NULL) != 0) throw std::runtime_error("pthread_mutex_init");
|
|
Packit |
807167 |
opq_ = (void*)mutex;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Constructor with the specifications.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
Mutex::Mutex(Type type) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::CRITICAL_SECTION* mutex = new ::CRITICAL_SECTION;
|
|
Packit |
807167 |
::InitializeCriticalSection(mutex);
|
|
Packit |
807167 |
opq_ = (void*)mutex;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_mutexattr_t attr;
|
|
Packit |
807167 |
if (::pthread_mutexattr_init(&attr) != 0) throw std::runtime_error("pthread_mutexattr_init");
|
|
Packit |
807167 |
switch (type) {
|
|
Packit |
807167 |
case FAST: {
|
|
Packit |
807167 |
break;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
case ERRORCHECK: {
|
|
Packit |
807167 |
if (::pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_mutexattr_settype");
|
|
Packit |
807167 |
break;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
case RECURSIVE: {
|
|
Packit |
807167 |
if (::pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_mutexattr_settype");
|
|
Packit |
807167 |
break;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
::pthread_mutex_t* mutex = new ::pthread_mutex_t;
|
|
Packit |
807167 |
if (::pthread_mutex_init(mutex, &attr) != 0) throw std::runtime_error("pthread_mutex_init");
|
|
Packit |
807167 |
::pthread_mutexattr_destroy(&attr);
|
|
Packit |
807167 |
opq_ = (void*)mutex;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Destructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
Mutex::~Mutex() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::CRITICAL_SECTION* mutex = (::CRITICAL_SECTION*)opq_;
|
|
Packit |
807167 |
::DeleteCriticalSection(mutex);
|
|
Packit |
807167 |
delete mutex;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_mutex_t* mutex = (::pthread_mutex_t*)opq_;
|
|
Packit |
807167 |
::pthread_mutex_destroy(mutex);
|
|
Packit |
807167 |
delete mutex;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get the lock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void Mutex::lock() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::CRITICAL_SECTION* mutex = (::CRITICAL_SECTION*)opq_;
|
|
Packit |
807167 |
::EnterCriticalSection(mutex);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_mutex_t* mutex = (::pthread_mutex_t*)opq_;
|
|
Packit |
807167 |
if (::pthread_mutex_lock(mutex) != 0) throw std::runtime_error("pthread_mutex_lock");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Try to get the lock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
bool Mutex::lock_try() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::CRITICAL_SECTION* mutex = (::CRITICAL_SECTION*)opq_;
|
|
Packit |
807167 |
if (!::TryEnterCriticalSection(mutex)) return false;
|
|
Packit |
807167 |
return true;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_mutex_t* mutex = (::pthread_mutex_t*)opq_;
|
|
Packit |
807167 |
int32_t ecode = ::pthread_mutex_trylock(mutex);
|
|
Packit |
807167 |
if (ecode == 0) return true;
|
|
Packit |
807167 |
if (ecode != EBUSY) throw std::runtime_error("pthread_mutex_trylock");
|
|
Packit |
807167 |
return false;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Try to get the lock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
bool Mutex::lock_try(double sec) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_) || defined(_SYS_CYGWIN_) || defined(_SYS_MACOSX_)
|
|
Packit |
807167 |
_assert_(sec >= 0.0);
|
|
Packit |
807167 |
if (lock_try()) return true;
|
|
Packit |
807167 |
double end = time() + sec;
|
|
Packit |
807167 |
Thread::yield();
|
|
Packit |
807167 |
uint32_t wcnt = 0;
|
|
Packit |
807167 |
while (!lock_try()) {
|
|
Packit |
807167 |
if (time() > end) return false;
|
|
Packit |
807167 |
if (wcnt >= LOCKBUSYLOOP) {
|
|
Packit |
807167 |
Thread::chill();
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
Thread::yield();
|
|
Packit |
807167 |
wcnt++;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
return true;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(sec >= 0.0);
|
|
Packit |
807167 |
::pthread_mutex_t* mutex = (::pthread_mutex_t*)opq_;
|
|
Packit |
807167 |
struct ::timeval tv;
|
|
Packit |
807167 |
struct ::timespec ts;
|
|
Packit |
807167 |
if (::gettimeofday(&tv, NULL) == 0) {
|
|
Packit |
807167 |
double integ;
|
|
Packit |
807167 |
double fract = std::modf(sec, &integ);
|
|
Packit |
807167 |
ts.tv_sec = tv.tv_sec + (time_t)integ;
|
|
Packit |
807167 |
ts.tv_nsec = (long)(tv.tv_usec * 1000.0 + fract * 999999000);
|
|
Packit |
807167 |
if (ts.tv_nsec >= 1000000000) {
|
|
Packit |
807167 |
ts.tv_nsec -= 1000000000;
|
|
Packit |
807167 |
ts.tv_sec++;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
ts.tv_sec = std::time(NULL) + 1;
|
|
Packit |
807167 |
ts.tv_nsec = 0;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
int32_t ecode = ::pthread_mutex_timedlock(mutex, &ts);
|
|
Packit |
807167 |
if (ecode == 0) return true;
|
|
Packit |
807167 |
if (ecode != ETIMEDOUT) throw std::runtime_error("pthread_mutex_timedlock");
|
|
Packit |
807167 |
return false;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Release the lock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void Mutex::unlock() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::CRITICAL_SECTION* mutex = (::CRITICAL_SECTION*)opq_;
|
|
Packit |
807167 |
::LeaveCriticalSection(mutex);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_mutex_t* mutex = (::pthread_mutex_t*)opq_;
|
|
Packit |
807167 |
if (::pthread_mutex_unlock(mutex) != 0) throw std::runtime_error("pthread_mutex_unlock");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* SlottedMutex internal.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
struct SlottedMutexCore {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
::CRITICAL_SECTION* mutexes; ///< primitives
|
|
Packit |
807167 |
size_t slotnum; ///< number of slots
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
::pthread_mutex_t* mutexes; ///< primitives
|
|
Packit |
807167 |
size_t slotnum; ///< number of slots
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
};
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Constructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
SlottedMutex::SlottedMutex(size_t slotnum) : opq_(NULL) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedMutexCore* core = new SlottedMutexCore;
|
|
Packit |
807167 |
::CRITICAL_SECTION* mutexes = new ::CRITICAL_SECTION[slotnum];
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
::InitializeCriticalSection(mutexes + i);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
core->mutexes = mutexes;
|
|
Packit |
807167 |
core->slotnum = slotnum;
|
|
Packit |
807167 |
opq_ = (void*)core;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedMutexCore* core = new SlottedMutexCore;
|
|
Packit |
807167 |
::pthread_mutex_t* mutexes = new ::pthread_mutex_t[slotnum];
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
if (::pthread_mutex_init(mutexes + i, NULL) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_mutex_init");
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
core->mutexes = mutexes;
|
|
Packit |
807167 |
core->slotnum = slotnum;
|
|
Packit |
807167 |
opq_ = (void*)core;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Destructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
SlottedMutex::~SlottedMutex() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedMutexCore* core = (SlottedMutexCore*)opq_;
|
|
Packit |
807167 |
::CRITICAL_SECTION* mutexes = core->mutexes;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
::DeleteCriticalSection(mutexes + i);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
delete[] mutexes;
|
|
Packit |
807167 |
delete core;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedMutexCore* core = (SlottedMutexCore*)opq_;
|
|
Packit |
807167 |
::pthread_mutex_t* mutexes = core->mutexes;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
::pthread_mutex_destroy(mutexes + i);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
delete[] mutexes;
|
|
Packit |
807167 |
delete core;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get the lock of a slot.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedMutex::lock(size_t idx) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedMutexCore* core = (SlottedMutexCore*)opq_;
|
|
Packit |
807167 |
::EnterCriticalSection(core->mutexes + idx);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedMutexCore* core = (SlottedMutexCore*)opq_;
|
|
Packit |
807167 |
if (::pthread_mutex_lock(core->mutexes + idx) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_mutex_lock");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Release the lock of a slot.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedMutex::unlock(size_t idx) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedMutexCore* core = (SlottedMutexCore*)opq_;
|
|
Packit |
807167 |
::LeaveCriticalSection(core->mutexes + idx);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedMutexCore* core = (SlottedMutexCore*)opq_;
|
|
Packit |
807167 |
if (::pthread_mutex_unlock(core->mutexes + idx) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_mutex_unlock");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get the locks of all slots.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedMutex::lock_all() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedMutexCore* core = (SlottedMutexCore*)opq_;
|
|
Packit |
807167 |
::CRITICAL_SECTION* mutexes = core->mutexes;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
::EnterCriticalSection(core->mutexes + i);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedMutexCore* core = (SlottedMutexCore*)opq_;
|
|
Packit |
807167 |
::pthread_mutex_t* mutexes = core->mutexes;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
if (::pthread_mutex_lock(mutexes + i) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_mutex_lock");
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Release the locks of all slots.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedMutex::unlock_all() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedMutexCore* core = (SlottedMutexCore*)opq_;
|
|
Packit |
807167 |
::CRITICAL_SECTION* mutexes = core->mutexes;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
::LeaveCriticalSection(mutexes + i);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedMutexCore* core = (SlottedMutexCore*)opq_;
|
|
Packit |
807167 |
::pthread_mutex_t* mutexes = core->mutexes;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
if (::pthread_mutex_unlock(mutexes + i) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_mutex_unlock");
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Default constructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
SpinLock::SpinLock() : opq_(NULL) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_spinlock_t* spin = new ::pthread_spinlock_t;
|
|
Packit |
807167 |
if (::pthread_spin_init(spin, PTHREAD_PROCESS_PRIVATE) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_spin_init");
|
|
Packit |
807167 |
opq_ = (void*)spin;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Destructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
SpinLock::~SpinLock() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_spinlock_t* spin = (::pthread_spinlock_t*)opq_;
|
|
Packit |
807167 |
::pthread_spin_destroy(spin);
|
|
Packit |
807167 |
delete spin;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get the lock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SpinLock::lock() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
uint32_t wcnt = 0;
|
|
Packit |
807167 |
while (::InterlockedCompareExchange((LONG*)&opq_, 1, 0) != 0) {
|
|
Packit |
807167 |
if (wcnt >= LOCKBUSYLOOP) {
|
|
Packit |
807167 |
Thread::chill();
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
Thread::yield();
|
|
Packit |
807167 |
wcnt++;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
uint32_t wcnt = 0;
|
|
Packit |
807167 |
while (!__sync_bool_compare_and_swap(&opq_, 0, 1)) {
|
|
Packit |
807167 |
if (wcnt >= LOCKBUSYLOOP) {
|
|
Packit |
807167 |
Thread::chill();
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
Thread::yield();
|
|
Packit |
807167 |
wcnt++;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_spinlock_t* spin = (::pthread_spinlock_t*)opq_;
|
|
Packit |
807167 |
if (::pthread_spin_lock(spin) != 0) throw std::runtime_error("pthread_spin_lock");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Try to get the lock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
bool SpinLock::lock_try() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
return ::InterlockedCompareExchange((LONG*)&opq_, 1, 0) == 0;
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
return __sync_bool_compare_and_swap(&opq_, 0, 1);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_spinlock_t* spin = (::pthread_spinlock_t*)opq_;
|
|
Packit |
807167 |
int32_t ecode = ::pthread_spin_trylock(spin);
|
|
Packit |
807167 |
if (ecode == 0) return true;
|
|
Packit |
807167 |
if (ecode != EBUSY) throw std::runtime_error("pthread_spin_trylock");
|
|
Packit |
807167 |
return false;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Release the lock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SpinLock::unlock() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::InterlockedExchange((LONG*)&opq_, 0);
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
__sync_lock_release(&opq_);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_spinlock_t* spin = (::pthread_spinlock_t*)opq_;
|
|
Packit |
807167 |
if (::pthread_spin_unlock(spin) != 0) throw std::runtime_error("pthread_spin_unlock");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* SlottedSpinLock internal.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
struct SlottedSpinLockCore {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_) || _KC_GCCATOMIC
|
|
Packit |
807167 |
uint32_t* locks; ///< primitives
|
|
Packit |
807167 |
size_t slotnum; ///< number of slots
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
::pthread_spinlock_t* spins; ///< primitives
|
|
Packit |
807167 |
size_t slotnum; ///< number of slots
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
};
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Constructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
SlottedSpinLock::SlottedSpinLock(size_t slotnum) : opq_(NULL) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_) || _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinLockCore* core = new SlottedSpinLockCore;
|
|
Packit |
807167 |
uint32_t* locks = new uint32_t[slotnum];
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
locks[i] = 0;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
core->locks = locks;
|
|
Packit |
807167 |
core->slotnum = slotnum;
|
|
Packit |
807167 |
opq_ = (void*)core;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinLockCore* core = new SlottedSpinLockCore;
|
|
Packit |
807167 |
::pthread_spinlock_t* spins = new ::pthread_spinlock_t[slotnum];
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
if (::pthread_spin_init(spins + i, PTHREAD_PROCESS_PRIVATE) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_spin_init");
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
core->spins = spins;
|
|
Packit |
807167 |
core->slotnum = slotnum;
|
|
Packit |
807167 |
opq_ = (void*)core;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Destructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
SlottedSpinLock::~SlottedSpinLock() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_) || _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
|
|
Packit |
807167 |
delete[] core->locks;
|
|
Packit |
807167 |
delete core;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
|
|
Packit |
807167 |
::pthread_spinlock_t* spins = core->spins;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
::pthread_spin_destroy(spins + i);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
delete[] spins;
|
|
Packit |
807167 |
delete core;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get the lock of a slot.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedSpinLock::lock(size_t idx) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
|
|
Packit |
807167 |
uint32_t* lock = core->locks + idx;
|
|
Packit |
807167 |
uint32_t wcnt = 0;
|
|
Packit |
807167 |
while (::InterlockedCompareExchange((LONG*)lock, 1, 0) != 0) {
|
|
Packit |
807167 |
if (wcnt >= LOCKBUSYLOOP) {
|
|
Packit |
807167 |
Thread::chill();
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
Thread::yield();
|
|
Packit |
807167 |
wcnt++;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
|
|
Packit |
807167 |
uint32_t* lock = core->locks + idx;
|
|
Packit |
807167 |
uint32_t wcnt = 0;
|
|
Packit |
807167 |
while (!__sync_bool_compare_and_swap(lock, 0, 1)) {
|
|
Packit |
807167 |
if (wcnt >= LOCKBUSYLOOP) {
|
|
Packit |
807167 |
Thread::chill();
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
Thread::yield();
|
|
Packit |
807167 |
wcnt++;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
|
|
Packit |
807167 |
if (::pthread_spin_lock(core->spins + idx) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_spin_lock");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Release the lock of a slot.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedSpinLock::unlock(size_t idx) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
|
|
Packit |
807167 |
uint32_t* lock = core->locks + idx;
|
|
Packit |
807167 |
::InterlockedExchange((LONG*)lock, 0);
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
|
|
Packit |
807167 |
uint32_t* lock = core->locks + idx;
|
|
Packit |
807167 |
__sync_lock_release(lock);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
|
|
Packit |
807167 |
if (::pthread_spin_unlock(core->spins + idx) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_spin_unlock");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get the locks of all slots.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedSpinLock::lock_all() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
|
|
Packit |
807167 |
uint32_t* locks = core->locks;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
uint32_t* lock = locks + i;
|
|
Packit |
807167 |
uint32_t wcnt = 0;
|
|
Packit |
807167 |
while (::InterlockedCompareExchange((LONG*)lock, 1, 0) != 0) {
|
|
Packit |
807167 |
if (wcnt >= LOCKBUSYLOOP) {
|
|
Packit |
807167 |
Thread::chill();
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
Thread::yield();
|
|
Packit |
807167 |
wcnt++;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
|
|
Packit |
807167 |
uint32_t* locks = core->locks;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
uint32_t* lock = locks + i;
|
|
Packit |
807167 |
uint32_t wcnt = 0;
|
|
Packit |
807167 |
while (!__sync_bool_compare_and_swap(lock, 0, 1)) {
|
|
Packit |
807167 |
if (wcnt >= LOCKBUSYLOOP) {
|
|
Packit |
807167 |
Thread::chill();
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
Thread::yield();
|
|
Packit |
807167 |
wcnt++;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
|
|
Packit |
807167 |
::pthread_spinlock_t* spins = core->spins;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
if (::pthread_spin_lock(spins + i) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_spin_lock");
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Release the locks of all slots.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedSpinLock::unlock_all() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
|
|
Packit |
807167 |
uint32_t* locks = core->locks;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
uint32_t* lock = locks + i;
|
|
Packit |
807167 |
::InterlockedExchange((LONG*)lock, 0);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
|
|
Packit |
807167 |
uint32_t* locks = core->locks;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
uint32_t* lock = locks + i;
|
|
Packit |
807167 |
__sync_lock_release(lock);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
|
|
Packit |
807167 |
::pthread_spinlock_t* spins = core->spins;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
if (::pthread_spin_unlock(spins + i) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_spin_unlock");
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Default constructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
RWLock::RWLock() : opq_(NULL) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SpinRWLock* rwlock = new SpinRWLock;
|
|
Packit |
807167 |
opq_ = (void*)rwlock;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_rwlock_t* rwlock = new ::pthread_rwlock_t;
|
|
Packit |
807167 |
if (::pthread_rwlock_init(rwlock, NULL) != 0) throw std::runtime_error("pthread_rwlock_init");
|
|
Packit |
807167 |
opq_ = (void*)rwlock;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Destructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
RWLock::~RWLock() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SpinRWLock* rwlock = (SpinRWLock*)opq_;
|
|
Packit |
807167 |
delete rwlock;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_rwlock_t* rwlock = (::pthread_rwlock_t*)opq_;
|
|
Packit |
807167 |
::pthread_rwlock_destroy(rwlock);
|
|
Packit |
807167 |
delete rwlock;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get the writer lock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void RWLock::lock_writer() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SpinRWLock* rwlock = (SpinRWLock*)opq_;
|
|
Packit |
807167 |
rwlock->lock_writer();
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_rwlock_t* rwlock = (::pthread_rwlock_t*)opq_;
|
|
Packit |
807167 |
if (::pthread_rwlock_wrlock(rwlock) != 0) throw std::runtime_error("pthread_rwlock_lock");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Try to get the writer lock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
bool RWLock::lock_writer_try() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SpinRWLock* rwlock = (SpinRWLock*)opq_;
|
|
Packit |
807167 |
return rwlock->lock_writer_try();
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_rwlock_t* rwlock = (::pthread_rwlock_t*)opq_;
|
|
Packit |
807167 |
int32_t ecode = ::pthread_rwlock_trywrlock(rwlock);
|
|
Packit |
807167 |
if (ecode == 0) return true;
|
|
Packit |
807167 |
if (ecode != EBUSY) throw std::runtime_error("pthread_rwlock_trylock");
|
|
Packit |
807167 |
return false;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get a reader lock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void RWLock::lock_reader() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SpinRWLock* rwlock = (SpinRWLock*)opq_;
|
|
Packit |
807167 |
rwlock->lock_reader();
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_rwlock_t* rwlock = (::pthread_rwlock_t*)opq_;
|
|
Packit |
807167 |
if (::pthread_rwlock_rdlock(rwlock) != 0) throw std::runtime_error("pthread_rwlock_lock");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Try to get a reader lock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
bool RWLock::lock_reader_try() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SpinRWLock* rwlock = (SpinRWLock*)opq_;
|
|
Packit |
807167 |
return rwlock->lock_reader_try();
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_rwlock_t* rwlock = (::pthread_rwlock_t*)opq_;
|
|
Packit |
807167 |
int32_t ecode = ::pthread_rwlock_tryrdlock(rwlock);
|
|
Packit |
807167 |
if (ecode == 0) return true;
|
|
Packit |
807167 |
if (ecode != EBUSY) throw std::runtime_error("pthread_rwlock_trylock");
|
|
Packit |
807167 |
return false;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Release the lock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void RWLock::unlock() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SpinRWLock* rwlock = (SpinRWLock*)opq_;
|
|
Packit |
807167 |
rwlock->unlock();
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_rwlock_t* rwlock = (::pthread_rwlock_t*)opq_;
|
|
Packit |
807167 |
if (::pthread_rwlock_unlock(rwlock) != 0) throw std::runtime_error("pthread_rwlock_unlock");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* SlottedRWLock internal.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
struct SlottedRWLockCore {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
RWLock* rwlocks; ///< primitives
|
|
Packit |
807167 |
size_t slotnum; ///< number of slots
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
::pthread_rwlock_t* rwlocks; ///< primitives
|
|
Packit |
807167 |
size_t slotnum; ///< number of slots
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
};
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Constructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
SlottedRWLock::SlottedRWLock(size_t slotnum) : opq_(NULL) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedRWLockCore* core = new SlottedRWLockCore;
|
|
Packit |
807167 |
RWLock* rwlocks = new RWLock[slotnum];
|
|
Packit |
807167 |
core->rwlocks = rwlocks;
|
|
Packit |
807167 |
core->slotnum = slotnum;
|
|
Packit |
807167 |
opq_ = (void*)core;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedRWLockCore* core = new SlottedRWLockCore;
|
|
Packit |
807167 |
::pthread_rwlock_t* rwlocks = new ::pthread_rwlock_t[slotnum];
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
if (::pthread_rwlock_init(rwlocks + i, NULL) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_rwlock_init");
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
core->rwlocks = rwlocks;
|
|
Packit |
807167 |
core->slotnum = slotnum;
|
|
Packit |
807167 |
opq_ = (void*)core;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Destructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
SlottedRWLock::~SlottedRWLock() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
|
|
Packit |
807167 |
delete[] core->rwlocks;
|
|
Packit |
807167 |
delete core;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
|
|
Packit |
807167 |
::pthread_rwlock_t* rwlocks = core->rwlocks;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
::pthread_rwlock_destroy(rwlocks + i);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
delete[] rwlocks;
|
|
Packit |
807167 |
delete core;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get the writer lock of a slot.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedRWLock::lock_writer(size_t idx) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
|
|
Packit |
807167 |
core->rwlocks[idx].lock_writer();
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
|
|
Packit |
807167 |
if (::pthread_rwlock_wrlock(core->rwlocks + idx) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_rwlock_wrlock");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get the reader lock of a slot.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedRWLock::lock_reader(size_t idx) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
|
|
Packit |
807167 |
core->rwlocks[idx].lock_reader();
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
|
|
Packit |
807167 |
if (::pthread_rwlock_rdlock(core->rwlocks + idx) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_rwlock_rdlock");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Release the lock of a slot.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedRWLock::unlock(size_t idx) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
|
|
Packit |
807167 |
core->rwlocks[idx].unlock();
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
|
|
Packit |
807167 |
if (::pthread_rwlock_unlock(core->rwlocks + idx) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_rwlock_unlock");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get the writer locks of all slots.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedRWLock::lock_writer_all() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
|
|
Packit |
807167 |
RWLock* rwlocks = core->rwlocks;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
rwlocks[i].lock_writer();
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
|
|
Packit |
807167 |
::pthread_rwlock_t* rwlocks = core->rwlocks;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
if (::pthread_rwlock_wrlock(rwlocks + i) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_rwlock_wrlock");
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get the reader locks of all slots.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedRWLock::lock_reader_all() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
|
|
Packit |
807167 |
RWLock* rwlocks = core->rwlocks;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
rwlocks[i].lock_reader();
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
|
|
Packit |
807167 |
::pthread_rwlock_t* rwlocks = core->rwlocks;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
if (::pthread_rwlock_rdlock(rwlocks + i) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_rwlock_rdlock");
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Release the locks of all slots.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedRWLock::unlock_all() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
|
|
Packit |
807167 |
RWLock* rwlocks = core->rwlocks;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
rwlocks[i].unlock();
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
|
|
Packit |
807167 |
::pthread_rwlock_t* rwlocks = core->rwlocks;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
if (::pthread_rwlock_unlock(rwlocks + i) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_rwlock_unlock");
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* SpinRWLock internal.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
struct SpinRWLockCore {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
LONG sem; ///< semaphore
|
|
Packit |
807167 |
uint32_t cnt; ///< count of threads
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
int32_t sem; ///< semaphore
|
|
Packit |
807167 |
uint32_t cnt; ///< count of threads
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
::pthread_spinlock_t sem; ///< semaphore
|
|
Packit |
807167 |
uint32_t cnt; ///< count of threads
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
};
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Lock the semephore of SpinRWLock.
|
|
Packit |
807167 |
* @param core the internal fields.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
static void spinrwlocklock(SpinRWLockCore* core);
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Unlock the semephore of SpinRWLock.
|
|
Packit |
807167 |
* @param core the internal fields.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
static void spinrwlockunlock(SpinRWLockCore* core);
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Default constructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
SpinRWLock::SpinRWLock() : opq_(NULL) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_) || _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SpinRWLockCore* core = new SpinRWLockCore;
|
|
Packit |
807167 |
core->sem = 0;
|
|
Packit |
807167 |
core->cnt = 0;
|
|
Packit |
807167 |
opq_ = (void*)core;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SpinRWLockCore* core = new SpinRWLockCore;
|
|
Packit |
807167 |
if (::pthread_spin_init(&core->sem, PTHREAD_PROCESS_PRIVATE) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_spin_init");
|
|
Packit |
807167 |
core->cnt = 0;
|
|
Packit |
807167 |
opq_ = (void*)core;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Destructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
SpinRWLock::~SpinRWLock() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_) || _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SpinRWLockCore* core = (SpinRWLockCore*)opq_;
|
|
Packit |
807167 |
delete core;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SpinRWLockCore* core = (SpinRWLockCore*)opq_;
|
|
Packit |
807167 |
::pthread_spin_destroy(&core->sem);
|
|
Packit |
807167 |
delete core;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get the writer lock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SpinRWLock::lock_writer() {
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SpinRWLockCore* core = (SpinRWLockCore*)opq_;
|
|
Packit |
807167 |
spinrwlocklock(core);
|
|
Packit |
807167 |
uint32_t wcnt = 0;
|
|
Packit |
807167 |
while (core->cnt > 0) {
|
|
Packit |
807167 |
spinrwlockunlock(core);
|
|
Packit |
807167 |
if (wcnt >= LOCKBUSYLOOP) {
|
|
Packit |
807167 |
Thread::chill();
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
Thread::yield();
|
|
Packit |
807167 |
wcnt++;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
spinrwlocklock(core);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
core->cnt = INT32MAX;
|
|
Packit |
807167 |
spinrwlockunlock(core);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Try to get the writer lock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
bool SpinRWLock::lock_writer_try() {
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SpinRWLockCore* core = (SpinRWLockCore*)opq_;
|
|
Packit |
807167 |
spinrwlocklock(core);
|
|
Packit |
807167 |
if (core->cnt > 0) {
|
|
Packit |
807167 |
spinrwlockunlock(core);
|
|
Packit |
807167 |
return false;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
core->cnt = INT32MAX;
|
|
Packit |
807167 |
spinrwlockunlock(core);
|
|
Packit |
807167 |
return true;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get a reader lock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SpinRWLock::lock_reader() {
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SpinRWLockCore* core = (SpinRWLockCore*)opq_;
|
|
Packit |
807167 |
spinrwlocklock(core);
|
|
Packit |
807167 |
uint32_t wcnt = 0;
|
|
Packit |
807167 |
while (core->cnt >= (uint32_t)INT32MAX) {
|
|
Packit |
807167 |
spinrwlockunlock(core);
|
|
Packit |
807167 |
if (wcnt >= LOCKBUSYLOOP) {
|
|
Packit |
807167 |
Thread::chill();
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
Thread::yield();
|
|
Packit |
807167 |
wcnt++;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
spinrwlocklock(core);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
core->cnt++;
|
|
Packit |
807167 |
spinrwlockunlock(core);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Try to get a reader lock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
bool SpinRWLock::lock_reader_try() {
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SpinRWLockCore* core = (SpinRWLockCore*)opq_;
|
|
Packit |
807167 |
spinrwlocklock(core);
|
|
Packit |
807167 |
if (core->cnt >= (uint32_t)INT32MAX) {
|
|
Packit |
807167 |
spinrwlockunlock(core);
|
|
Packit |
807167 |
return false;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
core->cnt++;
|
|
Packit |
807167 |
spinrwlockunlock(core);
|
|
Packit |
807167 |
return true;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Release the lock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SpinRWLock::unlock() {
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SpinRWLockCore* core = (SpinRWLockCore*)opq_;
|
|
Packit |
807167 |
spinrwlocklock(core);
|
|
Packit |
807167 |
if (core->cnt >= (uint32_t)INT32MAX) {
|
|
Packit |
807167 |
core->cnt = 0;
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
core->cnt--;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
spinrwlockunlock(core);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Promote a reader lock to the writer lock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
bool SpinRWLock::promote() {
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SpinRWLockCore* core = (SpinRWLockCore*)opq_;
|
|
Packit |
807167 |
spinrwlocklock(core);
|
|
Packit |
807167 |
if (core->cnt > 1) {
|
|
Packit |
807167 |
spinrwlockunlock(core);
|
|
Packit |
807167 |
return false;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
core->cnt = INT32MAX;
|
|
Packit |
807167 |
spinrwlockunlock(core);
|
|
Packit |
807167 |
return true;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Demote the writer lock to a reader lock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SpinRWLock::demote() {
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SpinRWLockCore* core = (SpinRWLockCore*)opq_;
|
|
Packit |
807167 |
spinrwlocklock(core);
|
|
Packit |
807167 |
core->cnt = 1;
|
|
Packit |
807167 |
spinrwlockunlock(core);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Lock the semephore of SpinRWLock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
static void spinrwlocklock(SpinRWLockCore* core) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(core);
|
|
Packit |
807167 |
while (::InterlockedCompareExchange(&core->sem, 1, 0) != 0) {
|
|
Packit |
807167 |
::Sleep(0);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(core);
|
|
Packit |
807167 |
while (!__sync_bool_compare_and_swap(&core->sem, 0, 1)) {
|
|
Packit |
807167 |
::sched_yield();
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(core);
|
|
Packit |
807167 |
if (::pthread_spin_lock(&core->sem) != 0) throw std::runtime_error("pthread_spin_lock");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Unlock the semephore of SpinRWLock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
static void spinrwlockunlock(SpinRWLockCore* core) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(core);
|
|
Packit |
807167 |
::InterlockedExchange(&core->sem, 0);
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(core);
|
|
Packit |
807167 |
__sync_lock_release(&core->sem);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(core);
|
|
Packit |
807167 |
if (::pthread_spin_unlock(&core->sem) != 0) throw std::runtime_error("pthread_spin_unlock");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* SlottedRWLock internal.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
struct SlottedSpinRWLockCore {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
LONG sems[LOCKSEMNUM]; ///< semaphores
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
int32_t sems[LOCKSEMNUM]; ///< semaphores
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
::pthread_spinlock_t sems[LOCKSEMNUM]; ///< semaphores
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
uint32_t* cnts; ///< counts of threads
|
|
Packit |
807167 |
size_t slotnum; ///< number of slots
|
|
Packit |
807167 |
};
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Lock the semephore of SlottedSpinRWLock.
|
|
Packit |
807167 |
* @param core the internal fields.
|
|
Packit |
807167 |
* @param idx the index of the semaphoe.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
static void slottedspinrwlocklock(SlottedSpinRWLockCore* core, size_t idx);
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Unlock the semephore of SlottedSpinRWLock.
|
|
Packit |
807167 |
* @param core the internal fields.
|
|
Packit |
807167 |
* @param idx the index of the semaphoe.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
static void slottedspinrwlockunlock(SlottedSpinRWLockCore* core, size_t idx);
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Constructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
SlottedSpinRWLock::SlottedSpinRWLock(size_t slotnum) : opq_(NULL) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
SlottedSpinRWLockCore* core = new SlottedSpinRWLockCore;
|
|
Packit |
807167 |
LONG* sems = core->sems;
|
|
Packit |
807167 |
uint32_t* cnts = new uint32_t[slotnum];
|
|
Packit |
807167 |
for (size_t i = 0; i < LOCKSEMNUM; i++) {
|
|
Packit |
807167 |
sems[i] = 0;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
cnts[i] = 0;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
core->cnts = cnts;
|
|
Packit |
807167 |
core->slotnum = slotnum;
|
|
Packit |
807167 |
opq_ = (void*)core;
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
SlottedSpinRWLockCore* core = new SlottedSpinRWLockCore;
|
|
Packit |
807167 |
int32_t* sems = core->sems;
|
|
Packit |
807167 |
uint32_t* cnts = new uint32_t[slotnum];
|
|
Packit |
807167 |
for (size_t i = 0; i < LOCKSEMNUM; i++) {
|
|
Packit |
807167 |
sems[i] = 0;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
cnts[i] = 0;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
core->cnts = cnts;
|
|
Packit |
807167 |
core->slotnum = slotnum;
|
|
Packit |
807167 |
opq_ = (void*)core;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinRWLockCore* core = new SlottedSpinRWLockCore;
|
|
Packit |
807167 |
::pthread_spinlock_t* sems = core->sems;
|
|
Packit |
807167 |
uint32_t* cnts = new uint32_t[slotnum];
|
|
Packit |
807167 |
for (size_t i = 0; i < LOCKSEMNUM; i++) {
|
|
Packit |
807167 |
if (::pthread_spin_init(sems + i, PTHREAD_PROCESS_PRIVATE) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_spin_init");
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
cnts[i] = 0;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
core->cnts = cnts;
|
|
Packit |
807167 |
core->slotnum = slotnum;
|
|
Packit |
807167 |
opq_ = (void*)core;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Destructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
SlottedSpinRWLock::~SlottedSpinRWLock() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_) || _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinRWLockCore* core = (SlottedSpinRWLockCore*)opq_;
|
|
Packit |
807167 |
delete[] core->cnts;
|
|
Packit |
807167 |
delete core;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinRWLockCore* core = (SlottedSpinRWLockCore*)opq_;
|
|
Packit |
807167 |
::pthread_spinlock_t* sems = core->sems;
|
|
Packit |
807167 |
for (size_t i = 0; i < LOCKSEMNUM; i++) {
|
|
Packit |
807167 |
::pthread_spin_destroy(sems + i);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
delete[] core->cnts;
|
|
Packit |
807167 |
delete core;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get the writer lock of a slot.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedSpinRWLock::lock_writer(size_t idx) {
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinRWLockCore* core = (SlottedSpinRWLockCore*)opq_;
|
|
Packit |
807167 |
size_t semidx = idx % LOCKSEMNUM;
|
|
Packit |
807167 |
slottedspinrwlocklock(core, semidx);
|
|
Packit |
807167 |
uint32_t wcnt = 0;
|
|
Packit |
807167 |
while (core->cnts[idx] > 0) {
|
|
Packit |
807167 |
slottedspinrwlockunlock(core, semidx);
|
|
Packit |
807167 |
if (wcnt >= LOCKBUSYLOOP) {
|
|
Packit |
807167 |
Thread::chill();
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
Thread::yield();
|
|
Packit |
807167 |
wcnt++;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
slottedspinrwlocklock(core, semidx);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
core->cnts[idx] = INT32MAX;
|
|
Packit |
807167 |
slottedspinrwlockunlock(core, semidx);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get the reader lock of a slot.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedSpinRWLock::lock_reader(size_t idx) {
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinRWLockCore* core = (SlottedSpinRWLockCore*)opq_;
|
|
Packit |
807167 |
size_t semidx = idx % LOCKSEMNUM;
|
|
Packit |
807167 |
slottedspinrwlocklock(core, semidx);
|
|
Packit |
807167 |
uint32_t wcnt = 0;
|
|
Packit |
807167 |
while (core->cnts[idx] >= (uint32_t)INT32MAX) {
|
|
Packit |
807167 |
slottedspinrwlockunlock(core, semidx);
|
|
Packit |
807167 |
if (wcnt >= LOCKBUSYLOOP) {
|
|
Packit |
807167 |
Thread::chill();
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
Thread::yield();
|
|
Packit |
807167 |
wcnt++;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
slottedspinrwlocklock(core, semidx);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
core->cnts[idx]++;
|
|
Packit |
807167 |
slottedspinrwlockunlock(core, semidx);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Release the lock of a slot.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedSpinRWLock::unlock(size_t idx) {
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinRWLockCore* core = (SlottedSpinRWLockCore*)opq_;
|
|
Packit |
807167 |
size_t semidx = idx % LOCKSEMNUM;
|
|
Packit |
807167 |
slottedspinrwlocklock(core, semidx);
|
|
Packit |
807167 |
if (core->cnts[idx] >= (uint32_t)INT32MAX) {
|
|
Packit |
807167 |
core->cnts[idx] = 0;
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
core->cnts[idx]--;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
slottedspinrwlockunlock(core, semidx);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get the writer locks of all slots.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedSpinRWLock::lock_writer_all() {
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinRWLockCore* core = (SlottedSpinRWLockCore*)opq_;
|
|
Packit |
807167 |
uint32_t* cnts = core->cnts;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
size_t semidx = i % LOCKSEMNUM;
|
|
Packit |
807167 |
slottedspinrwlocklock(core, semidx);
|
|
Packit |
807167 |
uint32_t wcnt = 0;
|
|
Packit |
807167 |
while (cnts[i] > 0) {
|
|
Packit |
807167 |
slottedspinrwlockunlock(core, semidx);
|
|
Packit |
807167 |
if (wcnt >= LOCKBUSYLOOP) {
|
|
Packit |
807167 |
Thread::chill();
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
Thread::yield();
|
|
Packit |
807167 |
wcnt++;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
slottedspinrwlocklock(core, semidx);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
cnts[i] = INT32MAX;
|
|
Packit |
807167 |
slottedspinrwlockunlock(core, semidx);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get the reader locks of all slots.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedSpinRWLock::lock_reader_all() {
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinRWLockCore* core = (SlottedSpinRWLockCore*)opq_;
|
|
Packit |
807167 |
uint32_t* cnts = core->cnts;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
size_t semidx = i % LOCKSEMNUM;
|
|
Packit |
807167 |
slottedspinrwlocklock(core, semidx);
|
|
Packit |
807167 |
uint32_t wcnt = 0;
|
|
Packit |
807167 |
while (cnts[i] >= (uint32_t)INT32MAX) {
|
|
Packit |
807167 |
slottedspinrwlockunlock(core, semidx);
|
|
Packit |
807167 |
if (wcnt >= LOCKBUSYLOOP) {
|
|
Packit |
807167 |
Thread::chill();
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
Thread::yield();
|
|
Packit |
807167 |
wcnt++;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
slottedspinrwlocklock(core, semidx);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
cnts[i]++;
|
|
Packit |
807167 |
slottedspinrwlockunlock(core, semidx);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Release the locks of all slots.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void SlottedSpinRWLock::unlock_all() {
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
SlottedSpinRWLockCore* core = (SlottedSpinRWLockCore*)opq_;
|
|
Packit |
807167 |
uint32_t* cnts = core->cnts;
|
|
Packit |
807167 |
size_t slotnum = core->slotnum;
|
|
Packit |
807167 |
for (size_t i = 0; i < slotnum; i++) {
|
|
Packit |
807167 |
size_t semidx = i % LOCKSEMNUM;
|
|
Packit |
807167 |
slottedspinrwlocklock(core, semidx);
|
|
Packit |
807167 |
if (cnts[i] >= (uint32_t)INT32MAX) {
|
|
Packit |
807167 |
cnts[i] = 0;
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
cnts[i]--;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
slottedspinrwlockunlock(core, semidx);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Lock the semephore of SlottedSpinRWLock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
static void slottedspinrwlocklock(SlottedSpinRWLockCore* core, size_t idx) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(core);
|
|
Packit |
807167 |
while (::InterlockedCompareExchange(core->sems + idx, 1, 0) != 0) {
|
|
Packit |
807167 |
::Sleep(0);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(core);
|
|
Packit |
807167 |
while (!__sync_bool_compare_and_swap(core->sems + idx, 0, 1)) {
|
|
Packit |
807167 |
::sched_yield();
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(core);
|
|
Packit |
807167 |
if (::pthread_spin_lock(core->sems + idx) != 0) throw std::runtime_error("pthread_spin_lock");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Unlock the semephore of SlottedSpinRWLock.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
static void slottedspinrwlockunlock(SlottedSpinRWLockCore* core, size_t idx) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(core);
|
|
Packit |
807167 |
::InterlockedExchange(core->sems + idx, 0);
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(core);
|
|
Packit |
807167 |
__sync_lock_release(core->sems + idx);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(core);
|
|
Packit |
807167 |
if (::pthread_spin_unlock(core->sems + idx) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_spin_unlock");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Default constructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
CondVar::CondVar() : opq_(NULL) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
CondVarCore* core = new CondVarCore;
|
|
Packit |
807167 |
::InitializeCriticalSection(&core->mutex);
|
|
Packit |
807167 |
core->wait = 0;
|
|
Packit |
807167 |
core->wake = 0;
|
|
Packit |
807167 |
core->sev = ::CreateEvent(NULL, true, false, NULL);
|
|
Packit |
807167 |
if (!core->sev) throw std::runtime_error("CreateEvent");
|
|
Packit |
807167 |
core->fev = ::CreateEvent(NULL, false, false, NULL);
|
|
Packit |
807167 |
if (!core->fev) throw std::runtime_error("CreateEvent");
|
|
Packit |
807167 |
opq_ = (void*)core;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
CondVarCore* core = new CondVarCore;
|
|
Packit |
807167 |
if (::pthread_cond_init(&core->cond, NULL) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_cond_init");
|
|
Packit |
807167 |
opq_ = (void*)core;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Destructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
CondVar::~CondVar() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
CondVarCore* core = (CondVarCore*)opq_;
|
|
Packit |
807167 |
::CloseHandle(core->fev);
|
|
Packit |
807167 |
::CloseHandle(core->sev);
|
|
Packit |
807167 |
::DeleteCriticalSection(&core->mutex);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
CondVarCore* core = (CondVarCore*)opq_;
|
|
Packit |
807167 |
::pthread_cond_destroy(&core->cond);
|
|
Packit |
807167 |
delete core;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Wait for the signal.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void CondVar::wait(Mutex* mutex) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(mutex);
|
|
Packit |
807167 |
CondVarCore* core = (CondVarCore*)opq_;
|
|
Packit |
807167 |
::CRITICAL_SECTION* mymutex = (::CRITICAL_SECTION*)mutex->opq_;
|
|
Packit |
807167 |
::EnterCriticalSection(&core->mutex);
|
|
Packit |
807167 |
core->wait++;
|
|
Packit |
807167 |
::LeaveCriticalSection(&core->mutex);
|
|
Packit |
807167 |
::LeaveCriticalSection(mymutex);
|
|
Packit |
807167 |
while (true) {
|
|
Packit |
807167 |
::WaitForSingleObject(core->sev, INFINITE);
|
|
Packit |
807167 |
::EnterCriticalSection(&core->mutex);
|
|
Packit |
807167 |
if (core->wake > 0) {
|
|
Packit |
807167 |
core->wait--;
|
|
Packit |
807167 |
core->wake--;
|
|
Packit |
807167 |
if (core->wake < 1) {
|
|
Packit |
807167 |
::ResetEvent(core->sev);
|
|
Packit |
807167 |
::SetEvent(core->fev);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
::LeaveCriticalSection(&core->mutex);
|
|
Packit |
807167 |
break;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
::LeaveCriticalSection(&core->mutex);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
::EnterCriticalSection(mymutex);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(mutex);
|
|
Packit |
807167 |
CondVarCore* core = (CondVarCore*)opq_;
|
|
Packit |
807167 |
::pthread_mutex_t* mymutex = (::pthread_mutex_t*)mutex->opq_;
|
|
Packit |
807167 |
if (::pthread_cond_wait(&core->cond, mymutex) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_cond_wait");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Wait for the signal.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
bool CondVar::wait(Mutex* mutex, double sec) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(mutex && sec >= 0);
|
|
Packit |
807167 |
if (sec <= 0) return false;
|
|
Packit |
807167 |
CondVarCore* core = (CondVarCore*)opq_;
|
|
Packit |
807167 |
::CRITICAL_SECTION* mymutex = (::CRITICAL_SECTION*)mutex->opq_;
|
|
Packit |
807167 |
::EnterCriticalSection(&core->mutex);
|
|
Packit |
807167 |
core->wait++;
|
|
Packit |
807167 |
::LeaveCriticalSection(&core->mutex);
|
|
Packit |
807167 |
::LeaveCriticalSection(mymutex);
|
|
Packit |
807167 |
while (true) {
|
|
Packit |
807167 |
if (::WaitForSingleObject(core->sev, sec * 1000) == WAIT_TIMEOUT) {
|
|
Packit |
807167 |
::EnterCriticalSection(&core->mutex);
|
|
Packit |
807167 |
if (::WaitForSingleObject(core->sev, 0) == WAIT_TIMEOUT) {
|
|
Packit |
807167 |
core->wait--;
|
|
Packit |
807167 |
::SetEvent(core->fev);
|
|
Packit |
807167 |
::LeaveCriticalSection(&core->mutex);
|
|
Packit |
807167 |
::EnterCriticalSection(mymutex);
|
|
Packit |
807167 |
return false;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
::LeaveCriticalSection(&core->mutex);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
::EnterCriticalSection(&core->mutex);
|
|
Packit |
807167 |
if (core->wake > 0) {
|
|
Packit |
807167 |
core->wait--;
|
|
Packit |
807167 |
core->wake--;
|
|
Packit |
807167 |
if (core->wake < 1) {
|
|
Packit |
807167 |
::ResetEvent(core->sev);
|
|
Packit |
807167 |
::SetEvent(core->fev);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
::LeaveCriticalSection(&core->mutex);
|
|
Packit |
807167 |
break;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
::LeaveCriticalSection(&core->mutex);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
::EnterCriticalSection(mymutex);
|
|
Packit |
807167 |
return true;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(mutex && sec >= 0);
|
|
Packit |
807167 |
if (sec <= 0) return false;
|
|
Packit |
807167 |
CondVarCore* core = (CondVarCore*)opq_;
|
|
Packit |
807167 |
::pthread_mutex_t* mymutex = (::pthread_mutex_t*)mutex->opq_;
|
|
Packit |
807167 |
struct ::timeval tv;
|
|
Packit |
807167 |
struct ::timespec ts;
|
|
Packit |
807167 |
if (::gettimeofday(&tv, NULL) == 0) {
|
|
Packit |
807167 |
double integ;
|
|
Packit |
807167 |
double fract = std::modf(sec, &integ);
|
|
Packit |
807167 |
ts.tv_sec = tv.tv_sec + (time_t)integ;
|
|
Packit |
807167 |
ts.tv_nsec = (long)(tv.tv_usec * 1000.0 + fract * 999999000);
|
|
Packit |
807167 |
if (ts.tv_nsec >= 1000000000) {
|
|
Packit |
807167 |
ts.tv_nsec -= 1000000000;
|
|
Packit |
807167 |
ts.tv_sec++;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
ts.tv_sec = std::time(NULL) + 1;
|
|
Packit |
807167 |
ts.tv_nsec = 0;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
int32_t ecode = ::pthread_cond_timedwait(&core->cond, mymutex, &ts);
|
|
Packit |
807167 |
if (ecode == 0) return true;
|
|
Packit |
807167 |
if (ecode != ETIMEDOUT && ecode != EINTR)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_cond_timedwait");
|
|
Packit |
807167 |
return false;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Send the wake-up signal to another waiting thread.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void CondVar::signal() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
CondVarCore* core = (CondVarCore*)opq_;
|
|
Packit |
807167 |
::EnterCriticalSection(&core->mutex);
|
|
Packit |
807167 |
if (core->wait > 0) {
|
|
Packit |
807167 |
core->wake = 1;
|
|
Packit |
807167 |
::SetEvent(core->sev);
|
|
Packit |
807167 |
::LeaveCriticalSection(&core->mutex);
|
|
Packit |
807167 |
::WaitForSingleObject(core->fev, INFINITE);
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
::LeaveCriticalSection(&core->mutex);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
CondVarCore* core = (CondVarCore*)opq_;
|
|
Packit |
807167 |
if (::pthread_cond_signal(&core->cond) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_cond_signal");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Send the wake-up signals to all waiting threads.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void CondVar::broadcast() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
CondVarCore* core = (CondVarCore*)opq_;
|
|
Packit |
807167 |
::EnterCriticalSection(&core->mutex);
|
|
Packit |
807167 |
if (core->wait > 0) {
|
|
Packit |
807167 |
core->wake = core->wait;
|
|
Packit |
807167 |
::SetEvent(core->sev);
|
|
Packit |
807167 |
::LeaveCriticalSection(&core->mutex);
|
|
Packit |
807167 |
::WaitForSingleObject(core->fev, INFINITE);
|
|
Packit |
807167 |
} else {
|
|
Packit |
807167 |
::LeaveCriticalSection(&core->mutex);
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
CondVarCore* core = (CondVarCore*)opq_;
|
|
Packit |
807167 |
if (::pthread_cond_broadcast(&core->cond) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_cond_broadcast");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Default constructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
TSDKey::TSDKey() : opq_(NULL) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::DWORD key = ::TlsAlloc();
|
|
Packit |
807167 |
if (key == 0xFFFFFFFF) throw std::runtime_error("TlsAlloc");
|
|
Packit |
807167 |
opq_ = (void*)key;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_key_t* key = new ::pthread_key_t;
|
|
Packit |
807167 |
if (::pthread_key_create(key, NULL) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_key_create");
|
|
Packit |
807167 |
opq_ = (void*)key;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Constructor with the specifications.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
TSDKey::TSDKey(void (*dstr)(void*)) : opq_(NULL) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::DWORD key = ::TlsAlloc();
|
|
Packit |
807167 |
if (key == 0xFFFFFFFF) throw std::runtime_error("TlsAlloc");
|
|
Packit |
807167 |
opq_ = (void*)key;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_key_t* key = new ::pthread_key_t;
|
|
Packit |
807167 |
if (::pthread_key_create(key, dstr) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_key_create");
|
|
Packit |
807167 |
opq_ = (void*)key;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Destructor.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
TSDKey::~TSDKey() {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::DWORD key = (::DWORD)opq_;
|
|
Packit |
807167 |
::TlsFree(key);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_key_t* key = (::pthread_key_t*)opq_;
|
|
Packit |
807167 |
::pthread_key_delete(*key);
|
|
Packit |
807167 |
delete key;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Set the value.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void TSDKey::set(void* ptr) {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::DWORD key = (::DWORD)opq_;
|
|
Packit |
807167 |
if (!::TlsSetValue(key, ptr)) std::runtime_error("TlsSetValue");
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_key_t* key = (::pthread_key_t*)opq_;
|
|
Packit |
807167 |
if (::pthread_setspecific(*key, ptr) != 0)
|
|
Packit |
807167 |
throw std::runtime_error("pthread_setspecific");
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get the value.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
void* TSDKey::get() const {
|
|
Packit |
807167 |
#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::DWORD key = (::DWORD)opq_;
|
|
Packit |
807167 |
return ::TlsGetValue(key);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
::pthread_key_t* key = (::pthread_key_t*)opq_;
|
|
Packit |
807167 |
return ::pthread_getspecific(*key);
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Set the new value.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
int64_t AtomicInt64::set(int64_t val) {
|
|
Packit |
807167 |
#if (defined(_SYS_MSVC_) || defined(_SYS_MINGW_)) && defined(_SYS_WIN64_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
return ::InterlockedExchange((uint64_t*)&value_, val);
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
int64_t oval = __sync_lock_test_and_set(&value_, val);
|
|
Packit |
807167 |
__sync_synchronize();
|
|
Packit |
807167 |
return oval;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
lock_.lock();
|
|
Packit |
807167 |
int64_t oval = value_;
|
|
Packit |
807167 |
value_ = val;
|
|
Packit |
807167 |
lock_.unlock();
|
|
Packit |
807167 |
return oval;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Add a value.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
int64_t AtomicInt64::add(int64_t val) {
|
|
Packit |
807167 |
#if (defined(_SYS_MSVC_) || defined(_SYS_MINGW_)) && defined(_SYS_WIN64_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
return ::InterlockedExchangeAdd((uint64_t*)&value_, val);
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
int64_t oval = __sync_fetch_and_add(&value_, val);
|
|
Packit |
807167 |
__sync_synchronize();
|
|
Packit |
807167 |
return oval;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
lock_.lock();
|
|
Packit |
807167 |
int64_t oval = value_;
|
|
Packit |
807167 |
value_ += val;
|
|
Packit |
807167 |
lock_.unlock();
|
|
Packit |
807167 |
return oval;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Perform compare-and-swap.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
bool AtomicInt64::cas(int64_t oval, int64_t nval) {
|
|
Packit |
807167 |
#if (defined(_SYS_MSVC_) || defined(_SYS_MINGW_)) && defined(_SYS_WIN64_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
return ::InterlockedCompareExchange((uint64_t*)&value_, nval, oval) == oval;
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
bool rv = __sync_bool_compare_and_swap(&value_, oval, nval);
|
|
Packit |
807167 |
__sync_synchronize();
|
|
Packit |
807167 |
return rv;
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
bool rv = false;
|
|
Packit |
807167 |
lock_.lock();
|
|
Packit |
807167 |
if (value_ == oval) {
|
|
Packit |
807167 |
value_ = nval;
|
|
Packit |
807167 |
rv = true;
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
lock_.unlock();
|
|
Packit |
807167 |
return rv;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
/**
|
|
Packit |
807167 |
* Get the current value.
|
|
Packit |
807167 |
*/
|
|
Packit |
807167 |
int64_t AtomicInt64::get() const {
|
|
Packit |
807167 |
#if (defined(_SYS_MSVC_) || defined(_SYS_MINGW_)) && defined(_SYS_WIN64_)
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
return ::InterlockedExchangeAdd((uint64_t*)&value_, 0);
|
|
Packit |
807167 |
#elif _KC_GCCATOMIC
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
return __sync_fetch_and_add((int64_t*)&value_, 0);
|
|
Packit |
807167 |
#else
|
|
Packit |
807167 |
_assert_(true);
|
|
Packit |
807167 |
lock_.lock();
|
|
Packit |
807167 |
int64_t oval = value_;
|
|
Packit |
807167 |
lock_.unlock();
|
|
Packit |
807167 |
return oval;
|
|
Packit |
807167 |
#endif
|
|
Packit |
807167 |
}
|
|
Packit |
807167 |
|
|
Packit |
807167 |
|
|
Packit |
807167 |
} // common namespace
|
|
Packit |
807167 |
|
|
Packit |
807167 |
// END OF FILE
|