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
|
|
|
|
2007-12-19 15:35:52 +01:00
|
|
|
#include "../jrd/gdsassert.h"
|
2003-09-16 22:45:31 +02:00
|
|
|
#ifdef WIN_NT
|
2007-11-17 11:16:04 +01:00
|
|
|
// Note: Windows does not need signal safe version of the class
|
2003-09-16 22:45:31 +02:00
|
|
|
|
|
|
|
#include <windows.h>
|
|
|
|
#include <limits.h>
|
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
namespace Firebird
|
|
|
|
{
|
2003-09-16 22:45:31 +02:00
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
class Semaphore
|
|
|
|
{
|
2003-09-16 22:45:31 +02:00
|
|
|
private:
|
|
|
|
HANDLE hSemaphore;
|
|
|
|
public:
|
2007-11-17 11:16:04 +01:00
|
|
|
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
|
|
|
}
|
2007-11-17 11:16:04 +01:00
|
|
|
~Semaphore()
|
|
|
|
{
|
2004-03-11 06:30:07 +01:00
|
|
|
if (hSemaphore && !CloseHandle(hSemaphore))
|
|
|
|
system_call_failed::raise("CloseHandle");
|
|
|
|
}
|
2003-09-16 22:45:31 +02:00
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
bool tryEnter(int seconds = 0)
|
|
|
|
{
|
2003-09-16 22:45:31 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
void release(SLONG count = 1)
|
|
|
|
{
|
2003-09-16 22:45:31 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2007-11-12 16:18:49 +01:00
|
|
|
} // namespace Firebird
|
|
|
|
|
|
|
|
#else //WIN_NT
|
|
|
|
|
2007-11-15 12:31:56 +01:00
|
|
|
#ifdef MULTI_THREAD
|
|
|
|
|
2007-11-12 16:18:49 +01:00
|
|
|
#ifdef HAVE_SEMAPHORE_H
|
|
|
|
|
|
|
|
#include <semaphore.h>
|
|
|
|
#include <errno.h>
|
2007-12-19 15:35:52 +01:00
|
|
|
#include <time.h>
|
2007-12-07 13:19:37 +01:00
|
|
|
#ifndef WORKING_SEM_INIT
|
|
|
|
#include <fcntl.h>
|
2007-12-19 15:35:52 +01:00
|
|
|
#if defined(DARWIN)
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
#define MIXED_SEMAPHORE_AND_FILE_HANDLE
|
2007-12-07 13:19:37 +01:00
|
|
|
#endif
|
2007-12-19 15:35:52 +01:00
|
|
|
#endif
|
2007-12-22 01:53:39 +01:00
|
|
|
#endif // WORKING_SEM_INIT
|
2007-11-12 16:18:49 +01:00
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
namespace Firebird
|
|
|
|
{
|
2007-12-07 13:19:37 +01:00
|
|
|
#ifndef WORKING_SEM_INIT
|
|
|
|
static const char* semName = "/firebird_temp_sem";
|
|
|
|
#endif
|
2007-11-12 16:18:49 +01:00
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
class SignalSafeSemaphore
|
|
|
|
{
|
2007-11-12 16:18:49 +01:00
|
|
|
private:
|
2007-12-07 13:19:37 +01:00
|
|
|
#ifdef WORKING_SEM_INIT
|
|
|
|
sem_t sem[1];
|
|
|
|
#else
|
|
|
|
sem_t* sem;
|
2007-12-19 15:35:52 +01:00
|
|
|
#ifdef MIXED_SEMAPHORE_AND_FILE_HANDLE
|
|
|
|
static bool divorceDone;
|
|
|
|
static SignalSafeSemaphore* initialList;
|
|
|
|
void linkToInitialList();
|
|
|
|
SignalSafeSemaphore* next;
|
2007-12-07 13:19:37 +01:00
|
|
|
#endif
|
2007-12-22 01:53:39 +01:00
|
|
|
#endif // WORKING_SEM_INIT
|
2007-11-12 16:18:49 +01:00
|
|
|
bool init;
|
|
|
|
public:
|
2007-12-19 15:35:52 +01:00
|
|
|
#ifdef MIXED_SEMAPHORE_AND_FILE_HANDLE
|
2007-12-27 14:47:38 +01:00
|
|
|
static bool SignalSafeSemaphore::checkHandle(int n);
|
2007-12-19 15:35:52 +01:00
|
|
|
#endif
|
2007-11-17 18:22:41 +01:00
|
|
|
SignalSafeSemaphore()
|
|
|
|
: init(false)
|
2007-11-17 11:16:04 +01:00
|
|
|
{
|
2007-12-07 13:19:37 +01:00
|
|
|
#ifdef WORKING_SEM_INIT
|
|
|
|
if (sem_init(sem, 0, 0) == -1) {
|
2007-11-12 16:18:49 +01:00
|
|
|
system_call_failed::raise("sem_init");
|
|
|
|
}
|
2007-12-07 13:19:37 +01:00
|
|
|
#else
|
|
|
|
sem = sem_open(semName, O_CREAT | O_EXCL, 0700, 0);
|
2007-12-19 15:35:52 +01:00
|
|
|
#if defined(DARWIN) && defined(__ppc__)
|
2007-12-22 01:53:39 +01:00
|
|
|
if (sem == (sem_t*) SEM_FAILED) {
|
2007-12-19 15:35:52 +01:00
|
|
|
#else
|
2007-12-07 13:19:37 +01:00
|
|
|
if (sem == SEM_FAILED) {
|
2007-12-19 15:35:52 +01:00
|
|
|
#endif
|
2007-12-07 13:19:37 +01:00
|
|
|
system_call_failed::raise("sem_open");
|
|
|
|
}
|
|
|
|
sem_unlink(semName);
|
2007-12-19 15:35:52 +01:00
|
|
|
#ifdef MIXED_SEMAPHORE_AND_FILE_HANDLE
|
|
|
|
linkToInitialList();
|
|
|
|
#endif
|
2007-12-07 13:19:37 +01:00
|
|
|
#endif
|
2007-11-12 16:18:49 +01:00
|
|
|
init = true;
|
|
|
|
}
|
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
~SignalSafeSemaphore()
|
|
|
|
{
|
2007-11-12 16:18:49 +01:00
|
|
|
fb_assert(init == true);
|
2007-12-07 13:19:37 +01:00
|
|
|
#ifdef WORKING_SEM_INIT
|
|
|
|
if (sem_destroy(sem) == -1) {
|
2007-11-12 16:18:49 +01:00
|
|
|
system_call_failed::raise("sem_destroy");
|
|
|
|
}
|
2007-12-07 13:19:37 +01:00
|
|
|
#else
|
|
|
|
if (sem_close(sem) == -1) {
|
|
|
|
system_call_failed::raise("sem_close");
|
|
|
|
}
|
|
|
|
#endif
|
2007-11-12 16:18:49 +01:00
|
|
|
init = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
void enter()
|
|
|
|
{
|
2007-11-12 16:18:49 +01:00
|
|
|
fb_assert(init == true);
|
|
|
|
do {
|
2007-12-07 13:19:37 +01:00
|
|
|
if (sem_wait(sem) != -1)
|
2007-11-12 16:18:49 +01:00
|
|
|
return;
|
|
|
|
} while (errno == EINTR);
|
|
|
|
system_call_failed::raise("semaphore.h: enter: sem_wait()");
|
|
|
|
}
|
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
void release(SLONG count = 1)
|
|
|
|
{
|
2007-11-12 16:18:49 +01:00
|
|
|
fb_assert(init == true);
|
|
|
|
for (int i = 0; i < count; i++)
|
2007-12-28 01:14:00 +01:00
|
|
|
{
|
2007-12-07 13:50:43 +01:00
|
|
|
if (sem_post(sem) == -1)
|
2007-12-27 11:55:58 +01:00
|
|
|
{
|
2007-11-12 16:18:49 +01:00
|
|
|
system_call_failed::raise("semaphore.h: release: sem_post()");
|
2007-12-27 11:55:58 +01:00
|
|
|
}
|
2007-12-28 01:14:00 +01:00
|
|
|
}
|
2007-11-12 16:18:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_SEM_TIMEDWAIT
|
2007-11-17 01:38:16 +01:00
|
|
|
// In case when sem_timedwait() is implemented by host OS,
|
|
|
|
// class SignalSafeSemaphore may have this function:
|
2007-11-17 11:16:04 +01:00
|
|
|
bool tryEnter(int seconds = 0)
|
|
|
|
{
|
2007-11-12 16:18:49 +01:00
|
|
|
// Return true in case of success
|
|
|
|
fb_assert(init == true);
|
2007-11-17 11:16:04 +01:00
|
|
|
if (seconds == 0)
|
|
|
|
{
|
2007-11-12 16:18:49 +01:00
|
|
|
// Instant try
|
|
|
|
do {
|
2007-12-07 13:19:37 +01:00
|
|
|
if (sem_trywait(sem) != -1)
|
2007-11-12 16:18:49 +01:00
|
|
|
return true;
|
|
|
|
} while (errno == EINTR);
|
|
|
|
if (errno == EAGAIN)
|
|
|
|
return false;
|
|
|
|
system_call_failed::raise("sem_trywait");
|
|
|
|
}
|
2007-11-17 11:16:04 +01:00
|
|
|
if (seconds < 0)
|
|
|
|
{
|
2007-11-12 16:18:49 +01:00
|
|
|
// Unlimited wait, like enter()
|
|
|
|
do {
|
2007-12-07 13:19:37 +01:00
|
|
|
if (sem_wait(sem) != -1)
|
2007-11-12 16:18:49 +01:00
|
|
|
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;
|
|
|
|
int errcode = 0;
|
|
|
|
do {
|
2007-12-07 13:19:37 +01:00
|
|
|
int rc = sem_timedwait(sem, &timeout);
|
2007-11-12 16:18:49 +01:00
|
|
|
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
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef HAVE_SEM_TIMEDWAIT
|
|
|
|
// In case when sem_timedwait() is implemented by host OS,
|
|
|
|
// SignalSafeSemaphore and Semaphore are just the same
|
|
|
|
typedef SignalSafeSemaphore Semaphore;
|
|
|
|
#endif //HAVE_SEM_TIMEDWAIT
|
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
|
|
|
|
2007-11-12 16:18:49 +01:00
|
|
|
#endif //HAVE_SEMAPHORE_H
|
2003-09-16 22:45:31 +02:00
|
|
|
|
2007-11-12 16:18:49 +01:00
|
|
|
#ifndef HAVE_SEM_TIMEDWAIT
|
2007-11-17 11:16:04 +01:00
|
|
|
// Should implement Semaphore independent from SignalSafeSemaphore.
|
2007-11-12 16:18:49 +01:00
|
|
|
// In the worst case no SignalSafeSemaphore at all (and no SS for that platform).
|
2003-09-16 22:45:31 +02:00
|
|
|
|
2007-12-07 13:19:37 +01:00
|
|
|
#if defined(HAVE_SYS_SEM_H) && defined(HAVE_SEMTIMEDOP)
|
2007-11-12 16:18:49 +01:00
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/ipc.h>
|
|
|
|
#include <sys/sem.h>
|
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
namespace Firebird
|
|
|
|
{
|
2007-11-12 16:18:49 +01:00
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
class Semaphore
|
|
|
|
{
|
2007-11-12 16:18:49 +01:00
|
|
|
private:
|
|
|
|
int semId;
|
2007-11-17 11:16:04 +01:00
|
|
|
union semun
|
|
|
|
{
|
2007-11-12 16:18:49 +01:00
|
|
|
int val;
|
|
|
|
struct semid_ds* buf;
|
|
|
|
unsigned short* array;
|
|
|
|
};
|
|
|
|
public:
|
2007-11-17 18:22:41 +01:00
|
|
|
Semaphore()
|
|
|
|
: semId(semget(IPC_PRIVATE, 1, 0600))
|
2007-11-17 11:16:04 +01:00
|
|
|
{
|
2007-11-12 16:18:49 +01:00
|
|
|
if (semId < 0)
|
|
|
|
system_call_failed::raise("semaphore.h: Semaphore: semget()");
|
|
|
|
semun arg;
|
|
|
|
arg.val = 0;
|
|
|
|
if (semctl(semId, 0, SETVAL, arg) < 0)
|
|
|
|
system_call_failed::raise("semaphore.h: Semaphore: semctl()");
|
|
|
|
}
|
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
~Semaphore()
|
|
|
|
{
|
2007-11-12 16:18:49 +01:00
|
|
|
semun arg;
|
|
|
|
if (semctl(semId, 0, IPC_RMID, arg) < 0)
|
|
|
|
system_call_failed::raise("semaphore.h: ~Semaphore: semctl()");
|
|
|
|
}
|
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
bool tryEnter(int seconds = 0) // Returns true in case of success
|
|
|
|
{
|
2007-11-12 16:18:49 +01:00
|
|
|
timespec timeout;
|
|
|
|
timeout.tv_sec = time(NULL) + seconds;
|
|
|
|
timeout.tv_nsec = 0;
|
|
|
|
timespec* t = &timeout;
|
|
|
|
|
|
|
|
sembuf sb;
|
|
|
|
sb.sem_num = 0;
|
|
|
|
sb.sem_op = -1;
|
|
|
|
sb.sem_flg = 0;
|
|
|
|
|
|
|
|
if (seconds < 0) {
|
|
|
|
// Unlimited wait
|
|
|
|
t = 0;
|
|
|
|
}
|
|
|
|
else if (seconds == 0) {
|
|
|
|
// just try
|
|
|
|
t = 0;
|
|
|
|
sb.sem_flg = IPC_NOWAIT;
|
|
|
|
}
|
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
while (semtimedop(semId, &sb, 1, t) < 0)
|
|
|
|
{
|
2007-11-17 18:22:41 +01:00
|
|
|
switch (errno)
|
|
|
|
{
|
2007-11-12 16:18:49 +01:00
|
|
|
case EAGAIN:
|
|
|
|
return false;
|
|
|
|
case EINTR:
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
system_call_failed::raise("semaphore.h: tryEnter: semop()");
|
|
|
|
}
|
|
|
|
|
2007-11-19 11:30:59 +01:00
|
|
|
return true;
|
2007-11-12 16:18:49 +01:00
|
|
|
}
|
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
void enter()
|
|
|
|
{
|
2007-11-12 16:18:49 +01:00
|
|
|
tryEnter(-1);
|
|
|
|
}
|
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
void release(SLONG count = 1)
|
|
|
|
{
|
2007-11-12 16:18:49 +01:00
|
|
|
sembuf sb;
|
|
|
|
sb.sem_num = 0;
|
|
|
|
sb.sem_op = 1;
|
|
|
|
sb.sem_flg = 0;
|
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
while (semop(semId, &sb, 1) < 0)
|
|
|
|
{
|
2007-11-12 16:18:49 +01:00
|
|
|
if (errno == EINTR) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
system_call_failed::raise("semaphore.h: release: semop()");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace Firebird
|
|
|
|
|
2007-12-07 13:19:37 +01:00
|
|
|
#else //defined(HAVE_SYS_SEM_H) && defined(HAVE_SEMTIMEDOP)
|
|
|
|
|
|
|
|
// This implementation will NOT work with FB > 2.1
|
|
|
|
#ifdef SOLARIS
|
|
|
|
#error Mutex/Condition based semaphore is NOT OK for Solaris
|
|
|
|
#endif
|
2007-06-06 11:03:33 +02:00
|
|
|
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
namespace Firebird
|
|
|
|
{
|
2007-06-06 11:03:33 +02:00
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
class Semaphore
|
|
|
|
{
|
2007-06-06 11:03:33 +02:00
|
|
|
private:
|
|
|
|
pthread_mutex_t mu;
|
|
|
|
pthread_cond_t cv;
|
2007-11-17 11:16:04 +01:00
|
|
|
bool init;
|
2007-06-06 11:03:33 +02:00
|
|
|
public:
|
2007-11-17 18:22:41 +01:00
|
|
|
Semaphore()
|
|
|
|
: init(false)
|
2007-11-17 11:16:04 +01:00
|
|
|
{
|
2007-06-06 11:03:33 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
init = true;
|
|
|
|
}
|
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
~Semaphore()
|
|
|
|
{
|
2007-06-06 11:03:33 +02:00
|
|
|
fb_assert(init == true);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
init = false;
|
|
|
|
}
|
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
bool tryEnter(int seconds = 0)
|
|
|
|
{
|
2007-06-06 11:03:33 +02:00
|
|
|
bool rt = false;
|
|
|
|
int err2 = 0;
|
|
|
|
int err = 0;
|
|
|
|
// Return true in case of success
|
|
|
|
fb_assert(init == true);
|
2007-11-17 11:16:04 +01:00
|
|
|
if (seconds == 0)
|
|
|
|
{
|
2007-06-06 11:03:33 +02:00
|
|
|
// Instant try
|
|
|
|
|
|
|
|
err2 = pthread_mutex_trylock(&mu);
|
2007-11-17 11:16:04 +01:00
|
|
|
if (err2 == 0)
|
|
|
|
{
|
2007-06-06 11:03:33 +02:00
|
|
|
do {
|
|
|
|
err = pthread_cond_wait(&cv, &mu);
|
|
|
|
if (err != 0) {
|
|
|
|
rt = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
rt = true;
|
|
|
|
} while (err == EINTR);
|
|
|
|
if (err == ETIMEDOUT)
|
|
|
|
rt = false;
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&mu);
|
|
|
|
return rt;
|
|
|
|
}
|
2007-11-17 11:16:04 +01:00
|
|
|
if (err2 == EBUSY)
|
|
|
|
return false;
|
|
|
|
|
2007-06-06 11:03:33 +02:00
|
|
|
system_call_failed::raise("pthread_mutex_trylock", err2);
|
|
|
|
}
|
2007-11-17 18:22:41 +01:00
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
if (seconds < 0)
|
|
|
|
{
|
2007-06-06 11:03:33 +02:00
|
|
|
// Unlimited wait, like enter()
|
|
|
|
err2 = pthread_mutex_lock(&mu);
|
2007-11-17 11:16:04 +01:00
|
|
|
if (err2 == 0)
|
|
|
|
{
|
2007-06-06 11:03:33 +02:00
|
|
|
do {
|
|
|
|
err = pthread_cond_wait(&cv, &mu);
|
|
|
|
if (err != 0) {
|
|
|
|
rt = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
rt = true;
|
|
|
|
} while (err == EINTR);
|
|
|
|
if (err == ETIMEDOUT)
|
|
|
|
rt = false;
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&mu);
|
|
|
|
return rt;
|
|
|
|
}
|
2007-11-17 11:16:04 +01:00
|
|
|
if (err2 == EBUSY)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
system_call_failed::raise("pthread_mutex_lock", err2);
|
2007-06-06 11:03:33 +02:00
|
|
|
} //seconds < 0
|
2007-11-12 16:18:49 +01:00
|
|
|
|
2007-06-06 11:03:33 +02:00
|
|
|
// Wait with timeout
|
|
|
|
timespec timeout;
|
|
|
|
timeout.tv_sec = time(NULL) + seconds;
|
|
|
|
timeout.tv_nsec = 0;
|
|
|
|
err2 = pthread_mutex_lock(&mu);
|
2007-11-12 16:18:49 +01:00
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
if (err2 == 0)
|
|
|
|
{
|
2007-06-06 11:03:33 +02:00
|
|
|
do {
|
|
|
|
err = pthread_cond_timedwait(&cv, &mu, &timeout);
|
|
|
|
if (err != 0) {
|
|
|
|
rt = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
rt = true;
|
|
|
|
} while (err == EINTR);
|
|
|
|
if (err == ETIMEDOUT)
|
|
|
|
rt = false;
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&mu);
|
|
|
|
return rt;
|
|
|
|
}
|
2007-11-17 11:16:04 +01:00
|
|
|
if (err2 == EBUSY)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
system_call_failed::raise("pthread_mutex_lock", err2);
|
2007-11-12 16:18:49 +01:00
|
|
|
|
|
|
|
return false; //compiler silencer
|
2007-06-06 11:03:33 +02:00
|
|
|
}
|
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
void enter()
|
|
|
|
{
|
2007-06-06 11:03:33 +02:00
|
|
|
fb_assert(init == true);
|
|
|
|
int err = 0;
|
|
|
|
int err2 = pthread_mutex_lock(&mu);
|
2007-11-17 11:16:04 +01:00
|
|
|
if (err2 == 0)
|
|
|
|
{
|
2006-04-17 00:01:41 +02:00
|
|
|
do {
|
2007-06-06 11:03:33 +02:00
|
|
|
err = pthread_cond_wait(&cv, &mu);
|
2006-04-17 00:01:41 +02:00
|
|
|
if (err == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (err == EINTR);
|
|
|
|
|
2007-06-06 11:03:33 +02:00
|
|
|
pthread_mutex_unlock(&mu);
|
2006-04-17 00:01:41 +02:00
|
|
|
}
|
|
|
|
else
|
2007-06-06 11:03:33 +02:00
|
|
|
system_call_failed::raise("pthread_mutex_lock", err2);
|
2004-05-21 16:14:34 +02:00
|
|
|
}
|
|
|
|
|
2007-11-17 11:16:04 +01:00
|
|
|
void release(SLONG count = 1)
|
|
|
|
{
|
2006-04-16 21:54:26 +02:00
|
|
|
int err = 0;
|
2004-05-21 16:14:34 +02:00
|
|
|
fb_assert(init == true);
|
|
|
|
for (int i = 0; i < count; i++)
|
2006-04-16 21:54:26 +02:00
|
|
|
{
|
2007-06-06 11:03:33 +02:00
|
|
|
err = pthread_mutex_lock(&mu) ;
|
|
|
|
if (err == 0) {
|
|
|
|
err = pthread_cond_broadcast(&cv);
|
2006-04-12 11:25:56 +02:00
|
|
|
if (err != 0) {
|
2007-06-06 11:03:33 +02:00
|
|
|
system_call_failed::raise("pthread_cond_broadcast", err);
|
2004-05-23 08:07:46 +02:00
|
|
|
}
|
2004-05-21 16:14:34 +02:00
|
|
|
|
2007-06-06 11:03:33 +02:00
|
|
|
pthread_mutex_unlock(&mu);
|
2006-04-06 10:18:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2004-05-21 16:14:34 +02:00
|
|
|
//gds__log("Error on semaphore.h: release");
|
2007-06-06 11:03:33 +02:00
|
|
|
system_call_failed::raise("pthread_mutex_lock", err);
|
2004-05-21 16:14:34 +02:00
|
|
|
}
|
2006-04-16 21:54:26 +02:00
|
|
|
}
|
2004-05-21 16:14:34 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2004-06-14 01:45:02 +02:00
|
|
|
} // namespace Firebird
|
2004-05-21 16:14:34 +02:00
|
|
|
|
2007-12-07 13:19:37 +01:00
|
|
|
#endif //defined(HAVE_SYS_SEM_H) && defined(HAVE_SEMTIMEDOP)
|
2007-06-05 09:11:39 +02:00
|
|
|
|
2007-11-12 16:18:49 +01:00
|
|
|
#endif //HAVE_SEM_TIMEDWAIT
|
2003-09-16 22:45:31 +02:00
|
|
|
|
2007-11-15 12:31:56 +01:00
|
|
|
#else //MULTI_THREAD
|
|
|
|
|
|
|
|
namespace Firebird
|
|
|
|
{
|
|
|
|
class SignalSafeSemaphore
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
SignalSafeSemaphore() { }
|
|
|
|
~SignalSafeSemaphore() { }
|
|
|
|
|
|
|
|
void enter() { }
|
|
|
|
void release(SLONG count = 1) { }
|
|
|
|
bool tryEnter(int seconds = 0) { return true; }
|
|
|
|
};
|
|
|
|
typedef SignalSafeSemaphore Semaphore;
|
|
|
|
} // namespace Firebird
|
|
|
|
|
|
|
|
#endif //MULTI_THREAD
|
|
|
|
|
2007-11-12 16:18:49 +01:00
|
|
|
#endif //WIN_NT
|
2003-09-16 22:45:31 +02:00
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
#endif // CLASSES_SEMAPHORE_H
|