8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-02-01 04:43:03 +01:00
firebird-mirror/src/common/classes/semaphore.cpp

322 lines
6.5 KiB
C++
Raw Normal View History

2007-12-19 15:35:52 +01:00
/*
* 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"
2007-12-19 15:35:52 +01:00
namespace Firebird {
2007-12-19 15:35:52 +01:00
#ifdef COMMON_CLASSES_SEMAPHORE_MACH
void SignalSafeSemaphore::machErrorCheck(kern_return_t rc, const char* fun)
{
if (rc != KERN_SUCCESS)
{
(Arg::Gds(isc_sys_request) << fun << Arg::Mach(static_cast<ISC_STATUS>(rc))).raise();
}
}
2007-12-19 15:35:52 +01:00
void SignalSafeSemaphore::init()
{
machErrorCheck(semaphore_create(mach_task_self(), &sem, SYNC_POLICY_FIFO, 0),
"semaphore_create");
}
2007-12-19 15:35:52 +01:00
SignalSafeSemaphore::~SignalSafeSemaphore()
{
machErrorCheck(semaphore_destroy(mach_task_self(), sem), "semaphore_destroy");
}
2007-12-19 15:35:52 +01:00
#endif // COMMON_CLASSES_SEMAPHORE_MACH
2007-12-19 15:35:52 +01:00
#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()
2007-12-19 15:35:52 +01:00
{
#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
2007-12-19 15:35:52 +01:00
}
SignalSafeSemaphore::~SignalSafeSemaphore()
2007-12-19 15:35:52 +01:00
{
#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
2007-12-19 15:35:52 +01:00
}
void SignalSafeSemaphore::enter()
2007-12-19 15:35:52 +01:00
{
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)
{
milliseconds += seconds * 1000;
// Return true in case of success
if (milliseconds == 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 (milliseconds < 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
struct timespec timeout;
timeout.tv_sec = time(NULL) + milliseconds / 1000;
timeout.tv_nsec = (milliseconds % 1000) * 1000000;
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);
}
2007-12-19 15:35:52 +01:00
}
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);
}
}
2007-12-19 15:35:52 +01:00
bool Semaphore::tryEnter(const int seconds, int milliseconds)
2007-12-19 15:35:52 +01:00
{
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)
2007-12-19 15:35:52 +01:00
{
// Unlimited wait
enter();
2007-12-19 15:35:52 +01:00
return true;
}
// Wait with timeout
mtxLock();
2009-06-19 04:29:08 +02:00
if (--value >= 0)
{
mtxUnlock();
return true;
}
timespec timeout;
timeout.tv_sec = time(NULL) + milliseconds / 1000;
timeout.tv_nsec = (milliseconds % 1000) * 1000000;
err = pthread_cond_timedwait(&cv, &mu, &timeout);
mtxUnlock();
2009-06-19 04:29:08 +02:00
if (err == ETIMEDOUT)
{
++value;
}
2009-06-19 04:29:08 +02:00
else if (err != 0)
{
system_call_failed::raise("pthread_cond_timedwait", err);
}
2009-06-19 04:29:08 +02:00
else
{
rt = true;
}
return rt;
2007-12-19 15:35:52 +01:00
}
void Semaphore::enter()
{
mtxLock();
if (--value >= 0)
{
mtxUnlock();
return;
}
int err = pthread_cond_wait(&cv, &mu);
mtxUnlock();
2009-06-19 04:29:08 +02:00
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);
2007-12-19 15:35:52 +01:00
mtxUnlock();
2009-06-19 04:29:08 +02:00
if (err != 0)
{
system_call_failed::raise("pthread_cond_broadcast", err);
}
}
}
#endif // COMMON_CLASSES_SEMAPHORE_COND_VAR
}
2007-12-19 15:35:52 +01:00