8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-31 23:23:04 +01:00
firebird-mirror/src/common/classes/semaphore.h

366 lines
7.9 KiB
C
Raw Normal View History

/*
* PROGRAM: Client/Server Common Code
* MODULE: semaphore.h
* DESCRIPTION: Semaphore lock
*
* 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 Nickolay Samofatov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2004 Nickolay Samofatov <nickolay@broadviewsoftware.com>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*
*/
#ifndef CLASSES_SEMAPHORE_H
#define CLASSES_SEMAPHORE_H
#ifdef WIN_NT
#include <windows.h>
#include <limits.h>
namespace Firebird {
class Semaphore {
private:
HANDLE hSemaphore;
public:
Semaphore() {
hSemaphore = CreateSemaphore(NULL, 0 /*initial count*/,
INT_MAX, NULL);
if (hSemaphore == NULL)
system_call_failed::raise("CreateSemaphore");
}
~Semaphore() {
if (hSemaphore && !CloseHandle(hSemaphore))
system_call_failed::raise("CloseHandle");
}
bool tryEnter(int seconds = 0) {
DWORD result = WaitForSingleObject(
hSemaphore, seconds >= 0 ? seconds * 1000 : INFINITE);
if (result == WAIT_FAILED)
system_call_failed::raise("WaitForSingleObject");
return result != WAIT_TIMEOUT;
}
void release(SLONG count = 1) {
if (!ReleaseSemaphore(hSemaphore, count, NULL))
system_call_failed::raise("ReleaseSemaphore");
}
};
} // namespace Firebird
#else
#ifdef MULTI_THREAD
#ifdef SOLARIS_MT
2005-08-18 11:33:25 +02:00
/* This is implementation of FB::Semaphore
on Solaris using conditional variable protected by mutex.
2005-08-18 11:33:25 +02:00
Reasons is:
1) Old (~1985) troubles reported to Borland about semaphores on Solaris
2) No gds_lock_manager
3) No sem_timedwait on Solaris
4) thread functions does not garantie setting errno 12 apr 2006
2005-08-18 11:33:25 +02:00
Readings is:
2005-08-19 08:04:10 +02:00
1) http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libpthread/thread/thr_sem.c?rev=1.15
2005-08-18 11:33:25 +02:00
2) http://docs.sun.com/app/docs/doc/802-5747-03/6i9g1bhqp?a=view
3) http://docs.sun.com/app/docs/doc/802-5938?a=expand
Status:
12 apr 2006 add looping if EINTR caused
Still under testings
Konstantin Kuznetsov kkuznetsov at the users of the sf net
thank's to Claudio ...
*/
#include <thread.h>
#include <synch.h>
#include <semaphore.h>
#include <errno.h>
#include <sys/stat.h> //for timestruct_t
namespace Firebird {
class Semaphore {
private:
mutex_t mu;
cond_t cv;
bool init;
int err; //thread functions does not garantie setting errno
public:
Semaphore() : init(false) {
/* USINC_PROCESS got ability to syncronise Classic
*/
err = 0;
err = mutex_init(&mu, USYNC_PROCESS, NULL);
if (err != 0) {
//gds__log("Error on semaphore.h: constructor");
system_call_failed::raise("Semaphore:init:mutex_init", err);
}
err = cond_init(&cv, USYNC_PROCESS, NULL);
if ( err != 0) {
//gds__log("Error on semaphore.h: constructor");
system_call_failed::raise("Semaphore:init:cond_init",err);
}
init = true;
}
~Semaphore() {
fb_assert(init == true);
err = 0;
err = mutex_destroy(&mu);
if (err != 0) {
//gds__log("Error on semaphore.h: destructor");
system_call_failed::raise("Semaphore:~mutex_destroy",err);
}
err = cond_destroy(&cv);
if (err != 0) {
//gds__log("Error on semaphore.h: destructor");
system_call_failed::raise("Semaphore:~cond_destroy",err);
}
init = false;
}
bool tryEnter(int seconds = 0) {
bool rt = false;
int err2 = 0;
// Return true in case of success
fb_assert(init == true);
if (seconds == 0) {
// Instant try
err2 = mutex_trylock(&mu);
if (err2 != 0) {
do {
err = cond_wait(&cv, &mu);
if (err != 0) {
rt = false;
}
else
rt = true;
} while (err == EINTR);
if (err == ETIMEDOUT)
rt = false;
mutex_unlock(&mu);
return rt;
}
else if (err2 == EBUSY) {
rt = false;
return rt;
}
system_call_failed::raise("Semaphore:tryEnter:mutex_trylock", err2);
}
if (seconds < 0) {
// Unlimited wait, like enter()
err2 = mutex_lock(&mu);
if (err2 != 0) {
do {
err = cond_wait(&cv, &mu);
if (err != 0) {
rt = false;
}
else
rt = true;
} while (err == EINTR);
if (err == ETIMEDOUT)
rt = false;
mutex_unlock(&mu);
return rt;
}
else if (err2 == EBUSY) {
rt = false;
return rt;
}
else
system_call_failed::raise("Semaphore:tryEnter:mutex_lock", err2);
} //seconds < 0
// Wait with timeout
timestruc_t timeout;
timeout.tv_sec = time(NULL) + seconds;
timeout.tv_nsec = 0;
err2 = mutex_lock(&mu) ;
if (err2 != 0) {
do {
err = cond_timedwait(&cv, &mu, &timeout);
if (err != 0) {
rt = false;
}
else
rt = true;
} while (err == EINTR);
if (err == ETIMEDOUT)
rt = false;
mutex_unlock(&mu);
return rt;
}
else if (err2 == EBUSY) {
rt = false;
return rt;
}
else
system_call_failed::raise("Semaphore:tryEnter:mutex_lock", err2);
}
void enter() {
fb_assert(init == true);
int err2 = 0;
err2 = mutex_lock(&mu);
if (err2 != 0) {
do {
err = cond_wait(&cv, &mu);
if (err == 0) {
break;
}
} while (err == EINTR);
mutex_unlock(&mu);
}
else
system_call_failed::raise("Semaphore:enter:mutex_lock", err2);
}
void release(SLONG count = 1) {
int err2 = 0;
fb_assert(init == true);
for (int i = 0; i < count; i++)
err2 = mutex_lock(&mu) ;
if (err2 != 0) {
err = cond_broadcast(&cv);
if (err != 0) {
system_call_failed::raise("Semaphore:release:cond_signal", err);
}
mutex_unlock(&mu);
2006-04-06 10:18:53 +02:00
}
else {
//gds__log("Error on semaphore.h: release");
system_call_failed::raise("Semaphore:release:mutex_lock", err2);
}
}
};
} // namespace Firebird
#else
#include <semaphore.h>
#include <errno.h>
namespace Firebird {
class Semaphore {
private:
sem_t sem;
bool init;
public:
Semaphore() : init(false) {
if (sem_init(&sem, 0, 0) == -1) {
//gds__log("Error on semaphore.h: constructor");
system_call_failed::raise("sem_init");
}
init = true;
}
~Semaphore() {
2003-11-04 00:59:24 +01:00
fb_assert(init == true);
if (sem_destroy(&sem) == -1) {
//gds__log("Error on semaphore.h: destructor");
system_call_failed::raise("sem_destroy");
}
init = false;
}
bool tryEnter(int seconds = 0) {
// Return true in case of success
2003-11-04 00:59:24 +01:00
fb_assert(init == true);
if (seconds == 0) {
// Instant try
2005-10-28 17:25:15 +02:00
do {
if (sem_trywait(&sem) != -1)
return true;
} while (errno == EINTR);
if (errno == EAGAIN)
return false;
system_call_failed::raise("sem_trywait");
}
if (seconds < 0) {
// Unlimited wait, like enter()
2005-10-28 17:25:15 +02:00
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) + seconds;
timeout.tv_nsec = 0;
2005-10-28 17:25:15 +02:00
do {
if (sem_timedwait(&sem, &timeout) == 0)
return true;
} while (errno == EINTR);
if (errno == ETIMEDOUT) {
return false;
}
system_call_failed::raise("sem_timedwait");
2006-01-16 16:39:55 +01:00
return false; // avoid warnings
}
void enter() {
2003-11-04 00:59:24 +01:00
fb_assert(init == true);
2005-10-28 17:25:15 +02:00
do {
if (sem_wait(&sem) != -1)
return;
} while (errno == EINTR);
//gds__log("Error on semaphore.h: enter");
system_call_failed::raise("sem_wait");
}
void release(SLONG count = 1) {
2003-11-04 00:59:24 +01:00
fb_assert(init == true);
2005-10-28 17:25:15 +02:00
for (int i = 0; i < count; i++)
if (sem_post(&sem) == -1) {
//gds__log("Error on semaphore.h: release");
system_call_failed::raise("sem_post");
}
}
};
} // namespace Firebird
2004-12-25 10:44:03 +01:00
#endif /* SOLARIS_MT */
#endif /*MULTI_THREAD*/
#endif /*!WIN_NT*/
#endif // CLASSES_SEMAPHORE_H