2003-09-16 22:45:31 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: Client/Server Common Code
|
|
|
|
* MODULE: semaphore.h
|
|
|
|
* DESCRIPTION: Semaphore lock
|
|
|
|
*
|
2004-06-30 03:26:40 +02:00
|
|
|
* 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.
|
2003-09-16 22:45:31 +02:00
|
|
|
*
|
2004-06-30 03:26:40 +02:00
|
|
|
* 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.
|
2003-09-16 22:45:31 +02:00
|
|
|
*
|
2004-06-30 03:26:40 +02:00
|
|
|
* The Original Code was created by Nickolay Samofatov
|
|
|
|
* for the Firebird Open Source RDBMS project.
|
2003-09-16 22:45:31 +02:00
|
|
|
*
|
2004-06-30 03:26:40 +02:00
|
|
|
* Copyright (c) 2004 Nickolay Samofatov <nickolay@broadviewsoftware.com>
|
|
|
|
* and all contributors signed below.
|
|
|
|
*
|
|
|
|
* All Rights Reserved.
|
|
|
|
* Contributor(s): ______________________________________.
|
|
|
|
*
|
|
|
|
*
|
2003-09-16 22:45:31 +02:00
|
|
|
*/
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
#ifndef CLASSES_SEMAPHORE_H
|
|
|
|
#define CLASSES_SEMAPHORE_H
|
2003-09-16 22:45:31 +02:00
|
|
|
|
|
|
|
#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);
|
2004-03-11 06:30:07 +01:00
|
|
|
if (hSemaphore == NULL)
|
|
|
|
system_call_failed::raise("CreateSemaphore");
|
2003-09-16 22:45:31 +02:00
|
|
|
}
|
2004-03-11 06:30:07 +01:00
|
|
|
~Semaphore() {
|
|
|
|
if (hSemaphore && !CloseHandle(hSemaphore))
|
|
|
|
system_call_failed::raise("CloseHandle");
|
|
|
|
}
|
2003-09-16 22:45:31 +02:00
|
|
|
|
|
|
|
bool tryEnter(int seconds = 0) {
|
|
|
|
DWORD result = WaitForSingleObject(
|
2003-11-01 11:26:43 +01:00
|
|
|
hSemaphore, seconds >= 0 ? seconds * 1000 : INFINITE);
|
2003-09-16 22:45:31 +02:00
|
|
|
if (result == WAIT_FAILED)
|
2004-03-01 04:35:23 +01:00
|
|
|
system_call_failed::raise("WaitForSingleObject");
|
2003-09-16 22:45:31 +02:00
|
|
|
return result != WAIT_TIMEOUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
void release(SLONG count = 1) {
|
|
|
|
if (!ReleaseSemaphore(hSemaphore, count, NULL))
|
2004-03-01 04:35:23 +01:00
|
|
|
system_call_failed::raise("ReleaseSemaphore");
|
2003-09-16 22:45:31 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2004-06-14 01:45:02 +02:00
|
|
|
} // namespace Firebird
|
2003-09-16 22:45:31 +02:00
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
#ifdef MULTI_THREAD
|
|
|
|
|
2004-12-24 10:35:48 +01:00
|
|
|
#ifdef SOLARIS_MT
|
2005-08-18 11:33:25 +02:00
|
|
|
/* This is implementation of FB::Semaphore
|
2004-05-24 13:23:41 +02:00
|
|
|
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
|
|
|
|
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
|
2005-02-17 13:42:49 +01:00
|
|
|
|
2004-05-24 13:23:41 +02:00
|
|
|
Konstantin
|
|
|
|
thank's to Claudio ...
|
2004-05-21 16:14:34 +02:00
|
|
|
*/
|
|
|
|
#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;
|
|
|
|
public:
|
|
|
|
Semaphore() : init(false) {
|
|
|
|
/* USINC_PROCESS got ability to syncronise Classic
|
|
|
|
*/
|
2004-05-23 08:07:46 +02:00
|
|
|
if ( mutex_init(&mu, USYNC_PROCESS, NULL) != 0) {
|
2004-05-21 16:14:34 +02:00
|
|
|
//gds__log("Error on semaphore.h: constructor");
|
|
|
|
system_call_failed::raise("mutex_init");
|
|
|
|
}
|
2004-11-24 10:22:07 +01:00
|
|
|
if (cond_init(&cv, USYNC_PROCESS, NULL) != 0) {
|
2004-05-21 16:14:34 +02:00
|
|
|
//gds__log("Error on semaphore.h: constructor");
|
|
|
|
system_call_failed::raise("cond_init");
|
|
|
|
}
|
|
|
|
init = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
~Semaphore() {
|
|
|
|
fb_assert(init == true);
|
|
|
|
if (mutex_destroy(&mu) != 0) {
|
|
|
|
//gds__log("Error on semaphore.h: destructor");
|
|
|
|
system_call_failed::raise("mutex_destroy");
|
|
|
|
}
|
|
|
|
if (cond_destroy(&cv) != 0) {
|
|
|
|
//gds__log("Error on semaphore.h: destructor");
|
|
|
|
system_call_failed::raise("cond_destroy");
|
|
|
|
}
|
|
|
|
|
|
|
|
init = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bool tryEnter(int seconds = 0) {
|
|
|
|
bool rt = false;
|
|
|
|
// Return true in case of success
|
|
|
|
fb_assert(init == true);
|
|
|
|
if (seconds == 0) {
|
|
|
|
// Instant try
|
2004-05-23 08:07:46 +02:00
|
|
|
if (mutex_trylock(&mu) != 0) {
|
2004-05-21 16:14:34 +02:00
|
|
|
|
2004-05-23 08:07:46 +02:00
|
|
|
if (cond_wait(&cv, &mu) != 0) {
|
|
|
|
rt = false;
|
2004-05-21 16:14:34 +02:00
|
|
|
|
2004-05-23 08:07:46 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
rt = true;
|
|
|
|
if (errno == ETIMEDOUT)
|
|
|
|
rt = false;
|
|
|
|
|
|
|
|
mutex_unlock(&mu);
|
|
|
|
return rt;
|
|
|
|
}
|
|
|
|
else if (errno == EBUSY) {
|
|
|
|
rt = false;
|
|
|
|
return rt;
|
2004-11-07 11:52:36 +01:00
|
|
|
}
|
2004-05-21 16:14:34 +02:00
|
|
|
|
|
|
|
system_call_failed::raise("mutex_lock");
|
|
|
|
}
|
|
|
|
if (seconds < 0) {
|
|
|
|
// Unlimited wait, like enter()
|
2004-05-23 08:07:46 +02:00
|
|
|
if (mutex_lock(&mu) != 0) {
|
2004-05-21 16:14:34 +02:00
|
|
|
|
2004-05-23 08:07:46 +02:00
|
|
|
if (cond_wait(&cv, &mu) != 0) {
|
|
|
|
rt = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
rt = true;
|
|
|
|
|
|
|
|
if (errno == ETIMEDOUT)
|
|
|
|
rt = false;
|
2004-05-21 16:14:34 +02:00
|
|
|
|
2004-05-23 08:07:46 +02:00
|
|
|
mutex_unlock(&mu);
|
|
|
|
return rt;
|
|
|
|
}
|
|
|
|
else if (errno == EBUSY) {
|
|
|
|
rt = false;
|
|
|
|
return rt;
|
|
|
|
}
|
2004-05-21 16:14:34 +02:00
|
|
|
else
|
2004-05-23 08:07:46 +02:00
|
|
|
system_call_failed::raise("mutex_lock");
|
2004-05-21 16:14:34 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
// Wait with timeout
|
|
|
|
timestruc_t timeout;
|
|
|
|
timeout.tv_sec = time(NULL) + seconds;
|
|
|
|
timeout.tv_nsec = 0;
|
2004-05-23 08:07:46 +02:00
|
|
|
if (mutex_lock(&mu) != 0) {
|
|
|
|
|
|
|
|
if (cond_timedwait(&cv, &mu, &timeout) != 0) {
|
|
|
|
rt = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
rt = true;
|
|
|
|
if (errno == ETIMEDOUT)
|
|
|
|
rt = false;
|
|
|
|
|
|
|
|
mutex_unlock(&mu);
|
|
|
|
return rt;
|
|
|
|
}
|
|
|
|
else if (errno == EBUSY) {
|
|
|
|
rt = false;
|
|
|
|
return rt;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
system_call_failed::raise("mutex_lock");
|
2004-05-21 16:14:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void enter() {
|
|
|
|
fb_assert(init == true);
|
2004-05-23 08:07:46 +02:00
|
|
|
if (mutex_lock(&mu) != 0) {
|
2004-05-21 16:14:34 +02:00
|
|
|
|
2004-05-23 08:07:46 +02:00
|
|
|
if (cond_wait(&cv, &mu) != 0) {
|
|
|
|
}
|
|
|
|
// Is the above if() meant to be empty?
|
|
|
|
mutex_unlock(&mu);
|
|
|
|
}
|
2004-05-21 16:14:34 +02:00
|
|
|
else
|
2004-05-23 08:07:46 +02:00
|
|
|
system_call_failed::raise("mutex_lock");
|
2004-05-21 16:14:34 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void release(SLONG count = 1) {
|
|
|
|
fb_assert(init == true);
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
|
2004-05-23 08:07:46 +02:00
|
|
|
if (mutex_lock(&mu) != 0) {
|
2004-05-21 16:14:34 +02:00
|
|
|
|
2004-05-24 13:23:41 +02:00
|
|
|
if (cond_broadcast(&cv) != 0) {
|
2005-08-18 11:33:25 +02:00
|
|
|
system_call_failed::raise("cond_signal");
|
2004-05-23 08:07:46 +02:00
|
|
|
}
|
2004-05-21 16:14:34 +02:00
|
|
|
|
2004-05-23 08:07:46 +02:00
|
|
|
mutex_unlock(&mu);
|
2004-05-21 16:14:34 +02:00
|
|
|
} else {
|
|
|
|
//gds__log("Error on semaphore.h: release");
|
|
|
|
system_call_failed::raise("mutex_lock");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2004-06-14 01:45:02 +02:00
|
|
|
} // namespace Firebird
|
2004-05-21 16:14:34 +02:00
|
|
|
|
|
|
|
|
|
|
|
#else
|
2003-09-16 22:45:31 +02:00
|
|
|
#include <semaphore.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
namespace Firebird {
|
|
|
|
|
|
|
|
class Semaphore {
|
|
|
|
private:
|
|
|
|
sem_t sem;
|
2003-10-30 11:59:32 +01:00
|
|
|
bool init;
|
2003-09-16 22:45:31 +02:00
|
|
|
public:
|
2003-11-01 11:26:43 +01:00
|
|
|
Semaphore() : init(false) {
|
|
|
|
if (sem_init(&sem, 0, 0) == -1) {
|
2004-03-01 04:35:23 +01:00
|
|
|
//gds__log("Error on semaphore.h: constructor");
|
|
|
|
system_call_failed::raise("sem_init");
|
2003-10-30 11:59:32 +01:00
|
|
|
}
|
|
|
|
init = true;
|
2003-09-16 22:45:31 +02:00
|
|
|
}
|
2004-03-01 04:35:23 +01:00
|
|
|
|
2003-09-16 22:45:31 +02:00
|
|
|
~Semaphore() {
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(init == true);
|
2003-10-30 11:59:32 +01:00
|
|
|
if (sem_destroy(&sem) == -1) {
|
2004-03-01 04:35:23 +01:00
|
|
|
//gds__log("Error on semaphore.h: destructor");
|
|
|
|
system_call_failed::raise("sem_destroy");
|
2003-10-30 11:59:32 +01:00
|
|
|
}
|
|
|
|
init = false;
|
|
|
|
|
2003-09-16 22:45:31 +02:00
|
|
|
}
|
2004-03-01 04:35:23 +01:00
|
|
|
|
2003-09-16 22:45:31 +02:00
|
|
|
bool tryEnter(int seconds = 0) {
|
2004-03-01 04:35:23 +01:00
|
|
|
// Return true in case of success
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(init == true);
|
2003-09-16 22:45:31 +02:00
|
|
|
if (seconds == 0) {
|
2004-03-01 04:35:23 +01:00
|
|
|
// Instant try
|
2005-10-28 17:25:15 +02:00
|
|
|
do {
|
|
|
|
if (sem_trywait(&sem) != -1)
|
|
|
|
return true;
|
|
|
|
} while (errno == EINTR);
|
2003-10-30 11:59:32 +01:00
|
|
|
if (errno == EAGAIN)
|
|
|
|
return false;
|
2004-03-01 04:35:23 +01:00
|
|
|
system_call_failed::raise("sem_trywait");
|
2004-01-28 08:50:41 +01:00
|
|
|
}
|
2004-03-01 04:35:23 +01:00
|
|
|
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);
|
2004-03-01 04:35:23 +01:00
|
|
|
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);
|
2004-03-01 04:35:23 +01:00
|
|
|
if (errno == ETIMEDOUT) {
|
|
|
|
return false;
|
2003-09-16 22:45:31 +02:00
|
|
|
}
|
2004-03-01 04:35:23 +01:00
|
|
|
system_call_failed::raise("sem_timedwait");
|
2006-01-16 16:39:55 +01:00
|
|
|
return false; // avoid warnings
|
2003-09-16 22:45:31 +02:00
|
|
|
}
|
2004-03-01 04:35:23 +01:00
|
|
|
|
2003-09-16 22:45:31 +02:00
|
|
|
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");
|
2003-09-16 22:45:31 +02:00
|
|
|
}
|
2004-03-01 04:35:23 +01:00
|
|
|
|
2003-09-16 22:45:31 +02:00
|
|
|
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++)
|
2003-11-01 11:26:43 +01:00
|
|
|
if (sem_post(&sem) == -1) {
|
2004-03-01 04:35:23 +01:00
|
|
|
//gds__log("Error on semaphore.h: release");
|
|
|
|
system_call_failed::raise("sem_post");
|
2003-10-30 11:59:32 +01:00
|
|
|
}
|
2003-09-16 22:45:31 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2004-06-14 01:45:02 +02:00
|
|
|
} // namespace Firebird
|
2003-09-16 22:45:31 +02:00
|
|
|
|
2004-12-25 10:44:03 +01:00
|
|
|
#endif /* SOLARIS_MT */
|
2003-09-16 22:45:31 +02:00
|
|
|
#endif /*MULTI_THREAD*/
|
|
|
|
|
|
|
|
#endif /*!WIN_NT*/
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
#endif // CLASSES_SEMAPHORE_H
|
2003-11-01 11:26:43 +01:00
|
|
|
|