mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-31 23:23:04 +01:00
354 lines
7.0 KiB
C++
354 lines
7.0 KiB
C++
/*
|
|
* PROGRAM: Client/Server Common Code
|
|
* MODULE: locks.cpp
|
|
* DESCRIPTION: Darwin specific semaphore support
|
|
*
|
|
* The contents of this file are subject to the Initial
|
|
* Developer's Public License Version 1.0 (the "License");
|
|
* you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
|
*
|
|
* Software distributed under the License is distributed AS IS,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing rights
|
|
* and limitations under the License.
|
|
*
|
|
* The Original Code was created by Alexander Peshkoff
|
|
* for the Firebird Open Source RDBMS project.
|
|
*
|
|
* Copyright (c) 2007 Alexander Peshkoff <peshkoff@mail.ru>
|
|
* and all contributors signed below.
|
|
*
|
|
* All Rights Reserved.
|
|
* Contributor(s): ______________________________________.
|
|
*/
|
|
|
|
#include "firebird.h"
|
|
#include "../common/classes/semaphore.h"
|
|
#include "../common/classes/alloc.h"
|
|
#include "gen/iberror.h"
|
|
|
|
#ifdef HAVE_SYS_TIMES_H
|
|
#include <sys/times.h>
|
|
#endif
|
|
#ifdef HAVE_SYS_TIMEB_H
|
|
#include <sys/timeb.h>
|
|
#endif
|
|
#ifdef HAVE_SYS_TIME_H
|
|
#include <sys/time.h>
|
|
#endif
|
|
|
|
#if defined(COMMON_CLASSES_SEMAPHORE_POSIX_RT) || defined(COMMON_CLASSES_SEMAPHORE_COND_VAR)
|
|
|
|
static timespec getCurrentTime()
|
|
{
|
|
timespec rc;
|
|
|
|
#ifdef HAVE_GETTIMEOFDAY
|
|
struct timeval tp;
|
|
GETTIMEOFDAY(&tp);
|
|
rc.tv_sec = tp.tv_sec;
|
|
rc.tv_nsec = tp.tv_usec * 1000;
|
|
#else
|
|
struct timeb time_buffer;
|
|
ftime(&time_buffer);
|
|
rc.tv_sec = time_buffer.time;
|
|
rc.tv_nsec = time_buffer.millitm * 1000000;
|
|
#endif
|
|
|
|
return rc;
|
|
}
|
|
|
|
#endif // semaphore kind defined
|
|
|
|
|
|
|
|
namespace Firebird {
|
|
|
|
#ifdef COMMON_CLASSES_SEMAPHORE_MACH
|
|
|
|
void SignalSafeSemaphore::init()
|
|
{
|
|
semaphore = dispatch_semaphore_create(0);
|
|
if (!semaphore) // With const zero parameter this means OOM
|
|
{
|
|
BadAlloc::raise();
|
|
}
|
|
}
|
|
|
|
SignalSafeSemaphore::~SignalSafeSemaphore()
|
|
{
|
|
dispatch_release(semaphore);
|
|
}
|
|
|
|
#endif // COMMON_CLASSES_SEMAPHORE_MACH
|
|
|
|
|
|
|
|
#ifdef COMMON_CLASSES_SEMAPHORE_POSIX_RT
|
|
|
|
#ifndef WORKING_SEM_INIT
|
|
static const char* semName = "/firebird_temp_sem";
|
|
#endif
|
|
|
|
#ifndef SEM_FAILED
|
|
#define SEM_FAILED ((sem_t*) (-1))
|
|
#endif
|
|
|
|
void SignalSafeSemaphore::init()
|
|
{
|
|
#ifdef WORKING_SEM_INIT
|
|
if (sem_init(sem, 0, 0) == -1) {
|
|
system_call_failed::raise("sem_init");
|
|
}
|
|
#else
|
|
sem = sem_open(semName, O_CREAT | O_EXCL, 0700, 0);
|
|
if (sem == (sem_t*) SEM_FAILED) {
|
|
system_call_failed::raise("sem_open");
|
|
}
|
|
sem_unlink(semName);
|
|
#endif
|
|
}
|
|
|
|
SignalSafeSemaphore::~SignalSafeSemaphore()
|
|
{
|
|
#ifdef WORKING_SEM_INIT
|
|
if (sem_destroy(sem) == -1) {
|
|
system_call_failed::raise("sem_destroy");
|
|
}
|
|
#else
|
|
if (sem_close(sem) == -1) {
|
|
system_call_failed::raise("sem_close");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void SignalSafeSemaphore::enter()
|
|
{
|
|
do {
|
|
if (sem_wait(sem) != -1)
|
|
return;
|
|
} while (errno == EINTR);
|
|
system_call_failed::raise("semaphore.h: enter: sem_wait()");
|
|
}
|
|
|
|
#ifdef HAVE_SEM_TIMEDWAIT
|
|
bool SignalSafeSemaphore::tryEnter(const int seconds, int milliseconds)
|
|
{
|
|
long nanoseconds = long(milliseconds + seconds * 1000) * 1000000l;
|
|
// Return true in case of success
|
|
if (nanoseconds == 0)
|
|
{
|
|
// Instant try
|
|
do {
|
|
if (sem_trywait(sem) != -1)
|
|
return true;
|
|
} while (errno == EINTR);
|
|
if (errno == EAGAIN)
|
|
return false;
|
|
system_call_failed::raise("sem_trywait");
|
|
}
|
|
if (nanoseconds < 0)
|
|
{
|
|
// Unlimited wait, like enter()
|
|
do {
|
|
if (sem_wait(sem) != -1)
|
|
return true;
|
|
} while (errno == EINTR);
|
|
system_call_failed::raise("sem_wait");
|
|
}
|
|
// Wait with timeout
|
|
timespec timeout = getCurrentTime();
|
|
nanoseconds += timeout.tv_nsec;
|
|
timeout.tv_sec += nanoseconds / 1000000000l;
|
|
timeout.tv_nsec = nanoseconds % 1000000000l;
|
|
int errcode = 0;
|
|
do {
|
|
int rc = sem_timedwait(sem, &timeout);
|
|
if (rc == 0)
|
|
return true;
|
|
// fix for CORE-988, also please see
|
|
// http://carcino.gen.nz/tech/linux/glibc_sem_timedwait_errors.php
|
|
errcode = rc > 0 ? rc : errno;
|
|
} while (errcode == EINTR);
|
|
if (errcode == ETIMEDOUT) {
|
|
return false;
|
|
}
|
|
system_call_failed::raise("sem_timedwait", errcode);
|
|
return false; // avoid warnings
|
|
}
|
|
#endif // HAVE_SEM_TIMEDWAIT
|
|
|
|
#endif // COMMON_CLASSES_SEMAPHORE_POSIX_RT
|
|
|
|
|
|
|
|
#ifdef COMMON_CLASSES_SEMAPHORE_COND_VAR
|
|
|
|
void Semaphore::init()
|
|
{
|
|
value = 0;
|
|
int err = pthread_mutex_init(&mu, NULL);
|
|
if (err != 0) {
|
|
//gds__log("Error on semaphore.h: constructor");
|
|
system_call_failed::raise("pthread_mutex_init", err);
|
|
}
|
|
err = pthread_cond_init(&cv, NULL);
|
|
if (err != 0) {
|
|
//gds__log("Error on semaphore.h: constructor");
|
|
system_call_failed::raise("pthread_cond_init", err);
|
|
}
|
|
}
|
|
|
|
void Semaphore::mtxLock()
|
|
{
|
|
int err = pthread_mutex_lock(&mu);
|
|
if (err != 0)
|
|
{
|
|
system_call_failed::raise("pthread_mutex_lock", err);
|
|
}
|
|
}
|
|
|
|
void Semaphore::mtxUnlock()
|
|
{
|
|
int err = pthread_mutex_unlock(&mu);
|
|
if (err != 0)
|
|
{
|
|
system_call_failed::raise("pthread_mutex_unlock", err);
|
|
}
|
|
}
|
|
|
|
Semaphore::~Semaphore()
|
|
{
|
|
fb_assert(value == 0);
|
|
int err = pthread_mutex_destroy(&mu);
|
|
if (err != 0) {
|
|
//gds__log("Error on semaphore.h: destructor");
|
|
//system_call_failed::raise("pthread_mutex_destroy", err);
|
|
}
|
|
err = pthread_cond_destroy(&cv);
|
|
if (err != 0) {
|
|
//gds__log("Error on semaphore.h: destructor");
|
|
//system_call_failed::raise("pthread_cond_destroy", err);
|
|
}
|
|
}
|
|
|
|
bool Semaphore::tryEnter(const int seconds, int milliseconds)
|
|
{
|
|
bool rt = false; // Return true in case of success
|
|
int err = 0;
|
|
milliseconds += seconds * 1000;
|
|
|
|
if (milliseconds == 0)
|
|
{
|
|
// Instant try
|
|
err = pthread_mutex_trylock(&mu);
|
|
if (err != 0)
|
|
{
|
|
if (err == EBUSY)
|
|
{
|
|
return false;
|
|
}
|
|
system_call_failed::raise("pthread_mutex_trylock", err);
|
|
}
|
|
|
|
if (value > 0)
|
|
{
|
|
--value;
|
|
rt = true;
|
|
}
|
|
|
|
mtxUnlock();
|
|
return rt;
|
|
}
|
|
|
|
if (milliseconds < 0)
|
|
{
|
|
// Unlimited wait
|
|
enter();
|
|
return true;
|
|
}
|
|
|
|
// Wait with timeout
|
|
mtxLock();
|
|
|
|
if (--value >= 0)
|
|
{
|
|
mtxUnlock();
|
|
return true;
|
|
}
|
|
|
|
timespec timeout = getCurrentTime();
|
|
nanoseconds += timeout.tv_nsec;
|
|
timeout.tv_sec += nanoseconds / 1000000000l;
|
|
timeout.tv_nsec = nanoseconds % 1000000000l;
|
|
err = pthread_cond_timedwait(&cv, &mu, &timeout);
|
|
|
|
mtxUnlock();
|
|
|
|
if (err == ETIMEDOUT)
|
|
{
|
|
++value;
|
|
}
|
|
else if (err != 0)
|
|
{
|
|
system_call_failed::raise("pthread_cond_timedwait", err);
|
|
}
|
|
else
|
|
{
|
|
rt = true;
|
|
}
|
|
|
|
return rt;
|
|
}
|
|
|
|
void Semaphore::enter()
|
|
{
|
|
mtxLock();
|
|
|
|
if (--value >= 0)
|
|
{
|
|
mtxUnlock();
|
|
return;
|
|
}
|
|
|
|
int err = pthread_cond_wait(&cv, &mu);
|
|
|
|
mtxUnlock();
|
|
|
|
if (err != 0)
|
|
{
|
|
system_call_failed::raise("pthread_cond_timedwait", err);
|
|
}
|
|
}
|
|
|
|
void Semaphore::release(SLONG count)
|
|
{
|
|
int err = 0;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
mtxLock();
|
|
|
|
if (++value > 0)
|
|
{
|
|
mtxUnlock();
|
|
continue;
|
|
}
|
|
|
|
err = pthread_cond_signal(&cv);
|
|
|
|
mtxUnlock();
|
|
|
|
if (err != 0)
|
|
{
|
|
system_call_failed::raise("pthread_cond_broadcast", err);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // COMMON_CLASSES_SEMAPHORE_COND_VAR
|
|
|
|
}
|
|
|