8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-28 02:43:03 +01:00
firebird-mirror/src/jrd/isc_sync.cpp

3235 lines
78 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Access Method
* MODULE: isc_sync.cpp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: General purpose but non-user routines.
*
* The contents of this file are subject to the Interbase 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.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, 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 Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
* 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "XENIX" port
2002-02-16 04:05:21 +01:00
* 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "DELTA" port
2002-02-16 04:27:33 +01:00
* 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "IMP" port
*
* 2002-02-23 Sean Leyne - Code Cleanup, removed old M88K and NCR3000 port
*
* 2002.10.27 Sean Leyne - Completed removal of obsolete "DG_X86" port
* 2002.10.27 Sean Leyne - Completed removal of obsolete "M88K" port
*
2002-10-29 03:45:09 +01:00
* 2002.10.28 Sean Leyne - Completed removal of obsolete "DGUX" port
* 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "DecOSF" port
* 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "SGI" port
2002-10-29 03:45:09 +01:00
*
2002-10-30 07:40:58 +01:00
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
*
2001-05-23 15:26:42 +02:00
*/
#include "firebird.h"
2004-04-29 00:43:34 +02:00
#include <stdio.h>
2001-05-23 15:26:42 +02:00
#include <stdlib.h>
#include <string.h>
2003-03-04 04:42:23 +01:00
#ifdef SOLARIS
#ifndef DEV_BUILD
2003-11-04 00:59:24 +01:00
#define NDEBUG // Turn off fb_assert() macros
2003-03-04 04:42:23 +01:00
#endif
2003-11-04 00:59:24 +01:00
#include "../jrd/gdsassert.h"
2003-03-04 04:42:23 +01:00
#endif
2007-11-12 16:18:49 +01:00
#ifdef HPUX
2001-05-23 15:26:42 +02:00
#include <sys/pstat.h>
#endif
//#include "../common/classes/timestamp.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/common.h"
#include "gen/iberror.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/isc.h"
#include "../jrd/gds_proto.h"
#include "../jrd/isc_proto.h"
#include "../jrd/os/isc_i_proto.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/isc_s_proto.h"
#include "../jrd/file_params.h"
#include "../jrd/gdsassert.h"
#include "../jrd/jrd.h"
#include "../jrd/err_proto.h"
#include "../jrd/thread_proto.h"
#include "../jrd/jrd_pwd.h"
2008-04-11 03:38:50 +02:00
#include "../common/classes/fb_tls.h"
#include "../common/config/config.h"
#include "../common/utils_proto.h"
2001-05-23 15:26:42 +02:00
2008-04-11 03:38:50 +02:00
#ifdef UNIX
#include <setjmp.h>
#endif
2001-05-23 15:26:42 +02:00
static int process_id;
2003-04-02 13:22:30 +02:00
#ifdef UNIX
2001-05-23 15:26:42 +02:00
static UCHAR *next_shared_memory;
#endif
/* Unix specific stuff */
#ifdef UNIX
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#ifdef HAVE_SIGNAL_H
2001-05-23 15:26:42 +02:00
#include <signal.h>
#endif
#ifdef HAVE_SYS_SIGNAL_H
#include <sys/signal.h>
2002-11-01 14:21:17 +01:00
#endif
2001-05-23 15:26:42 +02:00
#include <errno.h>
#ifdef HAVE_UNISTD_H
2001-05-23 15:26:42 +02:00
#include <unistd.h>
#endif
2001-05-23 15:26:42 +02:00
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#ifndef O_RDWR
#include <fcntl.h>
#endif
#ifdef HAVE_MMAP
2001-05-23 15:26:42 +02:00
#include <sys/mman.h>
#endif
#define FTOK_KEY 15
#define PRIV 0666
#ifndef SHMEM_DELTA
#define SHMEM_DELTA (1 << 22)
#endif
#ifndef SIGURG
#define SIGURG SIGINT
#endif
2002-11-21 11:20:07 +01:00
#ifndef HAVE_SEMUN
union semun
{
2001-05-23 15:26:42 +02:00
int val;
struct semid_ds *buf;
ushort *array;
};
#endif
2002-11-21 11:20:07 +01:00
#endif /* UNIX */
2001-05-23 15:26:42 +02:00
2002-07-06 07:32:02 +02:00
#ifdef HAVE_SYS_PARAM_H
2002-07-02 11:49:19 +02:00
#include <sys/param.h>
2002-07-06 07:32:02 +02:00
#endif
#ifndef HAVE_GETPAGESIZE
static size_t getpagesize(void)
{
return PAGESIZE;
}
#endif
2002-07-02 11:49:19 +02:00
2001-05-23 15:26:42 +02:00
/* Windows NT */
#ifdef WIN_NT
#include <process.h>
#include <signal.h>
#include <windows.h>
#endif
using namespace Jrd;
static void error(ISC_STATUS*, TEXT*, ISC_STATUS);
2008-01-16 10:07:24 +01:00
static bool event_blocked(USHORT count, const event_t* const* events, const SLONG* values);
#ifdef UNIX
static TLS_DECLARE(sigjmp_buf*, sigjmp_ptr);
2003-04-10 08:49:16 +02:00
static SLONG find_key(ISC_STATUS *, TEXT *);
2001-05-23 15:26:42 +02:00
static void longjmp_sig_handler(int);
#endif
2001-05-23 15:26:42 +02:00
#if defined(WIN_NT)
static void make_object_name(TEXT*, size_t, const TEXT*, const TEXT*);
2001-05-23 15:26:42 +02:00
#endif
2007-11-12 16:18:49 +01:00
#if defined FREEBSD || defined NETBSD || defined DARWIN || defined HPUX
2001-05-23 15:26:42 +02:00
#define sigset signal
#endif
#ifdef SOLARIS_MT
2008-01-16 10:07:24 +01:00
static bool event_blocked(USHORT count, const event_t* const* events, const SLONG* values)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ e v e n t _ b l o c k e d ( S O L A R I S _ M T )
*
**************************************
*
* Functional description
* If a wait would block, return TRUE.
*
**************************************/
for (; count > 0; --count, ++events, ++values)
if ((*events)->event_count >= *values) {
2003-02-10 01:03:54 +01:00
#ifdef DEBUG_ISC_SYNC
2008-01-16 10:07:24 +01:00
printf("event_blocked: FALSE (eg something to report)\n");
2004-04-29 00:43:34 +02:00
fflush(stdout);
2001-05-23 15:26:42 +02:00
#endif
2008-01-16 10:07:24 +01:00
return false;
2001-05-23 15:26:42 +02:00
}
2003-02-10 01:03:54 +01:00
#ifdef DEBUG_ISC_SYNC
2008-01-16 10:07:24 +01:00
printf("event_blocked: TRUE (eg nothing happened yet)\n");
2004-04-29 00:43:34 +02:00
fflush(stdout);
2001-05-23 15:26:42 +02:00
#endif
2008-01-16 10:07:24 +01:00
return true;
2001-05-23 15:26:42 +02:00
}
2004-02-02 12:02:12 +01:00
SLONG ISC_event_clear(event_t* event)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ e v e n t _ c l e a r ( S O L A R I S _ M T )
*
**************************************
*
* Functional description
* Clear an event preparatory to waiting on it. The order of
* battle for event synchronization is:
*
* 1. Clear event.
* 2. Test data structure for event already completed
* 3. Wait on event.
*
**************************************/
mutex_lock(event->event_mutex);
const SLONG ret = event->event_count + 1;
2001-05-23 15:26:42 +02:00
mutex_unlock(event->event_mutex);
return ret;
}
2004-02-02 12:02:12 +01:00
void ISC_event_fini(event_t* event)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ e v e n t _ f i n i ( S O L A R I S _ M T )
*
**************************************
*
* Functional description
* Discard an event object.
*
**************************************/
/* Inter-Process event's are destroyed only */
if (event->event_semid == -1) {
mutex_destroy(event->event_mutex);
cond_destroy(event->event_semnum);
}
}
2004-02-02 12:02:12 +01:00
int ISC_event_init(event_t* event, int semid, int semnum)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ e v e n t _ i n i t ( S O L A R I S _ M T )
*
**************************************
*
* Functional description
* Prepare an event object for use.
*
**************************************/
//SLONG key, n;
//union semun arg;
2001-05-23 15:26:42 +02:00
event->event_count = 0;
if (!semnum) {
/* Prepare an Inter-Thread event block */
event->event_semid = -1;
mutex_init(event->event_mutex, USYNC_THREAD, NULL);
cond_init(event->event_semnum, USYNC_THREAD, NULL);
}
else {
/* Prepare an Inter-Process event block */
event->event_semid = semid;
mutex_init(event->event_mutex, USYNC_PROCESS, NULL);
cond_init(event->event_semnum, USYNC_PROCESS, NULL);
}
return TRUE;
}
2004-02-02 12:02:12 +01:00
int ISC_event_post(event_t* event)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ e v e n t _ p o s t ( S O L A R I S _ M T )
*
**************************************
*
* Functional description
* Post an event to wake somebody else up.
*
**************************************/
/* For Solaris, we use cond_broadcast rather than cond_signal so that
all waiters on the event are notified and awakened */
mutex_lock(event->event_mutex);
++event->event_count;
const int ret = cond_broadcast(event->event_semnum);
2001-05-23 15:26:42 +02:00
mutex_unlock(event->event_mutex);
if (ret)
gds__log("ISC_event_post: cond_broadcast failed with errno = %d",
ret);
return ret;
}
int ISC_event_wait(SSHORT count,
2008-01-16 10:07:24 +01:00
event_t* const* events,
const SLONG* values,
const SLONG micro_seconds)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ e v e n t _ w a i t ( S O L A R I S _ M T )
*
**************************************
*
* Functional description
* Wait on an event. If timeout limit specified, return
* anyway after the timeout even if no event has
* happened. If returning due to timeout, return
* FB_FAILURE else return FB_SUCCESS.
2001-05-23 15:26:42 +02:00
*
**************************************/
/* While the API for ISC_event_wait allows for a list of events
we never actually make use of it. This implementation wont
support it anyway as Solaris doesn't provide a "wait for one
of a series of conditions" function */
2003-11-04 00:59:24 +01:00
fb_assert(count == 1);
2001-05-23 15:26:42 +02:00
/* If we're not blocked, the rest is a gross waste of time */
2008-01-16 10:07:24 +01:00
if (!event_blocked(count, events, values))
return FB_SUCCESS;
2001-05-23 15:26:42 +02:00
/* Set up timers if a timeout period was specified. */
timestruc_t timer;
2001-05-23 15:26:42 +02:00
if (micro_seconds > 0) {
timer.tv_sec = time(NULL);
timer.tv_sec += micro_seconds / 1000000;
timer.tv_nsec = 1000 * (micro_seconds % 1000000);
}
int ret = FB_SUCCESS;
2001-05-23 15:26:42 +02:00
mutex_lock((*events)->event_mutex);
for (;;) {
2008-01-16 10:07:24 +01:00
if (!event_blocked(count, events, values)) {
ret = FB_SUCCESS;
2001-05-23 15:26:42 +02:00
break;
}
/* The Solaris cond_wait & cond_timedwait calls atomically release
the mutex and start a wait. The mutex is reacquired before the
call returns. */
if (micro_seconds > 0)
ret =
cond_timedwait((*events)->event_semnum,
(*events)->event_mutex, &timer);
else
ret = cond_wait((*events)->event_semnum, (*events)->event_mutex);
if (micro_seconds > 0 && (ret == ETIME)) {
/* The timer expired - see if the event occured and return
FB_SUCCESS or FB_FAILURE accordingly. */
2001-05-23 15:26:42 +02:00
2008-01-16 10:07:24 +01:00
if (event_blocked(count, events, values))
ret = FB_FAILURE;
2001-05-23 15:26:42 +02:00
else
ret = FB_SUCCESS;
2001-05-23 15:26:42 +02:00
break;
}
}
mutex_unlock((*events)->event_mutex);
return ret;
}
#endif /* SOLARIS_MT */
#ifdef USE_POSIX_THREADS
2008-01-16 10:07:24 +01:00
static bool event_blocked(USHORT count, const event_t* const* events, const SLONG* values)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ e v e n t _ b l o c k e d ( P O S I X _ T H R E A D S )
*
**************************************
*
* Functional description
* If a wait would block, return TRUE.
*
**************************************/
for (; count > 0; --count, ++events, ++values)
if ((*events)->event_count >= *values) {
2003-02-10 01:03:54 +01:00
#ifdef DEBUG_ISC_SYNC
2008-01-16 10:07:24 +01:00
printf("event_blocked: FALSE (eg something to report)\n");
2004-04-29 00:43:34 +02:00
fflush(stdout);
2001-05-23 15:26:42 +02:00
#endif
2008-01-16 10:07:24 +01:00
return false;
2001-05-23 15:26:42 +02:00
}
2003-02-10 01:03:54 +01:00
#ifdef DEBUG_ISC_SYNC
2008-01-16 10:07:24 +01:00
printf("event_blocked: TRUE (eg nothing happened yet)\n");
2004-04-29 00:43:34 +02:00
fflush(stdout);
2001-05-23 15:26:42 +02:00
#endif
2008-01-16 10:07:24 +01:00
return true;
2001-05-23 15:26:42 +02:00
}
2004-02-02 12:02:12 +01:00
SLONG ISC_event_clear(event_t* event)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ e v e n t _ c l e a r ( P O S I X _ T H R E A D S )
*
**************************************
*
* Functional description
* Clear an event preparatory to waiting on it. The order of
* battle for event synchronization is:
*
* 1. Clear event.
* 2. Test data structure for event already completed
* 3. Wait on event.
*
**************************************/
pthread_mutex_lock(event->event_mutex);
const SLONG ret = event->event_count + 1;
2001-05-23 15:26:42 +02:00
pthread_mutex_unlock(event->event_mutex);
return ret;
}
2004-02-02 12:02:12 +01:00
void ISC_event_fini(event_t* event)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ e v e n t _ f i n i ( P O S I X _ T H R E A D S )
*
**************************************
*
* Functional description
* Discard an event object.
*
**************************************/
/* Inter-Thread event's are destroyed only */
if (event->event_semid == -1) {
pthread_mutex_destroy(event->event_mutex);
pthread_cond_destroy(event->event_semnum);
}
}
2004-02-02 12:02:12 +01:00
int ISC_event_init(event_t* event, int semid, int semnum)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ e v e n t _ i n i t ( P O S I X _ T H R E A D S )
*
**************************************
*
* Functional description
* Prepare an event object for use.
*
**************************************/
event->event_count = 0;
if (!semnum) {
/* Prepare an Inter-Thread event block */
event->event_semid = -1;
2002-02-16 04:05:21 +01:00
/* Default attribute objects initialize sync. primitives
2001-05-23 15:26:42 +02:00
to be used to sync thread within one process only.
*/
#ifdef HP10
pthread_mutex_init(event->event_mutex, pthread_mutexattr_default);
pthread_cond_init(event->event_semnum, pthread_condattr_default);
#else
pthread_mutex_init(event->event_mutex, NULL);
pthread_cond_init(event->event_semnum, NULL);
#endif /* HP10 */
}
else {
/* Prepare an Inter-Process event block */
2008-01-16 10:07:24 +01:00
pthread_mutexattr_t mattr;
pthread_condattr_t cattr;
2001-05-23 15:26:42 +02:00
event->event_semid = semid;
pthread_mutexattr_init(&mattr);
pthread_condattr_init(&cattr);
2008-01-17 17:17:31 +01:00
#ifdef PTHREAD_PROCESS_SHARED
2008-01-16 10:07:24 +01:00
pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
2001-05-23 15:26:42 +02:00
pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
2008-01-16 10:07:24 +01:00
#else
2008-01-17 17:17:31 +01:00
#error Your system must support PTHREAD_PROCESS_SHARED to use firebird.
#endif
2008-01-16 10:07:24 +01:00
pthread_mutex_init(event->event_mutex, &mattr);
2001-05-23 15:26:42 +02:00
pthread_cond_init(event->event_semnum, &cattr);
2008-01-16 10:07:24 +01:00
pthread_mutexattr_destroy(&mattr);
2001-05-23 15:26:42 +02:00
pthread_condattr_destroy(&cattr);
}
return TRUE;
}
2004-02-02 12:02:12 +01:00
int ISC_event_post(event_t* event)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ e v e n t _ p o s t ( P O S I X _ T H R E A D S )
*
**************************************
*
* Functional description
* Post an event to wake somebody else up.
*
**************************************/
pthread_mutex_lock(event->event_mutex);
++event->event_count;
const int ret = pthread_cond_broadcast(event->event_semnum);
2001-05-23 15:26:42 +02:00
pthread_mutex_unlock(event->event_mutex);
if (ret)
#ifdef HP10
{
2003-11-04 00:59:24 +01:00
fb_assert(ret == -1);
2001-05-23 15:26:42 +02:00
gds__log
("ISC_event_post: pthread_cond_broadcast failed with errno = %d",
errno);
return errno;
}
return 0;
#else
gds__log
("ISC_event_post: pthread_cond_broadcast failed with errno = %d",
ret);
return ret;
#endif /* HP10 */
}
2008-01-16 10:07:24 +01:00
int ISC_event_wait(SSHORT count,
event_t* const* events,
const SLONG* values,
const SLONG micro_seconds)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ e v e n t _ w a i t ( P O S I X _ T H R E A D S )
*
**************************************
*
* Functional description
* Wait on an event. If timeout limit specified, return
* anyway after the timeout even if no event has
* happened. If returning due to timeout, return
* FB_FAILURE else return FB_SUCCESS.
2001-05-23 15:26:42 +02:00
*
**************************************/
/* While the API for ISC_event_wait allows for a list of events
we never actually make use of it. This implementation wont
support it anyway as Solaris doesn't provide a "wait for one
of a series of conditions" function */
2003-11-04 00:59:24 +01:00
fb_assert(count == 1);
2001-05-23 15:26:42 +02:00
/* If we're not blocked, the rest is a gross waste of time */
2008-01-16 10:07:24 +01:00
if (!event_blocked(count, events, values))
return FB_SUCCESS;
2001-05-23 15:26:42 +02:00
/* Set up timers if a timeout period was specified. */
struct timespec timer;
2001-05-23 15:26:42 +02:00
if (micro_seconds > 0) {
timer.tv_sec = time(NULL);
timer.tv_sec += micro_seconds / 1000000;
timer.tv_nsec = 1000 * (micro_seconds % 1000000);
}
int ret = FB_SUCCESS;
2001-05-23 15:26:42 +02:00
pthread_mutex_lock((*events)->event_mutex);
for (;;) {
2008-01-16 10:07:24 +01:00
if (!event_blocked(count, events, values)) {
ret = FB_SUCCESS;
2001-05-23 15:26:42 +02:00
break;
}
/* The Posix pthread_cond_wait & pthread_cond_timedwait calls
atomically release the mutex and start a wait.
The mutex is reacquired before the call returns.
*/
if (micro_seconds > 0)
{
2001-05-23 15:26:42 +02:00
ret =
pthread_cond_timedwait((*events)->event_semnum,
(*events)->event_mutex, &timer);
#ifdef HP10
if ((ret == -1) && (errno == EAGAIN))
2001-05-23 15:26:42 +02:00
#else
#if (defined LINUX || defined DARWIN || defined HP11 || defined FREEBSD)
if (ret == ETIMEDOUT)
2001-05-23 15:26:42 +02:00
#else
if (ret == ETIME)
2001-05-23 15:26:42 +02:00
#endif
#endif
{
2001-05-23 15:26:42 +02:00
/* The timer expired - see if the event occured and return
FB_SUCCESS or FB_FAILURE accordingly. */
2001-05-23 15:26:42 +02:00
2008-01-16 10:07:24 +01:00
if (event_blocked(count, events, values))
ret = FB_FAILURE;
else
ret = FB_SUCCESS;
break;
}
2001-05-23 15:26:42 +02:00
}
else
ret =
pthread_cond_wait((*events)->event_semnum,
(*events)->event_mutex);
2001-05-23 15:26:42 +02:00
}
pthread_mutex_unlock((*events)->event_mutex);
return ret;
}
#endif /* USE_POSIX_THREADS */
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
2008-01-16 10:07:24 +01:00
static bool event_blocked(USHORT count, const event_t* const* events, const SLONG* values)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ e v e n t _ b l o c k e d ( W I N _ N T )
*
**************************************
*
* Functional description
* If a wait would block, return TRUE.
*
**************************************/
for (; count > 0; --count, ++events, ++values)
{
2004-02-02 12:02:12 +01:00
const event_t* pEvent = *events;
if (pEvent->event_count >= *values) {
2008-01-16 10:07:24 +01:00
return false;
2001-05-23 15:26:42 +02:00
}
}
2008-01-16 10:07:24 +01:00
return true;
2001-05-23 15:26:42 +02:00
}
2004-02-02 12:02:12 +01:00
SLONG ISC_event_clear(event_t* event)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ e v e n t _ c l e a r ( W I N _ N T )
*
**************************************
*
* Functional description
* Clear an event preparatory to waiting on it. The order of
* battle for event synchronization is:
*
* 1. Clear event.
* 2. Test data structure for event already completed
* 3. Wait on event.
*
**************************************/
ResetEvent((HANDLE) event->event_handle);
2008-01-16 10:07:24 +01:00
return event->event_count + 1;
2001-05-23 15:26:42 +02:00
}
2008-01-16 10:07:24 +01:00
void ISC_event_fini(event_t* event)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
2008-01-16 10:07:24 +01:00
* I S C _ e v e n t _ f i n i ( W I N _ N T )
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
2008-01-16 10:07:24 +01:00
* Discard an event object.
2001-05-23 15:26:42 +02:00
*
**************************************/
if (event->event_pid == process_id)
{
CloseHandle((HANDLE) event->event_handle);
}
2001-05-23 15:26:42 +02:00
}
2008-01-16 10:07:24 +01:00
int ISC_event_init(event_t* event, int unused, int type)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
2008-01-16 10:07:24 +01:00
* I S C _ e v e n t _ i n i t ( W I N _ N T )
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
2008-01-16 10:07:24 +01:00
* Prepare an event object for use.
2001-05-23 15:26:42 +02:00
*
**************************************/
static int idCounter = 0;
const int id = type ? ++idCounter : 0;
2008-01-16 10:07:24 +01:00
event->event_pid = process_id = getpid();
event->event_count = 0;
event->event_id = id;
2008-01-16 10:07:24 +01:00
event->event_handle = ISC_make_signal(true, true, process_id, id);
2008-01-16 10:07:24 +01:00
return (event->event_handle) ? TRUE : FALSE;
2001-05-23 15:26:42 +02:00
}
2004-02-02 12:02:12 +01:00
int ISC_event_post(event_t* event)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
2008-01-16 10:07:24 +01:00
* I S C _ e v e n t _ p o s t ( W I N _ N T )
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Post an event to wake somebody else up.
*
**************************************/
2008-01-16 10:07:24 +01:00
++event->event_count;
if (event->event_pid != process_id)
return ISC_kill(event->event_pid, event->event_id, event->event_handle);
2008-02-13 13:57:04 +01:00
return SetEvent((HANDLE) event->event_handle) ? 0 : -1;
2001-05-23 15:26:42 +02:00
}
int ISC_event_wait(SSHORT count,
2008-01-16 10:07:24 +01:00
event_t* const* events,
const SLONG* values,
const SLONG micro_seconds)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
2008-01-16 10:07:24 +01:00
* I S C _ e v e n t _ w a i t ( W I N _ N T )
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Wait on an event.
*
**************************************/
2008-01-16 10:07:24 +01:00
/* If we're not blocked, the rest is a gross waste of time */
2001-05-23 15:26:42 +02:00
2008-01-16 10:07:24 +01:00
if (!event_blocked(count, events, values)) {
return 0;
}
#pragma FB_COMPILER_MESSAGE("Warning: B.O. with more than 16 handles")
HANDLE handles[16];
HANDLE* handle_ptr = handles;
const event_t* const* ptr = events;
for (const event_t* const* const end = events + count; ptr < end;) {
*handle_ptr++ = (*ptr++)->event_handle;
}
/* Go into wait loop */
const DWORD timeout = (micro_seconds > 0) ? micro_seconds / 1000 : INFINITE;
for (;;) {
if (!event_blocked(count, events, values)) {
return 0;
}
const DWORD status =
WaitForMultipleObjects((DWORD) count, handles, TRUE, timeout);
if (!((status >= WAIT_OBJECT_0) && (status < WAIT_OBJECT_0 + (DWORD) count)))
{
return status;
}
}
2001-05-23 15:26:42 +02:00
}
2008-01-16 10:07:24 +01:00
#endif // WIN_NT
2001-05-23 15:26:42 +02:00
#ifdef UNIX
void ISC_exception_post(ULONG sig_num, const TEXT* err_msg)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
2002-02-16 04:05:21 +01:00
* I S C _ e x c e p t i o n _ p o s t ( U N I X )
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
2002-02-16 04:05:21 +01:00
* When we got a sync exception, fomulate the error code
2001-05-23 15:26:42 +02:00
* write it to the log file, and abort.
*
* 08-Mar-2004, Nickolay Samofatov.
* This function is dangerous and requires rewrite using signal-safe operations only.
* Main problem is that we call a lot of signal-unsafe functions from this signal handler,
* examples are gds__alloc, gds__log, etc... sprintf is safe on some BSD platforms,
* but not on Linux. This may result in lock-up during signal handling.
*
2001-05-23 15:26:42 +02:00
**************************************/
// If there's no err_msg, we asumed the switch() finds no case or we crash.
// Too much goodwill put on the caller. Weak programming style.
// Therefore, lifted this safety net from the NT version.
if (!err_msg)
{
err_msg = "";
}
TEXT* log_msg = (TEXT *) gds__alloc(strlen(err_msg) + 256);
// NOMEM: crash!
log_msg[0] = '\0';
2001-05-23 15:26:42 +02:00
switch (sig_num) {
case SIGSEGV:
sprintf(log_msg, "%s Segmentation Fault.\n"
"\t\tThe code attempted to access memory\n"
"\t\twithout privilege to do so.\n"
2002-07-02 11:49:19 +02:00
"\tThis exception will cause the Firebird server\n"
2001-05-23 15:26:42 +02:00
"\tto terminate abnormally.", err_msg);
break;
case SIGBUS:
sprintf(log_msg, "%s Bus Error.\n"
"\t\tThe code caused a system bus error.\n"
2002-07-02 11:49:19 +02:00
"\tThis exception will cause the Firebird server\n"
2001-05-23 15:26:42 +02:00
"\tto terminate abnormally.", err_msg);
break;
case SIGILL:
sprintf(log_msg, "%s Illegal Instruction.\n"
"\t\tThe code attempted to perfrom an\n"
"\t\tillegal operation."
2002-07-02 11:49:19 +02:00
"\tThis exception will cause the Firebird server\n"
2001-05-23 15:26:42 +02:00
"\tto terminate abnormally.", err_msg);
break;
case SIGFPE:
sprintf(log_msg, "%s Floating Point Error.\n"
"\t\tThe code caused an arithmetic exception\n"
"\t\tor floating point exception."
2002-07-02 11:49:19 +02:00
"\tThis exception will cause the Firebird server\n"
2001-05-23 15:26:42 +02:00
"\tto terminate abnormally.", err_msg);
break;
default:
sprintf(log_msg, "%s Unknown Exception.\n"
2006-01-18 11:43:13 +01:00
"\t\tException number %"ULONGFORMAT"."
2002-07-02 11:49:19 +02:00
"\tThis exception will cause the Firebird server\n"
2001-05-23 15:26:42 +02:00
"\tto terminate abnormally.", err_msg, sig_num);
break;
}
if (err_msg) {
gds__log(log_msg);
gds__free(log_msg);
}
abort();
}
#endif // UNIX
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
ULONG ISC_exception_post(ULONG except_code, const TEXT* err_msg)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
2002-02-16 04:05:21 +01:00
* I S C _ e x c e p t i o n _ p o s t ( W I N _ N T )
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
2002-02-16 04:05:21 +01:00
* When we got a sync exception, fomulate the error code
2001-05-23 15:26:42 +02:00
* write it to the log file, and abort. Note: We can not
* actually call "abort" since in windows this will cause
* a dialog to appear stating the obvious! Since on NT we
* would not get a core file, there is actually no difference
2002-02-16 04:05:21 +01:00
* between abort() and exit(3).
2001-05-23 15:26:42 +02:00
*
**************************************/
ULONG result = 0;
bool is_critical = true;
if (!err_msg)
{
err_msg = "";
}
TEXT* log_msg = (TEXT*) gds__alloc(strlen(err_msg) + 256);
// NOMEM: crash!
log_msg[0] = '\0';
2001-05-23 15:26:42 +02:00
switch (except_code) {
case EXCEPTION_ACCESS_VIOLATION:
sprintf(log_msg, "%s Access violation.\n"
"\t\tThe code attempted to access a virtual\n"
"\t\taddress without privilege to do so.\n"
2002-07-02 11:49:19 +02:00
"\tThis exception will cause the Firebird server\n"
2001-05-23 15:26:42 +02:00
"\tto terminate abnormally.", err_msg);
break;
case EXCEPTION_DATATYPE_MISALIGNMENT:
sprintf(log_msg, "%s Datatype misalignment.\n"
"\t\tThe attempted to read or write a value\n"
"\t\tthat was not stored on a memory boundary.\n"
2002-07-02 11:49:19 +02:00
"\tThis exception will cause the Firebird server\n"
2001-05-23 15:26:42 +02:00
"\tto terminate abnormally.", err_msg);
break;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
sprintf(log_msg, "%s Array bounds exceeded.\n"
"\t\tThe code attempted to access an array\n"
"\t\telement that is out of bounds.\n"
2002-07-02 11:49:19 +02:00
"\tThis exception will cause the Firebird server\n"
2001-05-23 15:26:42 +02:00
"\tto terminate abnormally.", err_msg);
break;
case EXCEPTION_FLT_DENORMAL_OPERAND:
sprintf(log_msg, "%s Float denormal operand.\n"
"\t\tOne of the floating-point operands is too\n"
"\t\tsmall to represent as a standard floating-point\n"
"\t\tvalue.\n"
2002-07-02 11:49:19 +02:00
"\tThis exception will cause the Firebird server\n"
2001-05-23 15:26:42 +02:00
"\tto terminate abnormally.", err_msg);
break;
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
sprintf(log_msg, "%s Floating-point divide by zero.\n"
"\t\tThe code attempted to divide a floating-point\n"
"\t\tvalue by a floating-point divisor of zero.\n"
2002-07-02 11:49:19 +02:00
"\tThis exception will cause the Firebird server\n"
2001-05-23 15:26:42 +02:00
"\tto terminate abnormally.", err_msg);
break;
case EXCEPTION_FLT_INEXACT_RESULT:
sprintf(log_msg, "%s Floating-point inexact result.\n"
"\t\tThe result of a floating-point operation cannot\n"
"\t\tbe represented exactly as a decimal fraction.\n"
2002-07-02 11:49:19 +02:00
"\tThis exception will cause the Firebird server\n"
2001-05-23 15:26:42 +02:00
"\tto terminate abnormally.", err_msg);
break;
case EXCEPTION_FLT_INVALID_OPERATION:
sprintf(log_msg, "%s Floating-point invalid operand.\n"
"\t\tAn indeterminant error occurred during a\n"
"\t\tfloating-point operation.\n"
2002-07-02 11:49:19 +02:00
"\tThis exception will cause the Firebird server\n"
2001-05-23 15:26:42 +02:00
"\tto terminate abnormally.", err_msg);
break;
case EXCEPTION_FLT_OVERFLOW:
sprintf(log_msg, "%s Floating-point overflow.\n"
"\t\tThe exponent of a floating-point operation\n"
"\t\tis greater than the magnitude allowed.\n"
2002-07-02 11:49:19 +02:00
"\tThis exception will cause the Firebird server\n"
2001-05-23 15:26:42 +02:00
"\tto terminate abnormally.", err_msg);
break;
case EXCEPTION_FLT_STACK_CHECK:
sprintf(log_msg, "%s Floating-point stack check.\n"
"\t\tThe stack overflowed or underflowed as the\n"
"result of a floating-point operation.\n"
2002-07-02 11:49:19 +02:00
"\tThis exception will cause the Firebird server\n"
2001-05-23 15:26:42 +02:00
"\tto terminate abnormally.", err_msg);
break;
case EXCEPTION_FLT_UNDERFLOW:
sprintf(log_msg, "%s Floating-point underflow.\n"
"\t\tThe exponent of a floating-point operation\n"
"\t\tis less than the magnitude allowed.\n"
2002-07-02 11:49:19 +02:00
"\tThis exception will cause the Firebird server\n"
2001-05-23 15:26:42 +02:00
"\tto terminate abnormally.", err_msg);
break;
case EXCEPTION_INT_DIVIDE_BY_ZERO:
sprintf(log_msg, "%s Integer divide by zero.\n"
"\t\tThe code attempted to divide an integer value\n"
"\t\tby an integer divisor of zero.\n"
2002-07-02 11:49:19 +02:00
"\tThis exception will cause the Firebird server\n"
2001-05-23 15:26:42 +02:00
"\tto terminate abnormally.", err_msg);
break;
case EXCEPTION_INT_OVERFLOW:
sprintf(log_msg, "%s Interger overflow.\n"
"\t\tThe result of an integer operation caused the\n"
"\t\tmost significant bit of the result to carry.\n"
2002-07-02 11:49:19 +02:00
"\tThis exception will cause the Firebird server\n"
2001-05-23 15:26:42 +02:00
"\tto terminate abnormally.", err_msg);
break;
case EXCEPTION_STACK_OVERFLOW:
Firebird::status_exception::raise(isc_exception_stack_overflow, 0);
2001-05-23 15:26:42 +02:00
/* This will never be called, but to be safe it's here */
result = (ULONG) EXCEPTION_CONTINUE_EXECUTION;
is_critical = false;
break;
2001-05-23 15:26:42 +02:00
case EXCEPTION_BREAKPOINT:
case EXCEPTION_SINGLE_STEP:
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
case EXCEPTION_INVALID_DISPOSITION:
case EXCEPTION_PRIV_INSTRUCTION:
case EXCEPTION_IN_PAGE_ERROR:
case EXCEPTION_ILLEGAL_INSTRUCTION:
case EXCEPTION_GUARD_PAGE:
/* Pass these exception on to someone else,
probably the OS or the debugger, since there
isn't a dam thing we can do with them */
result = EXCEPTION_CONTINUE_SEARCH;
is_critical = false;
2001-05-23 15:26:42 +02:00
break;
case 0xE06D7363: /* E == Exception. 0x6D7363 == "msc". Intel and Borland use the same code to be compatible */
/* If we've catched our own software exception,
continue rewinding the stack to properly handle it
and deliver an error information to the client side */
result = EXCEPTION_CONTINUE_SEARCH;
is_critical = false;
break;
default:
sprintf (log_msg, "%s An exception occurred that does\n"
"\t\tnot have a description. Exception number %"XLONGFORMAT".\n"
"\tThis exception will cause the Firebird server\n"
"\tto terminate abnormally.", err_msg, except_code);
break;
2001-05-23 15:26:42 +02:00
}
2003-03-12 14:20:23 +01:00
if (is_critical)
{
gds__log(log_msg);
}
gds__free(log_msg);
if (is_critical)
{
2004-10-17 05:35:42 +02:00
if (Config::getBugcheckAbort()) {
// Pass exception to outer handler in case debugger is present to collect memory dump
return EXCEPTION_CONTINUE_SEARCH;
}
2008-01-16 10:07:24 +01:00
// Silently exit so guardian or service manager can restart the server.
// If exception is getting out of the application Windows displays a message
// asking if you want to send report to Microsoft or attach debugger,
// application is not terminated until you press some button on resulting window.
// This happens even if you run application as non-interactive service on
// "server" OS like Windows Server 2003.
exit(3);
2001-05-23 15:26:42 +02:00
}
2008-01-16 10:07:24 +01:00
return result;
2001-05-23 15:26:42 +02:00
}
#endif // WIN_NT
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
void *ISC_make_signal(
bool create_flag,
bool manual_reset,
2004-05-12 21:39:17 +02:00
int process_idL,
int signal_number)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ m a k e _ s i g n a l ( W I N _ N T )
*
**************************************
*
* Functional description
* Create or open a Windows/NT event.
* Use the signal number and process id
* in naming the object.
*
**************************************/
const BOOLEAN man_rst = manual_reset ? TRUE : FALSE;
2001-05-23 15:26:42 +02:00
if (!signal_number)
return CreateEvent(NULL, man_rst, FALSE, NULL);
2001-05-23 15:26:42 +02:00
2008-01-16 10:07:24 +01:00
TEXT event_name[BUFFER_TINY];
sprintf(event_name, "_firebird_process%u_signal%d", process_idL, signal_number);
HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS, TRUE, event_name);
if (create_flag) {
fb_assert(!hEvent);
hEvent = CreateEvent(ISC_get_security_desc(), man_rst, FALSE, event_name);
}
return hEvent;
2001-05-23 15:26:42 +02:00
}
#endif
#ifdef UNIX
#ifdef HAVE_MMAP
UCHAR* ISC_map_file(ISC_STATUS* status_vector,
const TEXT* filename,
FPTR_INIT_GLOBAL_REGION init_routine,
void* init_arg, SLONG length, SH_MEM shmem_data)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ m a p _ f i l e ( U N I X - m m a p )
*
**************************************
*
* Functional description
* Try to map a given file. If we are the first (i.e. only)
* process to map the file, call a given initialization
* routine (if given) or punt (leaving the file unmapped).
*
**************************************/
TEXT expanded_filename[MAXPATHLEN], hostname[64];
sprintf(expanded_filename, filename,
ISC_get_host(hostname, sizeof(hostname)));
2002-02-16 04:05:21 +01:00
/* make the complete filename for the init file this file is to be used as a
2001-05-23 15:26:42 +02:00
master lock to eliminate possible race conditions with just a single file
2002-02-16 04:05:21 +01:00
locking. The race condition is caused as the conversion of a EXCLUSIVE
2001-05-23 15:26:42 +02:00
lock to a SHARED lock is not atomic*/
TEXT tmp[MAXPATHLEN];
2001-05-23 15:26:42 +02:00
gds__prefix_lock(tmp, INIT_FILE);
TEXT init_filename[MAXPATHLEN]; /* to hold the complete filename
of the init file. */
2001-05-23 15:26:42 +02:00
sprintf(init_filename, tmp, hostname); /* already have the hostname! */
const int oldmask = umask(0);
bool trunc_flag = true;
2001-05-23 15:26:42 +02:00
if (length < 0) {
length = -length;
trunc_flag = false;
2001-05-23 15:26:42 +02:00
}
/* Produce shared memory key for file */
SLONG key;
2001-05-23 15:26:42 +02:00
if (!(key = find_key(status_vector, expanded_filename))) {
umask(oldmask);
return NULL;
}
/* open the init lock file */
int fd_init; /* filedecr. for the init file */
2001-05-23 15:26:42 +02:00
fd_init = open(init_filename, O_RDWR | O_CREAT, 0666);
if (fd_init == -1) {
error(status_vector, "open", errno);
return NULL;
}
#ifndef HAVE_FLOCK
struct flock lock;
2001-05-23 15:26:42 +02:00
/* get an exclusive lock on the INIT file with a block */
lock.l_type = F_WRLCK;
lock.l_whence = 0;
lock.l_start = 0;
lock.l_len = 0;
if (fcntl(fd_init, F_SETLKW, &lock) == -1) {
error(status_vector, "fcntl", errno);
close(fd_init);
return NULL;
}
#else
/* get an flock exclusive on the INIT file with blocking */
if (flock(fd_init, LOCK_EX)) {
/* we failed to get an exclusive lock return back */
error(status_vector, "flock", errno);
close(fd_init);
return NULL;
}
#endif
/* open the file to be inited */
int fd = open(expanded_filename, O_RDWR | O_CREAT, 0666);
2001-05-23 15:26:42 +02:00
umask(oldmask);
if (fd == -1) {
error(status_vector, "open", errno);
#ifdef HAVE_FLOCK
2001-05-23 15:26:42 +02:00
/* unlock init file */
flock(fd_init, LOCK_UN);
#else
lock.l_type = F_UNLCK;
lock.l_whence = 0;
lock.l_start = 0;
lock.l_len = 0;
fcntl(fd_init, F_SETLK, &lock);
#endif
close(fd_init);
return NULL;
}
if (length == 0) {
/* Get and use the existing length of the shared segment */
struct stat file_stat;
2001-05-23 15:26:42 +02:00
if (fstat(fd, &file_stat) == -1) {
error(status_vector, "fstat", errno);
close(fd);
#ifdef HAVE_FLOCK
2001-05-23 15:26:42 +02:00
/* unlock init file */
flock(fd_init, LOCK_UN);
#else
lock.l_type = F_UNLCK;
lock.l_whence = 0;
lock.l_start = 0;
lock.l_len = 0;
fcntl(fd_init, F_SETLK, &lock);
#endif
close(fd_init); /* while we are at it close the init file also */
return NULL;
}
length = file_stat.st_size;
}
UCHAR* address =
2001-05-23 15:26:42 +02:00
(UCHAR *) mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if ((U_IPTR) address == (U_IPTR) -1) {
2001-05-23 15:26:42 +02:00
error(status_vector, "mmap", errno);
close(fd);
#ifdef HAVE_FLOCK
2001-05-23 15:26:42 +02:00
/* unlock init file */
flock(fd_init, LOCK_UN);
#else
lock.l_type = F_UNLCK;
lock.l_whence = 0;
lock.l_start = 0;
lock.l_len = 0;
fcntl(fd_init, F_SETLK, &lock);
#endif
close(fd_init);
return NULL;
}
/* Get semaphore for mutex */
shmem_data->sh_mem_address = address;
shmem_data->sh_mem_length_mapped = length;
shmem_data->sh_mem_handle = fd;
/* Try to get an exclusive lock on the lock file. This will
fail if somebody else has the exclusive lock */
#ifdef HAVE_FLOCK
2001-05-23 15:26:42 +02:00
if (!flock(fd, LOCK_EX | LOCK_NB))
{
if (!init_routine) {
/* unlock both files */
flock(fd, LOCK_UN);
flock(fd_init, LOCK_UN);
#else
lock.l_type = F_WRLCK;
lock.l_whence = 0;
lock.l_start = 0;
lock.l_len = 0;
if (fcntl(fd, F_SETLK, &lock) != -1) {
if (!init_routine) {
/* unlock the file and the init file to release the other process */
lock.l_type = F_UNLCK;
lock.l_whence = 0;
lock.l_start = 0;
lock.l_len = 0;
fcntl(fd, F_SETLK, &lock);
lock.l_type = F_UNLCK;
lock.l_whence = 0;
lock.l_start = 0;
lock.l_len = 0;
fcntl(fd_init, F_SETLK, &lock);
#endif
munmap((char *) address, length);
close(fd);
close(fd_init);
*status_vector++ = isc_arg_gds;
*status_vector++ = isc_unavailable;
*status_vector++ = isc_arg_end;
2001-05-23 15:26:42 +02:00
return NULL;
}
2001-05-23 15:26:42 +02:00
if (trunc_flag)
ftruncate(fd, length);
(*init_routine) (init_arg, shmem_data, true);
#ifdef HAVE_FLOCK
2001-05-23 15:26:42 +02:00
if (flock(fd, LOCK_SH)) {
error(status_vector, "flock", errno);
flock(fd, LOCK_UN);
flock(fd_init, LOCK_UN);
#else
lock.l_type = F_RDLCK;
lock.l_whence = 0;
lock.l_start = 0;
lock.l_len = 0;
if (fcntl(fd, F_SETLK, &lock) == -1)
{
error(status_vector, "fcntl", errno);
/* unlock the file */
lock.l_type = F_UNLCK;
lock.l_whence = 0;
lock.l_start = 0;
lock.l_len = 0;
fcntl(fd, F_SETLK, &lock);
/* unlock the init file to release the other process */
lock.l_type = F_UNLCK;
lock.l_whence = 0;
lock.l_start = 0;
lock.l_len = 0;
fcntl(fd_init, F_SETLK, &lock);
#endif
munmap((char *) address, length);
close(fd_init);
close(fd);
return NULL;
}
}
else {
#ifdef HAVE_FLOCK
2001-05-23 15:26:42 +02:00
if (flock(fd, LOCK_SH)) {
error(status_vector, "flock", errno);
flock(fd, LOCK_UN);
flock(fd_init, LOCK_UN);
#else
lock.l_type = F_RDLCK;
lock.l_whence = 0;
lock.l_start = 0;
lock.l_len = 0;
if (fcntl(fd, F_SETLK, &lock) == -1) {
error(status_vector, "fcntl", errno);
/* unlock the file */
lock.l_type = F_UNLCK;
lock.l_whence = 0;
lock.l_start = 0;
lock.l_len = 0;
fcntl(fd, F_SETLK, &lock);
/* unlock the init file to release the other process */
lock.l_type = F_UNLCK;
lock.l_whence = 0;
lock.l_start = 0;
lock.l_len = 0;
fcntl(fd_init, F_SETLK, &lock);
#endif
munmap((char *) address, length);
close(fd_init);
close(fd);
return NULL;
}
2001-05-23 15:26:42 +02:00
if (init_routine)
(*init_routine) (init_arg, shmem_data, false);
2001-05-23 15:26:42 +02:00
}
#ifdef HAVE_FLOCK
2001-05-23 15:26:42 +02:00
/* unlock the init file to release the other process */
flock(fd_init, LOCK_UN);
#else
/* unlock the init file to release the other process */
lock.l_type = F_UNLCK;
lock.l_whence = 0;
lock.l_start = 0;
lock.l_len = 0;
fcntl(fd_init, F_SETLK, &lock);
#endif
/* close the init file_decriptor */
close(fd_init);
return address;
}
#endif
#endif
#ifdef UNIX
#ifndef HAVE_MMAP
UCHAR* ISC_map_file(ISC_STATUS* status_vector,
const TEXT* filename,
FPTR_INIT_GLOBAL_REGION init_routine,
void* init_arg, SLONG length, SH_MEM shmem_data)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ m a p _ f i l e ( U N I X - s h m a t )
*
**************************************
*
* Functional description
* Try to map a given file. If we are the first (i.e. only)
* process to map the file, call a given initialization
* routine (if given) or punt (leaving the file unmapped).
*
**************************************/
//SSHORT count;
TEXT expanded_filename[512];
2001-05-23 15:26:42 +02:00
#ifdef NOHOSTNAME
strcpy(expanded_filename, filename);
#else
TEXT hostname[64];
2001-05-23 15:26:42 +02:00
sprintf(expanded_filename, filename,
ISC_get_host(hostname, sizeof(hostname)));
#endif
const int oldmask = umask(0);
bool init_flag = false;
2001-05-23 15:26:42 +02:00
if (length < 0)
length = -length;
/* Produce shared memory key for file */
const SLONG key = find_key(status_vector, expanded_filename);
if (!key) {
2001-05-23 15:26:42 +02:00
umask(oldmask);
return NULL;
}
/* Write shared memory key into expanded_filename file */
2004-04-29 00:43:34 +02:00
FILE* fp = fopen(expanded_filename, "w");
2001-05-23 15:26:42 +02:00
umask(oldmask);
if (!fp) {
2004-04-29 00:43:34 +02:00
error(status_vector, "fopen", errno);
2001-05-23 15:26:42 +02:00
return NULL;
}
2004-04-29 00:43:34 +02:00
fprintf(fp, "%ld", key);
2001-05-23 15:26:42 +02:00
/* Get an exclusive lock on the file until the initialization process
is complete. That way potential race conditions are avoided. */
2002-11-12 08:59:19 +01:00
#ifndef HAVE_FLOCK
2004-04-29 00:43:34 +02:00
if (lockf(fileno(fp), F_LOCK, 0)) {
2001-05-23 15:26:42 +02:00
error(status_vector, "lockf", errno);
#else
2004-04-29 00:43:34 +02:00
if (flock(fileno(fp), LOCK_EX)) {
2001-05-23 15:26:42 +02:00
error(status_vector, "flock", errno);
#endif
2004-04-29 00:43:34 +02:00
fclose(fp);
2001-05-23 15:26:42 +02:00
return NULL;
}
/* Create the shared memory region if it doesn't already exist. */
struct shmid_ds buf;
SLONG shmid;
2001-05-23 15:26:42 +02:00
if ((shmid = shmget(key, length, IPC_CREAT | PRIV)) == -1)
#ifdef SUPERSERVER
if (errno == EINVAL) {
/* There are two cases when shmget() returns EINVAL error:
- "length" is less than the system-imposed minimum or
greater than the system-imposed maximum.
- A shared memory identifier exists for "key" but the
size of the segment associated with it is less
than "length" and "length" is not equal to zero.
2002-02-16 04:05:21 +01:00
Let's find out what the problem is by getting the
2001-05-23 15:26:42 +02:00
system-imposed limits.
*/
#ifdef HP10
struct pst_ipcinfo pst;
if (pstat_getipc(&pst, sizeof(struct pst_ipcinfo), 1, 0) == -1) {
error(status_vector, "pstat_getipc", errno);
2004-04-29 00:43:34 +02:00
fclose(fp);
2001-05-23 15:26:42 +02:00
return NULL;
}
if ((length < pst.psi_shmmin) || (length > pst.psi_shmmax)) {
/* If pstat_getipc did not return an error "errno"
is still EINVAL, exactly what we want.
*/
error(status_vector, "shmget", errno);
2004-04-29 00:43:34 +02:00
fclose(fp);
2001-05-23 15:26:42 +02:00
return NULL;
}
#endif /* HP10 */
/* If we are here then the shared memory segment already
exists and the "length" we specified in shmget() is
2002-02-16 04:05:21 +01:00
bigger than the size of the existing segment.
2001-05-23 15:26:42 +02:00
Because the segment has to exist at this point the
following shmget() does not have IPC_CREAT flag set.
We need to get shmid to delete the segment. Because we
do not know the size of the existing segment the easiest
way to get shmid is to attach to the segment with zero
length
*/
if ((shmid = shmget(key, 0, PRIV)) == -1) {
error(status_vector, "shmget", errno);
2004-04-29 00:43:34 +02:00
fclose(fp);
2001-05-23 15:26:42 +02:00
return NULL;
}
if (shmctl(shmid, IPC_RMID, &buf) == -1) {
error(status_vector, "shmctl/IPC_RMID", errno);
2004-04-29 00:43:34 +02:00
fclose(fp);
2001-05-23 15:26:42 +02:00
return NULL;
}
/* We have just deleted shared memory segment and current
code fragment is an atomic operation (we are holding an
exclusive lock on the "isc_lock1.<machine>" file), so
we use IPC_EXCL flag to get an error if by some miracle
the sagment with the same key is already exists
*/
if ((shmid = shmget(key, length, IPC_CREAT | IPC_EXCL | PRIV)) ==
-1)
{
2001-05-23 15:26:42 +02:00
error(status_vector, "shmget", errno);
2004-04-29 00:43:34 +02:00
fclose(fp);
2001-05-23 15:26:42 +02:00
return NULL;
}
}
else /* if errno != EINVAL) */
#endif /* SUPERSERVER */
{
error(status_vector, "shmget", errno);
2004-04-29 00:43:34 +02:00
fclose(fp);
2001-05-23 15:26:42 +02:00
return NULL;
}
#ifdef SUPERSERVER
/* If we are here there are two possibilities:
1. we mapped the shared memory segment of the "length" size;
2. we mapped the segment of the size less than "length" (but
not zero length and bigger than system-imposed minimum);
We want shared memory segment exactly of the "length" size.
Let's find out what the size of the segment is and if it is
bigger than length, we remove it and create new one with the
size "length".
Also, if "length" is zero (that means we have already mapped
2002-02-16 04:05:21 +01:00
the existing segment with the zero size) remap the segment
with the existing size
2001-05-23 15:26:42 +02:00
*/
if (shmctl(shmid, IPC_STAT, &buf) == -1) {
error(status_vector, "shmctl/IPC_STAT", errno);
2004-04-29 00:43:34 +02:00
fclose(fp);
2001-05-23 15:26:42 +02:00
return NULL;
}
2003-11-04 00:59:24 +01:00
fb_assert(length <= buf.shm_segsz);
2001-05-23 15:26:42 +02:00
if (length < buf.shm_segsz)
if (length) {
if (shmctl(shmid, IPC_RMID, &buf) == -1) {
error(status_vector, "shmctl/IPC_RMID", errno);
2004-04-29 00:43:34 +02:00
fclose(fp);
2001-05-23 15:26:42 +02:00
return NULL;
}
if ((shmid = shmget(key, length, IPC_CREAT | IPC_EXCL | PRIV)) ==
-1)
{
2001-05-23 15:26:42 +02:00
error(status_vector, "shmget", errno);
2004-04-29 00:43:34 +02:00
fclose(fp);
2001-05-23 15:26:42 +02:00
return NULL;
}
}
else {
length = buf.shm_segsz;
if ((shmid = shmget(key, length, PRIV)) == -1) {
error(status_vector, "shmget", errno);
2004-04-29 00:43:34 +02:00
fclose(fp);
2001-05-23 15:26:42 +02:00
return NULL;
}
}
#else /* !SUPERSERVER */
if (length == 0) {
2002-02-16 04:05:21 +01:00
/* Use the existing length. This should not happen for the
2001-05-23 15:26:42 +02:00
very first attachment to the shared memory. */
if (shmctl(shmid, IPC_STAT, &buf) == -1) {
error(status_vector, "shmctl/IPC_STAT", errno);
2004-04-29 00:43:34 +02:00
fclose(fp);
2001-05-23 15:26:42 +02:00
return NULL;
}
length = buf.shm_segsz;
/* Now remap with the new-found length */
if ((shmid = shmget(key, length, PRIV)) == -1) {
error(status_vector, "shmget", errno);
2004-04-29 00:43:34 +02:00
fclose(fp);
2001-05-23 15:26:42 +02:00
return NULL;
}
}
#endif /* SUPERSERVER */
UCHAR* address = 0;
2001-05-23 15:26:42 +02:00
#ifdef SHMEM_PICKY
if (!next_shared_memory)
next_shared_memory = (UCHAR *) sbrk(0) + SHMEM_DELTA;
address = (UCHAR *) shmat(shmid, next_shared_memory, SHM_RND);
if ((U_IPTR) address != -1)
#ifndef SYSV_SHMEM
next_shared_memory = address + length;
#else
next_shared_memory = address + length + SHMLBA;
#endif
#else
address = (UCHAR *) shmat(shmid, NULL, 0);
#endif
if ((U_IPTR) address == -1) {
error(status_vector, "shmat", errno);
2004-04-29 00:43:34 +02:00
fclose(fp);
2001-05-23 15:26:42 +02:00
return NULL;
}
if (shmctl(shmid, IPC_STAT, &buf) == -1) {
error(status_vector, "shmctl/IPC_STAT", errno);
shmdt(address);
next_shared_memory -= length;
2004-04-29 00:43:34 +02:00
fclose(fp);
2001-05-23 15:26:42 +02:00
return NULL;
}
/* Get semaphore for mutex */
/* If we're the only one with shared memory mapped, see if
we can initialize it. If we can't, return failure. */
if (buf.shm_nattch == 1) {
if (!init_routine) {
shmdt(address);
next_shared_memory -= length;
2004-04-29 00:43:34 +02:00
fclose(fp);
*status_vector++ = isc_arg_gds;
*status_vector++ = isc_unavailable;
*status_vector++ = isc_arg_end;
2001-05-23 15:26:42 +02:00
return NULL;
}
buf.shm_perm.mode = 0666;
shmctl(shmid, IPC_SET, &buf);
init_flag = true;
2001-05-23 15:26:42 +02:00
}
shmem_data->sh_mem_address = address;
shmem_data->sh_mem_length_mapped = length;
shmem_data->sh_mem_handle = shmid;
2001-05-23 15:26:42 +02:00
if (init_routine)
(*init_routine) (init_arg, shmem_data, init_flag);
/* When the mapped file is closed here, the lock we applied for
synchronization will be released. */
2004-04-29 00:43:34 +02:00
fclose(fp);
2001-05-23 15:26:42 +02:00
return address;
}
#endif // !HAVE_MMAP
2001-05-23 15:26:42 +02:00
#endif // UNIX
#ifdef WIN_NT
UCHAR* ISC_map_file(
ISC_STATUS* status_vector,
const TEXT* filename,
FPTR_INIT_GLOBAL_REGION init_routine,
void* init_arg,
SLONG length,
SH_MEM shmem_data)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ m a p _ f i l e ( W I N _ N T )
*
**************************************
*
* Functional description
* Try to map a given file. If we are the first (i.e. only)
* process to map the file, call a given initialization
* routine (if given) or punt (leaving the file unmapped).
*
**************************************/
TEXT expanded_filename[MAXPATHLEN], hostname[64];
2001-05-23 15:26:42 +02:00
TEXT map_file[MAXPATHLEN];
HANDLE file_handle, event_handle;
2001-05-23 15:26:42 +02:00
int retry_count = 0;
/* retry to attach to mmapped file if the process initializing
* dies during initialization.
*/
retry:
retry_count++;
ISC_get_host(hostname, sizeof(hostname));
sprintf(map_file, filename, hostname);
if (length < 0)
length = -length;
file_handle = CreateFile(map_file,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
#ifdef EMBEDDED
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
#else
FILE_ATTRIBUTE_NORMAL,
#endif
NULL);
2001-05-23 15:26:42 +02:00
if (file_handle == INVALID_HANDLE_VALUE) {
error(status_vector, "CreateFile", GetLastError());
return NULL;
}
/* Check if file already exists */
const bool file_exists = (GetLastError() == ERROR_ALREADY_EXISTS);
2001-05-23 15:26:42 +02:00
/* Create an event that can be used to determine if someone has already
initialized shared memory. */
make_object_name(expanded_filename, sizeof(expanded_filename), filename, "_event");
2008-02-28 03:43:23 +01:00
event_handle = CreateEvent(ISC_get_security_desc(), TRUE, FALSE, expanded_filename);
2001-05-23 15:26:42 +02:00
if (!event_handle) {
error(status_vector, "CreateEvent", GetLastError());
2001-05-23 15:26:42 +02:00
CloseHandle(file_handle);
return NULL;
}
bool init_flag = (GetLastError() == ERROR_ALREADY_EXISTS) ? false: true;
2001-05-23 15:26:42 +02:00
if (init_flag && !init_routine) {
CloseHandle(event_handle);
CloseHandle(file_handle);
*status_vector++ = isc_arg_gds;
*status_vector++ = isc_unavailable;
*status_vector++ = isc_arg_end;
2001-05-23 15:26:42 +02:00
return NULL;
}
if (length == 0) {
/* Get and use the existing length of the shared segment */
if ((length = GetFileSize(file_handle, NULL)) == -1) {
error(status_vector, "GetFileSize", GetLastError());
CloseHandle(event_handle);
CloseHandle(file_handle);
return NULL;
}
}
/* All but the initializer will wait until the event is set. That
* is done after initialization is complete.
* Close the file and wait for the event to be set or time out.
* The file may be truncated.
*/
CloseHandle(file_handle);
if (!init_flag) {
/* Wait for 10 seconds. Then retry */
const DWORD ret_event = WaitForSingleObject(event_handle, 10000);
2001-05-23 15:26:42 +02:00
/* If we timed out, just retry. It is possible that the
* process doing the initialization died before setting the
* event.
*/
if (ret_event == WAIT_TIMEOUT) {
CloseHandle(event_handle);
if (retry_count > 10) {
error(status_vector, "WaitForSingleObject", GetLastError());
return NULL;
}
goto retry;
}
}
DWORD fdw_create;
2001-05-23 15:26:42 +02:00
if (init_flag && file_exists)
fdw_create = TRUNCATE_EXISTING | OPEN_ALWAYS;
else
fdw_create = OPEN_ALWAYS;
file_handle = CreateFile(map_file,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
fdw_create,
#ifdef EMBEDDED
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
#else
FILE_ATTRIBUTE_NORMAL,
#endif
NULL);
2001-05-23 15:26:42 +02:00
if (file_handle == INVALID_HANDLE_VALUE) {
CloseHandle(event_handle);
error(status_vector, "CreateFile", GetLastError());
return NULL;
}
/* Create a file mapping object that will be used to make remapping possible.
The current length of real mapped file and its name are saved in it. */
make_object_name(expanded_filename, sizeof(expanded_filename), filename, "_mapping");
2001-05-23 15:26:42 +02:00
HANDLE header_obj = CreateFileMapping ((HANDLE) -1,
ISC_get_security_desc(),
PAGE_READWRITE,
0,
2 * sizeof (SLONG),
expanded_filename);
2001-05-23 15:26:42 +02:00
if (header_obj == NULL) {
error(status_vector, "CreateFileMapping", GetLastError());
CloseHandle(event_handle);
CloseHandle(file_handle);
return NULL;
}
SLONG* header_address =
(SLONG*) MapViewOfFile(header_obj, FILE_MAP_WRITE, 0, 0, 0);
2001-05-23 15:26:42 +02:00
if (header_address == NULL) {
error(status_vector, "CreateFileMapping", GetLastError());
CloseHandle(header_obj);
CloseHandle(event_handle);
CloseHandle(file_handle);
return NULL;
}
/* Set or get the true length of the file depending on whether or not
we are the first user. */
if (init_flag) {
header_address[0] = length;
header_address[1] = 0;
}
else
length = header_address[0];
/* Create the real file mapping object. */
TEXT* p;
2001-05-23 15:26:42 +02:00
for (p = expanded_filename; *p; p++);
2003-04-01 23:59:31 +02:00
sprintf(p, "%"SLONGFORMAT, header_address[1]);
2001-05-23 15:26:42 +02:00
HANDLE file_obj =
CreateFileMapping(file_handle,
ISC_get_security_desc(),
PAGE_READWRITE,
0,
length,
expanded_filename);
2001-05-23 15:26:42 +02:00
if (file_obj == NULL) {
error(status_vector, "CreateFileMapping", GetLastError());
UnmapViewOfFile(header_address);
CloseHandle(header_obj);
CloseHandle(event_handle);
CloseHandle(file_handle);
return NULL;
}
UCHAR* address =
(UCHAR*) MapViewOfFile(file_obj, FILE_MAP_WRITE, 0, 0, 0);
2001-05-23 15:26:42 +02:00
if (address == NULL) {
error(status_vector, "CreateFileMapping", GetLastError());
CloseHandle(file_obj);
UnmapViewOfFile(header_address);
CloseHandle(header_obj);
CloseHandle(event_handle);
CloseHandle(file_handle);
return NULL;
}
*p = 0;
shmem_data->sh_mem_address = address;
shmem_data->sh_mem_length_mapped = length;
shmem_data->sh_mem_handle = file_handle;
shmem_data->sh_mem_object = file_obj;
shmem_data->sh_mem_interest = event_handle;
shmem_data->sh_mem_hdr_object = header_obj;
shmem_data->sh_mem_hdr_address = header_address;
strcpy(shmem_data->sh_mem_name, expanded_filename);
if (init_routine)
(*init_routine) (init_arg, shmem_data, init_flag);
2001-05-23 15:26:42 +02:00
if (init_flag) {
FlushViewOfFile(address, 0);
SetEvent(event_handle);
2001-05-23 15:26:42 +02:00
if (SetFilePointer
(shmem_data->sh_mem_handle, length, NULL,
FILE_BEGIN) == 0xFFFFFFFF
|| !SetEndOfFile(shmem_data->sh_mem_handle)
|| !FlushViewOfFile(shmem_data->sh_mem_address, 0))
{
2001-05-23 15:26:42 +02:00
error(status_vector, "SetFilePointer", GetLastError());
return NULL;
}
}
return address;
}
#endif
#ifdef HAVE_MMAP
2003-04-10 08:49:16 +02:00
UCHAR *ISC_map_object(ISC_STATUS * status_vector,
2001-05-23 15:26:42 +02:00
SH_MEM shmem_data,
SLONG object_offset, SLONG object_length)
{
/**************************************
*
2002-02-16 04:05:21 +01:00
* I S C _ m a p _ o b j e c t
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Try to map an object given a file mapping.
*
**************************************/
/* Get system page size as this is the unit of mapping. */
#ifdef SOLARIS
const SLONG page_size = sysconf(_SC_PAGESIZE);
if (page_size == -1) {
2001-05-23 15:26:42 +02:00
error(status_vector, "sysconf", errno);
return NULL;
}
#else
const SLONG page_size = (int) getpagesize();
if (page_size == -1) {
2001-05-23 15:26:42 +02:00
error(status_vector, "getpagesize", errno);
return NULL;
}
#endif
/* Compute the start and end page-aligned offsets which
contain the object being mapped. */
const SLONG start = (object_offset / page_size) * page_size;
const SLONG end = (((object_offset + object_length) / page_size) + 1) * page_size;
const SLONG length = end - start;
int fd = shmem_data->sh_mem_handle;
2001-05-23 15:26:42 +02:00
UCHAR* address =
2001-05-23 15:26:42 +02:00
(UCHAR *) mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
start);
if ((U_IPTR) address == (U_IPTR) -1) {
2001-05-23 15:26:42 +02:00
error(status_vector, "mmap", errno);
return NULL;
}
/* Return the virtual address of the mapped object. */
return (address + (object_offset - start));
}
void ISC_unmap_object(ISC_STATUS * status_vector,
2001-05-23 15:26:42 +02:00
SH_MEM shmem_data,
UCHAR ** object_pointer, SLONG object_length)
{
/**************************************
*
2002-02-16 04:05:21 +01:00
* I S C _ u n m a p _ o b j e c t
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Try to unmap an object given a file mapping.
* Zero the object pointer after a successful unmap.
*
**************************************/
/* Get system page size as this is the unit of mapping. */
#ifdef SOLARIS
const SLONG page_size = sysconf(_SC_PAGESIZE);
if (page_size == -1) {
2001-05-23 15:26:42 +02:00
error(status_vector, "sysconf", errno);
return; // false;
2001-05-23 15:26:42 +02:00
}
#else
const SLONG page_size = (int) getpagesize();
if (page_size == -1) {
2001-05-23 15:26:42 +02:00
error(status_vector, "getpagesize", errno);
return; // false;
2001-05-23 15:26:42 +02:00
}
#endif
/* Compute the start and end page-aligned addresses which
contain the mapped object. */
UCHAR* start = (UCHAR *) ((U_IPTR) * object_pointer & ~(page_size - 1));
const UCHAR* end =
2001-05-23 15:26:42 +02:00
(UCHAR
*) ((U_IPTR) ((*object_pointer + object_length) +
(page_size - 1)) & ~(page_size - 1));
const SLONG length = end - start;
2001-05-23 15:26:42 +02:00
if (munmap((char *) start, length) == -1) {
error(status_vector, "munmap", errno);
return; // false;
2001-05-23 15:26:42 +02:00
}
*object_pointer = NULL;
return; // true;
2001-05-23 15:26:42 +02:00
}
#endif
2008-01-16 10:07:24 +01:00
#ifdef WIN_NT
UCHAR* ISC_map_object(ISC_STATUS* status_vector,
SH_MEM shmem_data,
SLONG object_offset, SLONG object_length)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
2008-01-16 10:07:24 +01:00
* I S C _ m a p _ o b j e c t
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
2008-01-16 10:07:24 +01:00
* Try to map an object given a file mapping.
2001-05-23 15:26:42 +02:00
*
**************************************/
2008-01-16 10:07:24 +01:00
SYSTEM_INFO sys_info;
GetSystemInfo(&sys_info);
const SLONG page_size = sys_info.dwAllocationGranularity;
2001-05-23 15:26:42 +02:00
2008-01-16 10:07:24 +01:00
// Compute the start and end page-aligned offsets which
// contain the object being mapped.
2001-05-23 15:26:42 +02:00
2008-01-16 10:07:24 +01:00
const SLONG start = (object_offset / page_size) * page_size;
const SLONG end = (((object_offset + object_length) / page_size) + 1) * page_size;
const SLONG length = end - start;
const HANDLE handle = shmem_data->sh_mem_object;
2001-05-23 15:26:42 +02:00
2008-01-16 10:07:24 +01:00
UCHAR* address = (UCHAR*) MapViewOfFile(handle, FILE_MAP_WRITE, 0, start, length);
2001-05-23 15:26:42 +02:00
2008-01-16 10:07:24 +01:00
if (address == NULL) {
error(status_vector, "MapViewOfFile", GetLastError());
return NULL;
}
2001-05-23 15:26:42 +02:00
2008-01-16 10:07:24 +01:00
// Return the virtual address of the mapped object.
2001-05-23 15:26:42 +02:00
2008-01-16 10:07:24 +01:00
return (address + (object_offset - start));
2001-05-23 15:26:42 +02:00
}
2008-01-16 10:07:24 +01:00
void ISC_unmap_object(ISC_STATUS* status_vector,
SH_MEM shmem_data,
UCHAR** object_pointer, SLONG object_length)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
2008-01-16 10:07:24 +01:00
* I S C _ u n m a p _ o b j e c t
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
2008-01-16 10:07:24 +01:00
* Try to unmap an object given a file mapping.
* Zero the object pointer after a successful unmap.
2001-05-23 15:26:42 +02:00
*
**************************************/
2008-01-16 10:07:24 +01:00
SYSTEM_INFO sys_info;
GetSystemInfo(&sys_info);
const SLONG page_size = sys_info.dwAllocationGranularity;
2001-05-23 15:26:42 +02:00
2008-01-16 10:07:24 +01:00
// Compute the start and end page-aligned offsets which
// contain the object being mapped.
const UCHAR* start = (UCHAR*) ((U_IPTR) *object_pointer & ~(page_size - 1));
UnmapViewOfFile(start);
*object_pointer = NULL;
2001-05-23 15:26:42 +02:00
}
#endif
#ifdef SOLARIS_MT
2008-01-16 10:07:24 +01:00
int ISC_mutex_init(MTX mutex)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ m u t e x _ i n i t ( S O L A R I S _ M T )
*
**************************************
*
* Functional description
* Initialize a mutex.
*
**************************************/
return mutex_init(mutex->mtx_mutex, USYNC_PROCESS, NULL);
}
int ISC_mutex_lock(MTX mutex)
{
/**************************************
*
* I S C _ m u t e x _ l o c k ( S O L A R I S _ M T )
*
**************************************
*
* Functional description
* Sieze a mutex.
*
**************************************/
for (;;) {
int state = mutex_lock(mutex->mtx_mutex);
2001-05-23 15:26:42 +02:00
if (!state)
break;
if (!SYSCALL_INTERRUPTED(state))
return state;
}
return 0;
}
int ISC_mutex_lock_cond(MTX mutex)
{
/**************************************
*
* I S C _ m u t e x _ l o c k _ c o n d ( S O L A R I S _ M T )
*
**************************************
*
* Functional description
* Conditionally sieze a mutex.
*
**************************************/
for (;;) {
int state = mutex_trylock(mutex->mtx_mutex);
2001-05-23 15:26:42 +02:00
if (!state)
break;
if (!SYSCALL_INTERRUPTED(state))
return state;
}
return 0;
}
int ISC_mutex_unlock(MTX mutex)
{
/**************************************
*
* I S C _ m u t e x _ u n l o c k ( S O L A R I S _ M T )
*
**************************************
*
* Functional description
* Release a mutex.
*
**************************************/
for (;;) {
2002-02-16 04:05:21 +01:00
/* Note use of undocumented lwp_mutex_unlock call
2001-05-23 15:26:42 +02:00
* due to Solaris 2.4 bug */
int state = _lwp_mutex_unlock(mutex->mtx_mutex);
2001-05-23 15:26:42 +02:00
if (!state)
break;
if (!SYSCALL_INTERRUPTED(state))
return state;
}
return 0;
}
#endif /* SOLARIS_MT */
#ifdef USE_POSIX_THREADS
2008-01-16 10:07:24 +01:00
int ISC_mutex_init(MTX mutex)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ m u t e x _ i n i t ( P O S I X _ T H R E A D S )
*
**************************************
*
* Functional description
* Initialize a mutex.
*
**************************************/
pthread_mutexattr_t mattr;
int state = pthread_mutexattr_init(&mattr);
if (state == 0)
2003-10-30 11:03:22 +01:00
{
#if _POSIX_THREAD_PROCESS_SHARED >= 200112L
pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
#endif
state = pthread_mutex_init(mutex->mtx_mutex, &mattr);
pthread_mutexattr_destroy(&mattr);
}
#ifdef HP10
if (state != 0)
state = errno;
#endif
2001-05-23 15:26:42 +02:00
return state;
}
int ISC_mutex_lock(MTX mutex)
{
/**************************************
*
* I S C _ m u t e x _ l o c k ( P O S I X _ T H R E A D S )
*
**************************************
*
* Functional description
* Sieze a mutex.
*
**************************************/
#ifdef HP10
int state = pthread_mutex_lock(mutex->mtx_mutex);
2001-05-23 15:26:42 +02:00
if (!state)
return 0;
2003-11-04 00:59:24 +01:00
fb_assert(state == -1); /* if state is not 0, it should be -1 */
2001-05-23 15:26:42 +02:00
return errno;
#else
return pthread_mutex_lock(mutex->mtx_mutex);
#endif /* HP10 */
}
int ISC_mutex_lock_cond(MTX mutex)
{
/**************************************
*
* I S C _ m u t e x _ l o c k _ c o n d ( P O S I X _ T H R E A D S )
*
**************************************
*
* Functional description
* Conditionally sieze a mutex.
*
**************************************/
#ifdef HP10
int state = pthread_mutex_trylock(mutex->mtx_mutex);
2001-05-23 15:26:42 +02:00
/* HP's interpretation of return codes is different than Solaris
(and Posix Standard?). Usually in case of error they return
-1 and set errno to whatever error number is.
pthread_mutex_trylock() is a special case:
return errno description
1 Success
0 mutex has alreary been locked. Could not get it
-1 EINVAL invalid value of mutex
*/
if (!state)
return -99; /* we did not get the mutex for it had already */
/* been locked, let's return something which is */
/* not zero and negative (errno values are positive) */
if (state == 1)
return 0;
2003-11-04 00:59:24 +01:00
fb_assert(state == -1); /* if state is not 0 or 1, it should be -1 */
2001-05-23 15:26:42 +02:00
return errno;
#else
return pthread_mutex_trylock(mutex->mtx_mutex);
#endif /* HP10 */
}
int ISC_mutex_unlock(MTX mutex)
{
/**************************************
*
* I S C _ m u t e x _ u n l o c k ( P O S I X _ T H R E A D S )
*
**************************************
*
* Functional description
* Release a mutex.
*
**************************************/
#ifdef HP10
int state = pthread_mutex_unlock(mutex->mtx_mutex);
2001-05-23 15:26:42 +02:00
if (!state)
return 0;
2003-11-04 00:59:24 +01:00
fb_assert(state == -1); /* if state is not 0, it should be -1 */
2001-05-23 15:26:42 +02:00
return errno;
#else
return pthread_mutex_unlock(mutex->mtx_mutex);
#endif /* HP10 */
}
#endif /* USE_POSIX_THREADS */
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
static const LPCSTR FAST_MUTEX_EVT_NAME = "%s_FM_EVT";
static const LPCSTR FAST_MUTEX_MAP_NAME = "%s_FM_MAP";
static const int DEFAULT_INTERLOCKED_SPIN_COUNT = 0;
static const int DEFAULT_INTERLOCKED_SPIN_COUNT_SMP = 200;
2007-04-21 05:27:36 +02:00
typedef WINBASEAPI BOOL (WINAPI *pfnSwitchToThread) ();
2007-04-21 05:27:36 +02:00
static inline BOOL switchToThread()
{
static pfnSwitchToThread fnSwitchToThread = NULL;
static bool bInit = false;
if (!bInit)
{
HMODULE hLib = GetModuleHandle("kernel32.dll");
if (hLib) {
fnSwitchToThread = (pfnSwitchToThread) GetProcAddress(hLib, "SwitchToThread");
}
bInit = true;
}
BOOL res = FALSE;
if (fnSwitchToThread)
{
#if !defined SUPERSERVER && !defined EMBEDDED
const HANDLE hThread = GetCurrentThread();
SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL);
#endif
res = (*fnSwitchToThread) ();
#if !defined SUPERSERVER && !defined EMBEDDED
SetThreadPriority(hThread, THREAD_PRIORITY_NORMAL);
#endif
}
return res;
}
2007-03-01 11:35:11 +01:00
// VC6 has the wrong declaration for the operating system function.
2007-03-13 06:33:02 +01:00
// MinGW as well
#if (defined(_MSC_VER) && (_MSC_VER <= 1200)) || defined __GNUC__
2007-04-18 13:02:41 +02:00
// Cast away volatile
2007-03-01 11:35:11 +01:00
#define FIX_TYPE(arg) const_cast<LPLONG>(arg)
#else
#define FIX_TYPE(arg) arg
#endif
static inline void lockSharedSection(volatile FAST_MUTEX_SHARED_SECTION* lpSect, ULONG SpinCount)
{
while (InterlockedExchange(FIX_TYPE(&lpSect->lSpinLock), 1) != 0)
{
ULONG j = SpinCount;
while (j != 0)
{
if (lpSect->lSpinLock == 0)
goto next;
j--;
}
2007-04-21 05:27:36 +02:00
switchToThread();
next:;
}
}
static inline bool tryLockSharedSection(volatile FAST_MUTEX_SHARED_SECTION* lpSect)
{
return (InterlockedExchange(FIX_TYPE(&lpSect->lSpinLock), 1) == 0);
}
static inline void unlockSharedSection(volatile FAST_MUTEX_SHARED_SECTION* lpSect)
{
InterlockedExchange(FIX_TYPE(&lpSect->lSpinLock), 0);
}
static DWORD enterFastMutex(FAST_MUTEX* lpMutex, DWORD dwMilliseconds)
{
volatile FAST_MUTEX_SHARED_SECTION* lpSect = lpMutex->lpSharedInfo;
while (true)
{
DWORD dwResult;
if (dwMilliseconds == 0) {
if (!tryLockSharedSection(lpSect))
return WAIT_TIMEOUT;
}
else {
lockSharedSection(lpSect, lpMutex->lSpinCount);
}
if (lpSect->lAvailable > 0)
{
lpSect->lAvailable--;
#ifdef _DEBUG
lpSect->dwThreadId = GetCurrentThreadId();
#endif
unlockSharedSection(lpSect);
return WAIT_OBJECT_0;
}
#ifdef _DEBUG
if (lpSect->dwThreadId == GetCurrentThreadId())
DebugBreak();
#endif
if (dwMilliseconds == 0)
{
unlockSharedSection(lpSect);
return WAIT_TIMEOUT;
}
InterlockedIncrement(FIX_TYPE(&lpSect->lThreadsWaiting));
unlockSharedSection(lpSect);
// TODO actual timeout can be of any length
dwResult = WaitForSingleObject(lpMutex->hEvent, dwMilliseconds);
InterlockedDecrement(FIX_TYPE(&lpSect->lThreadsWaiting));
if (dwResult != WAIT_OBJECT_0)
return dwResult;
}
}
static bool leaveFastMutex(FAST_MUTEX* lpMutex)
{
volatile FAST_MUTEX_SHARED_SECTION* lpSect = lpMutex->lpSharedInfo;
lockSharedSection(lpSect, lpMutex->lSpinCount);
if (lpSect->lAvailable >= 1)
{
unlockSharedSection(lpSect);
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
lpSect->lAvailable++;
if (lpSect->lThreadsWaiting)
SetEvent(lpMutex->hEvent);
unlockSharedSection(lpSect);
return true;
}
2007-03-01 11:35:11 +01:00
static inline void deleteFastMutex(FAST_MUTEX* lpMutex)
{
UnmapViewOfFile((FAST_MUTEX_SHARED_SECTION*)lpMutex->lpSharedInfo);
CloseHandle(lpMutex->hFileMap);
CloseHandle(lpMutex->hEvent);
}
static inline void setupMutex(FAST_MUTEX* lpMutex)
{
SYSTEM_INFO si;
GetSystemInfo(&si);
if (si.dwNumberOfProcessors > 1)
lpMutex->lSpinCount = DEFAULT_INTERLOCKED_SPIN_COUNT_SMP;
else
lpMutex->lSpinCount = DEFAULT_INTERLOCKED_SPIN_COUNT;
}
static bool initializeFastMutex(FAST_MUTEX* lpMutex, LPSECURITY_ATTRIBUTES lpAttributes,
BOOL bInitialState, LPCSTR lpName)
{
LPCSTR name = lpName;
if (strlen(lpName) + strlen(FAST_MUTEX_EVT_NAME) - 2 >= MAXPATHLEN)
{
// this is the same error which CreateEvent will return for long name
SetLastError(ERROR_FILENAME_EXCED_RANGE);
return false;
}
setupMutex(lpMutex);
2008-01-16 10:07:24 +01:00
char sz[MAXPATHLEN];
if (lpName)
{
sprintf(sz, FAST_MUTEX_EVT_NAME, lpName);
name = sz;
}
lpMutex->hEvent = CreateEvent(lpAttributes, FALSE, FALSE, name);
2008-01-16 10:07:24 +01:00
DWORD dwLastError = GetLastError();
if (lpMutex->hEvent)
{
if (lpName)
sprintf(sz, FAST_MUTEX_MAP_NAME, lpName);
lpMutex->hFileMap = CreateFileMapping(
INVALID_HANDLE_VALUE,
lpAttributes,
PAGE_READWRITE,
0,
sizeof(FAST_MUTEX_SHARED_SECTION),
name);
dwLastError = GetLastError();
if (lpMutex->hFileMap)
{
lpMutex->lpSharedInfo = (FAST_MUTEX_SHARED_SECTION*)
MapViewOfFile(lpMutex->hFileMap, FILE_MAP_WRITE, 0, 0, 0);
if (lpMutex->lpSharedInfo)
{
if (dwLastError != ERROR_ALREADY_EXISTS)
{
lpMutex->lpSharedInfo->lSpinLock = 0;
lpMutex->lpSharedInfo->lThreadsWaiting = 0;
lpMutex->lpSharedInfo->lAvailable = bInitialState ? 0 : 1;
2007-03-01 11:35:11 +01:00
InterlockedExchange(FIX_TYPE(&lpMutex->lpSharedInfo->fInitialized), 1);
}
else
{
while (!lpMutex->lpSharedInfo->fInitialized)
2007-04-21 05:27:36 +02:00
switchToThread();
}
SetLastError(dwLastError);
return true;
}
CloseHandle(lpMutex->hFileMap);
}
CloseHandle(lpMutex->hEvent);
}
SetLastError(dwLastError);
return false;
}
static bool openFastMutex(FAST_MUTEX* lpMutex, DWORD DesiredAccess, LPCSTR lpName)
{
LPCSTR name = lpName;
if (strlen(lpName) + strlen(FAST_MUTEX_EVT_NAME) - 2 >= MAXPATHLEN)
{
SetLastError(ERROR_FILENAME_EXCED_RANGE);
return false;
}
setupMutex(lpMutex);
2008-01-16 10:07:24 +01:00
char sz[MAXPATHLEN];
if (lpName)
{
sprintf(sz, FAST_MUTEX_EVT_NAME, lpName);
name = sz;
}
lpMutex->hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, name);
2008-01-16 10:07:24 +01:00
DWORD dwLastError = GetLastError();
if (lpMutex->hEvent)
{
if (lpName)
sprintf(sz, FAST_MUTEX_MAP_NAME, lpName);
lpMutex->hFileMap = OpenFileMapping(
FILE_MAP_ALL_ACCESS,
FALSE,
name);
dwLastError = GetLastError();
if (lpMutex->hFileMap)
{
lpMutex->lpSharedInfo = (FAST_MUTEX_SHARED_SECTION*)
MapViewOfFile(lpMutex->hFileMap, FILE_MAP_WRITE, 0, 0, 0);
if (lpMutex->lpSharedInfo)
return true;
CloseHandle(lpMutex->hFileMap);
}
CloseHandle(lpMutex->hEvent);
}
SetLastError(dwLastError);
return false;
}
static inline void setFastMutexSpinCount(FAST_MUTEX* lpMutex, ULONG SpinCount)
{
lpMutex->lSpinCount = SpinCount;
}
int ISC_mutex_init(MTX mutex, const TEXT* mutex_name)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ m u t e x _ i n i t ( W I N _ N T )
*
**************************************
*
* Functional description
* Initialize a mutex.
*
**************************************/
char name_buffer[MAXPATHLEN];
2001-05-23 15:26:42 +02:00
make_object_name(name_buffer, sizeof(name_buffer), mutex_name, "_mutex");
2001-05-23 15:26:42 +02:00
return !initializeFastMutex(&mutex->mtx_fast,
ISC_get_security_desc(), FALSE, name_buffer);
}
void ISC_mutex_fini(struct mtx *mutex)
{
if (mutex->mtx_fast.lpSharedInfo)
deleteFastMutex(&mutex->mtx_fast);
2001-05-23 15:26:42 +02:00
}
int ISC_mutex_lock(MTX mutex)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ m u t e x _ l o c k ( W I N _ N T )
*
**************************************
*
* Functional description
* Sieze a mutex.
*
**************************************/
const DWORD status = (mutex->mtx_fast.lpSharedInfo) ?
enterFastMutex(&mutex->mtx_fast, INFINITE) :
WaitForSingleObject(mutex->mtx_fast.hEvent, INFINITE);
return (status == WAIT_OBJECT_0 || status == WAIT_ABANDONED) ? 0 : 1;
2001-05-23 15:26:42 +02:00
}
int ISC_mutex_lock_cond(MTX mutex)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ m u t e x _ l o c k _ c o n d ( W I N _ N T )
*
**************************************
*
* Functional description
* Conditionally sieze a mutex.
*
**************************************/
const DWORD status = (mutex->mtx_fast.lpSharedInfo) ?
enterFastMutex(&mutex->mtx_fast, 0) :
WaitForSingleObject (mutex->mtx_fast.hEvent, 0L);
return (status == WAIT_OBJECT_0 || status == WAIT_ABANDONED) ? 0 : 1;
2001-05-23 15:26:42 +02:00
}
int ISC_mutex_unlock(MTX mutex)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ m u t e x _ u n l o c k ( W I N _ N T )
*
**************************************
*
* Functional description
* Release a mutex.
*
**************************************/
if (mutex->mtx_fast.lpSharedInfo) {
return !leaveFastMutex(&mutex->mtx_fast);
}
2008-01-16 10:07:24 +01:00
return !ReleaseMutex(mutex->mtx_fast.hEvent);
2001-05-23 15:26:42 +02:00
}
void ISC_mutex_set_spin_count (struct mtx *mutex, ULONG spins)
{
if (mutex->mtx_fast.lpSharedInfo)
setFastMutexSpinCount(&mutex->mtx_fast, spins);
}
#endif // WIN_NT
2001-05-23 15:26:42 +02:00
#ifdef UNIX
#ifdef HAVE_MMAP
2001-05-23 15:26:42 +02:00
#define ISC_REMAP_FILE_DEFINED
2003-04-10 08:49:16 +02:00
UCHAR *ISC_remap_file(ISC_STATUS * status_vector,
SH_MEM shmem_data, SLONG new_length, bool flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ r e m a p _ f i l e ( U N I X - m m a p )
*
**************************************
*
* Functional description
* Try to re-map a given file.
*
**************************************/
if (flag)
ftruncate(shmem_data->sh_mem_handle, new_length);
UCHAR* address =
2001-05-23 15:26:42 +02:00
(UCHAR *) mmap(0, new_length, PROT_READ | PROT_WRITE, MAP_SHARED,
shmem_data->sh_mem_handle, 0);
if ((U_IPTR) address == (U_IPTR) -1)
2001-05-23 15:26:42 +02:00
return NULL;
munmap((char *) shmem_data->sh_mem_address,
shmem_data->sh_mem_length_mapped);
shmem_data->sh_mem_address = address;
shmem_data->sh_mem_length_mapped = new_length;
return address;
}
#endif
#endif
#ifdef WIN_NT
#define ISC_REMAP_FILE_DEFINED
UCHAR* ISC_remap_file(ISC_STATUS * status_vector,
SH_MEM shmem_data,
SLONG new_length,
bool flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ r e m a p _ f i l e ( W I N _ N T )
*
**************************************
*
* Functional description
* Try to re-map a given file.
*
**************************************/
if (flag)
if (SetFilePointer
(shmem_data->sh_mem_handle, new_length, NULL,
FILE_BEGIN) == 0xFFFFFFFF
|| !SetEndOfFile(shmem_data->sh_mem_handle)
|| !FlushViewOfFile(shmem_data->sh_mem_address, 0))
{
2001-05-23 15:26:42 +02:00
error(status_vector, "SetFilePointer", GetLastError());
return NULL;
}
/* If the remap file exists, remap does not occur correctly.
2002-02-16 04:05:21 +01:00
* The file number is local to the process and when it is
2001-05-23 15:26:42 +02:00
* incremented and a new filename is created, that file may
* already exist. In that case, the file is not expanded.
* This will happen when the file is expanded more than once
* by concurrently running processes.
2002-02-16 04:05:21 +01:00
*
2001-05-23 15:26:42 +02:00
* The problem will be fixed by making sure that a new file name
* is generated with the mapped file is created.
*/
HANDLE file_obj;
2004-11-10 05:35:58 +01:00
while (true) {
TEXT expanded_filename[MAXPATHLEN];
2003-04-01 23:59:31 +02:00
sprintf(expanded_filename, "%s%"SLONGFORMAT, shmem_data->sh_mem_name,
2001-05-23 15:26:42 +02:00
shmem_data->sh_mem_hdr_address[1] + 1);
file_obj = CreateFileMapping(shmem_data->sh_mem_handle,
ISC_get_security_desc(),
PAGE_READWRITE,
0,
new_length,
expanded_filename);
2001-05-23 15:26:42 +02:00
if (!((GetLastError() == ERROR_ALREADY_EXISTS) && flag))
break;
CloseHandle(file_obj);
shmem_data->sh_mem_hdr_address[1]++;
}
if (file_obj == NULL) {
error(status_vector, "CreateFileMapping", GetLastError());
return NULL;
}
LPVOID address = MapViewOfFile(file_obj, FILE_MAP_WRITE, 0, 0, 0);
2001-05-23 15:26:42 +02:00
if (address == NULL) {
error(status_vector, "CreateFileMapping", GetLastError());
CloseHandle(file_obj);
return NULL;
}
if (flag) {
shmem_data->sh_mem_hdr_address[0] = new_length;
shmem_data->sh_mem_hdr_address[1]++;
}
UnmapViewOfFile(shmem_data->sh_mem_address);
CloseHandle(shmem_data->sh_mem_object);
shmem_data->sh_mem_address = static_cast<UCHAR*>(address);
2001-05-23 15:26:42 +02:00
shmem_data->sh_mem_length_mapped = new_length;
shmem_data->sh_mem_object = file_obj;
return reinterpret_cast<UCHAR*>(address);
2001-05-23 15:26:42 +02:00
}
#endif
#ifndef ISC_REMAP_FILE_DEFINED
UCHAR* ISC_remap_file(ISC_STATUS * status_vector,
SH_MEM shmem_data,
SLONG new_length,
bool flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ r e m a p _ f i l e ( G E N E R I C )
*
**************************************
*
* Functional description
* Try to re-map a given file.
*
**************************************/
*status_vector++ = isc_arg_gds;
*status_vector++ = isc_unavailable;
*status_vector++ = isc_arg_end;
2001-05-23 15:26:42 +02:00
return NULL;
}
#endif
#if (defined UNIX)
void ISC_reset_timer(
FPTR_VOID_PTR timeout_handler,
2001-05-23 15:26:42 +02:00
void *timeout_arg,
SLONG * client_timer, void **client_handler)
{
/**************************************
*
* I S C _ r e s e t _ t i m e r
*
**************************************
*
* Functional description
* Clear a previously established timer and restore
* the previous context.
*
**************************************/
struct itimerval internal_timer;
ISC_signal_cancel(SIGALRM, timeout_handler, timeout_arg);
/* Cancel the timer, then restore the previous handler and alarm */
timerclear(&internal_timer.it_interval);
timerclear(&internal_timer.it_value);
setitimer(ITIMER_REAL, &internal_timer, NULL);
2001-07-12 07:46:06 +02:00
sigaction(SIGALRM, (struct sigaction*)client_handler, NULL);
setitimer(ITIMER_REAL, (itimerval*)client_timer, NULL);
2001-05-23 15:26:42 +02:00
}
#endif
#if (defined UNIX)
void ISC_set_timer(
SLONG micro_seconds,
FPTR_VOID_PTR timeout_handler,
2001-05-23 15:26:42 +02:00
void *timeout_arg,
SLONG * client_timer, void **client_handler)
{
/**************************************
*
* I S C _ s e t _ t i m e r
*
**************************************
*
* Functional description
* Set a timer for the specified amount of time.
*
**************************************/
struct itimerval internal_timer;
struct sigaction internal_handler;
/* Start by cancelling any existing timer */
timerclear(&internal_timer.it_interval);
timerclear(&internal_timer.it_value);
setitimer(ITIMER_REAL, &internal_timer,
(struct itimerval *) client_timer);
/* Now clear the signal handler while saving the existing one */
internal_handler.sa_handler = SIG_DFL;
sigemptyset(&internal_handler.sa_mask);
2001-05-23 15:26:42 +02:00
internal_handler.sa_flags = SA_RESTART;
sigaction(SIGALRM, &internal_handler,
(struct sigaction *) client_handler);
if (!micro_seconds)
return;
/* Next set the new alarm handler and finally set the new timer */
ISC_signal(SIGALRM, timeout_handler, timeout_arg);
if (micro_seconds < 1000000)
internal_timer.it_value.tv_usec = micro_seconds;
else {
internal_timer.it_value.tv_sec = micro_seconds / 1000000;
internal_timer.it_value.tv_usec = micro_seconds % 1000000;
}
setitimer(ITIMER_REAL, &internal_timer, NULL);
}
#endif
#ifdef UNIX
void ISC_sync_signals_set(void* arg)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ s y n c _ s i g n a l s _ s e t ( U N I X )
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Set all the synchronous signals for a particular thread
*
**************************************/
sigjmp_buf* const sigenv = static_cast<sigjmp_buf*>(arg);
TLS_SET(sigjmp_ptr, sigenv);
2001-05-23 15:26:42 +02:00
sigset(SIGILL, longjmp_sig_handler);
sigset(SIGFPE, longjmp_sig_handler);
sigset(SIGBUS, longjmp_sig_handler);
sigset(SIGSEGV, longjmp_sig_handler);
}
void ISC_sync_signals_reset()
{
/**************************************
*
* I S C _ s y n c _ s i g n a l s _ r e s e t ( U N I X )
*
**************************************
*
* Functional description
* Reset all the synchronous signals for a particular thread
* to default.
*
**************************************/
sigset(SIGILL, SIG_DFL);
sigset(SIGFPE, SIG_DFL);
sigset(SIGBUS, SIG_DFL);
sigset(SIGSEGV, SIG_DFL);
}
#endif // UNIX
2001-05-23 15:26:42 +02:00
#ifdef UNIX
#ifdef HAVE_MMAP
2001-05-23 15:26:42 +02:00
#define UNMAP_FILE
2003-04-10 08:49:16 +02:00
void ISC_unmap_file(ISC_STATUS * status_vector, SH_MEM shmem_data, USHORT flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ u n m a p _ f i l e ( U N I X - m m a p )
*
**************************************
*
* Functional description
* Unmap a given file. Depending upon the flag,
* get rid of the semaphore and/or truncate the file.
*
**************************************/
union semun arg;
munmap((char *) shmem_data->sh_mem_address,
shmem_data->sh_mem_length_mapped);
close(shmem_data->sh_mem_handle);
}
#endif
#endif
#ifdef UNIX
#ifndef HAVE_MMAP
2001-05-23 15:26:42 +02:00
#define UNMAP_FILE
void ISC_unmap_file(ISC_STATUS* status_vector, SH_MEM shmem_data, USHORT flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ u n m a p _ f i l e ( U N I X - s h m a t )
*
**************************************
*
* Functional description
* Detach from the shared memory. Depending upon the flag,
* get rid of the semaphore and/or get rid of shared memory.
*
**************************************/
struct shmid_ds buf;
union semun arg;
shmdt(shmem_data->sh_mem_address);
}
#endif
#endif
#ifdef WIN_NT
#define UNMAP_FILE
void ISC_unmap_file(ISC_STATUS * status_vector,
SH_MEM shmem_data,
USHORT flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ u n m a p _ f i l e ( W I N _ N T )
*
**************************************
*
* Functional description
* Detach from the shared memory. Depending upon the flag,
* get rid of the semaphore and/or get rid of shared memory.
*
**************************************/
CloseHandle(shmem_data->sh_mem_interest);
UnmapViewOfFile(shmem_data->sh_mem_address);
CloseHandle(shmem_data->sh_mem_object);
2001-05-23 15:26:42 +02:00
CloseHandle(shmem_data->sh_mem_handle);
UnmapViewOfFile(shmem_data->sh_mem_hdr_address);
CloseHandle(shmem_data->sh_mem_hdr_object);
}
#endif
#ifndef UNMAP_FILE
void ISC_unmap_file(ISC_STATUS * status_vector,
SH_MEM shmem_data,
USHORT flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I S C _ u n m a p _ f i l e ( G E N E R I C )
*
**************************************
*
* Functional description
* unmap a given file or shared memory.
*
**************************************/
*status_vector++ = isc_arg_gds;
*status_vector++ = isc_unavailable;
*status_vector++ = isc_arg_end;
2001-05-23 15:26:42 +02:00
}
#endif
static void error(ISC_STATUS* status_vector, TEXT* string, ISC_STATUS status)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* e r r o r
*
**************************************
*
* Functional description
* We've encountered an error, report it.
*
**************************************/
*status_vector++ = isc_arg_gds;
*status_vector++ = isc_sys_request;
*status_vector++ = isc_arg_string;
*status_vector++ = (ISC_STATUS)(U_IPTR) string;
2001-05-23 15:26:42 +02:00
*status_vector++ = SYS_ARG;
*status_vector++ = status;
*status_vector++ = isc_arg_end;
2001-05-23 15:26:42 +02:00
}
#ifdef UNIX
2003-04-10 08:49:16 +02:00
static SLONG find_key(ISC_STATUS * status_vector, TEXT * filename)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
2002-02-16 04:05:21 +01:00
* f i n d _ k e y
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Find the semaphore/shared memory key for a file.
*
**************************************/
int fd;
2002-11-21 11:20:07 +01:00
key_t key;
2001-05-23 15:26:42 +02:00
/* Produce shared memory key for file */
if ((key = ftok(filename, FTOK_KEY)) == -1) {
if ((fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, PRIV)) == -1) {
error(status_vector, "open", errno);
2002-09-26 11:26:40 +02:00
return 0L;
2001-05-23 15:26:42 +02:00
}
close(fd);
if ((key = ftok(filename, FTOK_KEY)) == -1) {
error(status_vector, "ftok", errno);
2002-09-26 11:26:40 +02:00
return 0L;
2001-05-23 15:26:42 +02:00
}
}
return key;
}
#endif
#ifdef UNIX
void longjmp_sig_handler(int sig_num)
{
/**************************************
*
* l o n g j m p _ s i g _ h a n d l e r
*
**************************************
*
* Functional description
* The generic signal handler for all signals in a thread.
*
**************************************/
siglongjmp(*TLS_GET(sigjmp_ptr), sig_num);
2001-05-23 15:26:42 +02:00
}
#endif // UNIX
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
static void make_object_name(
TEXT* buffer,
size_t bufsize,
const TEXT* object_name,
const TEXT* object_type)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* m a k e _ o b j e c t _ n a m e ( W I N _ N T )
*
**************************************
*
* Functional description
* Create an object name from a name and type.
* Also replace the file separator with "_".
*
**************************************/
char hostname[64];
_snprintf(buffer, bufsize, object_name, ISC_get_host(hostname, sizeof(hostname)));
buffer[bufsize - 1] = 0;
char* p;
char c;
2001-05-23 15:26:42 +02:00
for (p = buffer; c = *p; p++)
if (c == '/' || c == '\\' || c == ':')
*p = '_';
strcpy(p, object_type);
// hvlad: windows file systems use case-insensitive file names
// while kernel objects such as events use case-sensitive names.
// Since we use root directory as part of kernel objects names
// we must use lower (or upper) register for object name to avoid
// misunderstanding between processes
strlwr(buffer);
#ifndef EMBEDDED
fb_utils::prefix_kernel_object_name(buffer, bufsize);
#endif
2001-05-23 15:26:42 +02:00
}
#endif // WIN_NT