2
* PROGRAM: JRD Access Method
4
* DESCRIPTION: General purpose but non-user routines.
6
* The contents of this file are subject to the Interbase Public
7
* License Version 1.0 (the "License"); you may not use this file
8
* except in compliance with the License. You may obtain a copy
9
* of the License at http://www.Inprise.com/IPL.html
11
* Software distributed under the License is distributed on an
12
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
13
* or implied. See the License for the specific language governing
14
* rights and limitations under the License.
16
* The Original Code was created by Inprise Corporation
17
* and its predecessors. Portions created by Inprise Corporation are
18
* Copyright (C) Inprise Corporation.
20
* All Rights Reserved.
21
* Contributor(s): ______________________________________.
23
* 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "XENIX" port
24
* 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "DELTA" port
25
* 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "IMP" port
27
* 2002-02-23 Sean Leyne - Code Cleanup, removed old M88K and NCR3000 port
29
* 2002.10.27 Sean Leyne - Completed removal of obsolete "DG_X86" port
30
* 2002.10.27 Sean Leyne - Completed removal of obsolete "M88K" port
32
* 2002.10.28 Sean Leyne - Completed removal of obsolete "DGUX" port
33
* 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "DecOSF" port
34
* 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "SGI" port
36
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
47
#define NDEBUG // Turn off fb_assert() macros
49
#include "../jrd/gdsassert.h"
53
#include <sys/pstat.h>
56
//#include "../common/classes/timestamp.h"
57
#include "../jrd/common.h"
58
#include "gen/iberror.h"
59
#include "../jrd/isc.h"
60
#include "../jrd/gds_proto.h"
61
#include "../jrd/isc_proto.h"
62
#include "../jrd/os/isc_i_proto.h"
63
#include "../jrd/isc_s_proto.h"
64
#include "../jrd/file_params.h"
65
#include "../jrd/gdsassert.h"
66
#include "../jrd/jrd.h"
67
#include "../jrd/sch_proto.h"
68
#include "../jrd/err_proto.h"
69
#include "../jrd/thd.h"
70
#include "../jrd/thread_proto.h"
71
#include "../jrd/jrd_pwd.h"
72
#include "../common/config/config.h"
73
#include "../common/utils_proto.h"
75
#if defined(SIG_RESTART) || defined(UNIX)
76
static ULONG inhibit_restart;
79
static int process_id;
82
static UCHAR *next_shared_memory;
85
/* VMS Specific Stuff */
96
#include "../jrd/lnmdef.h"
99
#include "../jrd/prv_m_bypass.h"
100
#endif /* of ifdef VMS */
103
/* Unix specific stuff */
106
#include <sys/types.h>
107
#include <sys/stat.h>
108
#include <sys/file.h>
114
#ifdef HAVE_SYS_SIGNAL_H
115
#include <sys/signal.h>
131
#include <sys/mman.h>
138
#define SHMEM_DELTA (1 << 22)
142
#define SIGURG SIGINT
149
struct semid_ds *buf;
155
#ifdef HAVE_SYS_PARAM_H
156
#include <sys/param.h>
159
#ifndef HAVE_GETPAGESIZE
160
static size_t getpagesize(void)
179
static void error(ISC_STATUS*, TEXT*, ISC_STATUS);
182
static SLONG find_key(ISC_STATUS *, TEXT *);
183
#if !(defined(USE_POSIX_THREADS) || defined(SOLARIS_MT))
184
static void alarm_handler(void* arg);
185
static SLONG open_semaphores(ISC_STATUS *, SLONG, int&);
186
static SLONG create_semaphores(ISC_STATUS *, SLONG, int);
187
static bool semaphore_wait_isc_sync(int, int, int *);
190
static void longjmp_sig_handler(int);
195
static int event_test(WAIT *);
196
static BOOLEAN mutex_test(MTX);
200
static void make_object_name(TEXT*, size_t, const TEXT*, const TEXT*);
203
#if defined FREEBSD || defined NETBSD || defined DARWIN || defined HPUX
204
#define sigset signal
209
BOOLEAN ISC_check_restart(void)
211
/**************************************
213
* I S C _ c h e c k _ r e s t a r t
215
**************************************
217
* Functional description
218
* Return a flag that indicats whether
219
* or not to restart an interrupted
222
**************************************/
224
return (inhibit_restart) ? FALSE : TRUE;
226
#endif /* SIG_RESTART */
231
int ISC_event_blocked(USHORT count, event_t** events, SLONG* values)
233
/**************************************
235
* I S C _ e v e n t _ b l o c k e d ( S O L A R I S _ M T )
237
**************************************
239
* Functional description
240
* If a wait would block, return TRUE.
242
**************************************/
244
for (; count > 0; --count, ++events, ++values)
245
if ((*events)->event_count >= *values) {
246
#ifdef DEBUG_ISC_SYNC
247
printf("ISC_event_blocked: FALSE (eg something to report)\n");
253
#ifdef DEBUG_ISC_SYNC
254
printf("ISC_event_blocked: TRUE (eg nothing happened yet)\n");
261
SLONG ISC_event_clear(event_t* event)
263
/**************************************
265
* I S C _ e v e n t _ c l e a r ( S O L A R I S _ M T )
267
**************************************
269
* Functional description
270
* Clear an event preparatory to waiting on it. The order of
271
* battle for event synchronization is:
274
* 2. Test data structure for event already completed
277
**************************************/
278
mutex_lock(event->event_mutex);
279
const SLONG ret = event->event_count + 1;
280
mutex_unlock(event->event_mutex);
285
void ISC_event_fini(event_t* event)
287
/**************************************
289
* I S C _ e v e n t _ f i n i ( S O L A R I S _ M T )
291
**************************************
293
* Functional description
294
* Discard an event object.
296
**************************************/
298
/* Inter-Process event's are destroyed only */
299
if (event->event_semid == -1) {
300
mutex_destroy(event->event_mutex);
301
cond_destroy(event->event_semnum);
306
int ISC_event_init(event_t* event, int semid, int semnum)
308
/**************************************
310
* I S C _ e v e n t _ i n i t ( S O L A R I S _ M T )
312
**************************************
314
* Functional description
315
* Prepare an event object for use.
317
**************************************/
321
event->event_count = 0;
324
/* Prepare an Inter-Thread event block */
325
event->event_semid = -1;
326
mutex_init(event->event_mutex, USYNC_THREAD, NULL);
327
cond_init(event->event_semnum, USYNC_THREAD, NULL);
330
/* Prepare an Inter-Process event block */
331
event->event_semid = semid;
332
mutex_init(event->event_mutex, USYNC_PROCESS, NULL);
333
cond_init(event->event_semnum, USYNC_PROCESS, NULL);
340
int ISC_event_post(event_t* event)
342
/**************************************
344
* I S C _ e v e n t _ p o s t ( S O L A R I S _ M T )
346
**************************************
348
* Functional description
349
* Post an event to wake somebody else up.
351
**************************************/
352
/* For Solaris, we use cond_broadcast rather than cond_signal so that
353
all waiters on the event are notified and awakened */
355
mutex_lock(event->event_mutex);
356
++event->event_count;
357
const int ret = cond_broadcast(event->event_semnum);
358
mutex_unlock(event->event_mutex);
360
gds__log("ISC_event_post: cond_broadcast failed with errno = %d",
366
int ISC_event_wait(SSHORT count,
370
FPTR_VOID_PTR timeout_handler,
373
/**************************************
375
* I S C _ e v e n t _ w a i t ( S O L A R I S _ M T )
377
**************************************
379
* Functional description
380
* Wait on an event. If timeout limit specified, return
381
* anyway after the timeout even if no event has
382
* happened. If returning due to timeout, return
383
* FB_FAILURE else return FB_SUCCESS.
385
**************************************/
387
/* While the API for ISC_event_wait allows for a list of events
388
we never actually make use of it. This implementation wont
389
support it anyway as Solaris doesn't provide a "wait for one
390
of a series of conditions" function */
391
fb_assert(count == 1);
393
/* If we're not blocked, the rest is a gross waste of time */
395
if (!ISC_event_blocked(count, events, values))
398
/* Set up timers if a timeout period was specified. */
401
if (micro_seconds > 0) {
402
timer.tv_sec = time(NULL);
403
timer.tv_sec += micro_seconds / 1000000;
404
timer.tv_nsec = 1000 * (micro_seconds % 1000000);
407
int ret = FB_SUCCESS;
408
mutex_lock((*events)->event_mutex);
410
if (!ISC_event_blocked(count, events, values)) {
415
/* The Solaris cond_wait & cond_timedwait calls atomically release
416
the mutex and start a wait. The mutex is reacquired before the
419
if (micro_seconds > 0)
421
cond_timedwait((*events)->event_semnum,
422
(*events)->event_mutex, &timer);
424
ret = cond_wait((*events)->event_semnum, (*events)->event_mutex);
425
if (micro_seconds > 0 && (ret == ETIME)) {
427
/* The timer expired - see if the event occured and return
428
FB_SUCCESS or FB_FAILURE accordingly. */
430
if (ISC_event_blocked(count, events, values))
437
mutex_unlock((*events)->event_mutex);
440
#endif /* SOLARIS_MT */
443
#ifdef USE_POSIX_THREADS
445
int ISC_event_blocked(USHORT count, event_t** events, SLONG * values)
447
/**************************************
449
* 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 )
451
**************************************
453
* Functional description
454
* If a wait would block, return TRUE.
456
**************************************/
458
for (; count > 0; --count, ++events, ++values)
459
if ((*events)->event_count >= *values) {
460
#ifdef DEBUG_ISC_SYNC
461
printf("ISC_event_blocked: FALSE (eg something to report)\n");
467
#ifdef DEBUG_ISC_SYNC
468
printf("ISC_event_blocked: TRUE (eg nothing happened yet)\n");
475
SLONG ISC_event_clear(event_t* event)
477
/**************************************
479
* 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 )
481
**************************************
483
* Functional description
484
* Clear an event preparatory to waiting on it. The order of
485
* battle for event synchronization is:
488
* 2. Test data structure for event already completed
491
**************************************/
492
pthread_mutex_lock(event->event_mutex);
493
const SLONG ret = event->event_count + 1;
494
pthread_mutex_unlock(event->event_mutex);
499
void ISC_event_fini(event_t* event)
501
/**************************************
503
* I S C _ e v e n t _ f i n i ( P O S I X _ T H R E A D S )
505
**************************************
507
* Functional description
508
* Discard an event object.
510
**************************************/
512
/* Inter-Thread event's are destroyed only */
513
if (event->event_semid == -1) {
514
pthread_mutex_destroy(event->event_mutex);
515
pthread_cond_destroy(event->event_semnum);
520
int ISC_event_init(event_t* event, int semid, int semnum)
522
/**************************************
524
* I S C _ e v e n t _ i n i t ( P O S I X _ T H R E A D S )
526
**************************************
528
* Functional description
529
* Prepare an event object for use.
531
**************************************/
534
pthread_mutexattr_t mattr;
535
pthread_condattr_t cattr;
537
event->event_count = 0;
540
/* Prepare an Inter-Thread event block */
541
event->event_semid = -1;
543
/* Default attribute objects initialize sync. primitives
544
to be used to sync thread within one process only.
547
pthread_mutex_init(event->event_mutex, pthread_mutexattr_default);
548
pthread_cond_init(event->event_semnum, pthread_condattr_default);
550
pthread_mutex_init(event->event_mutex, NULL);
551
pthread_cond_init(event->event_semnum, NULL);
555
/* Prepare an Inter-Process event block */
556
event->event_semid = semid;
558
pthread_mutexattr_init(&mattr);
559
#if _POSIX_THREAD_PROCESS_SHARED >= 200112L
560
pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
562
pthread_mutex_init(event->event_mutex, &mattr);
563
pthread_mutexattr_destroy(&mattr);
565
pthread_condattr_init(&cattr);
566
#if _POSIX_THREAD_PROCESS_SHARED >= 200112L
567
pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
569
pthread_cond_init(event->event_semnum, &cattr);
570
pthread_condattr_destroy(&cattr);
577
int ISC_event_post(event_t* event)
579
/**************************************
581
* I S C _ e v e n t _ p o s t ( P O S I X _ T H R E A D S )
583
**************************************
585
* Functional description
586
* Post an event to wake somebody else up.
588
**************************************/
589
pthread_mutex_lock(event->event_mutex);
590
++event->event_count;
591
const int ret = pthread_cond_broadcast(event->event_semnum);
592
pthread_mutex_unlock(event->event_mutex);
597
fb_assert(ret == -1);
599
("ISC_event_post: pthread_cond_broadcast failed with errno = %d",
608
("ISC_event_post: pthread_cond_broadcast failed with errno = %d",
621
FPTR_VOID_PTR timeout_handler, void *handler_arg)
623
/**************************************
625
* I S C _ e v e n t _ w a i t ( P O S I X _ T H R E A D S )
627
**************************************
629
* Functional description
630
* Wait on an event. If timeout limit specified, return
631
* anyway after the timeout even if no event has
632
* happened. If returning due to timeout, return
633
* FB_FAILURE else return FB_SUCCESS.
635
**************************************/
637
/* While the API for ISC_event_wait allows for a list of events
638
we never actually make use of it. This implementation wont
639
support it anyway as Solaris doesn't provide a "wait for one
640
of a series of conditions" function */
641
fb_assert(count == 1);
643
/* If we're not blocked, the rest is a gross waste of time */
645
if (!ISC_event_blocked(count, events, values))
648
/* Set up timers if a timeout period was specified. */
650
struct timespec timer;
651
if (micro_seconds > 0) {
652
timer.tv_sec = time(NULL);
653
timer.tv_sec += micro_seconds / 1000000;
654
timer.tv_nsec = 1000 * (micro_seconds % 1000000);
657
int ret = FB_SUCCESS;
658
pthread_mutex_lock((*events)->event_mutex);
660
if (!ISC_event_blocked(count, events, values)) {
665
/* The Posix pthread_cond_wait & pthread_cond_timedwait calls
666
atomically release the mutex and start a wait.
667
The mutex is reacquired before the call returns.
669
if (micro_seconds > 0)
672
pthread_cond_timedwait((*events)->event_semnum,
673
(*events)->event_mutex, &timer);
676
if ((ret == -1) && (errno == EAGAIN))
678
#if (defined LINUX || defined DARWIN || defined HP11 || defined FREEBSD)
679
if (ret == ETIMEDOUT)
686
/* The timer expired - see if the event occured and return
687
FB_SUCCESS or FB_FAILURE accordingly. */
689
if (ISC_event_blocked(count, events, values))
698
pthread_cond_wait((*events)->event_semnum,
699
(*events)->event_mutex);
701
pthread_mutex_unlock((*events)->event_mutex);
704
#endif /* USE_POSIX_THREADS */
710
int ISC_event_blocked(USHORT count, event_t** events, SLONG * values)
712
/**************************************
714
* I S C _ e v e n t _ b l o c k e d ( U N I X )
716
* not USE_POSIX_THREADS
717
**************************************
719
* Functional description
720
* If a wait would block, return TRUE.
722
**************************************/
724
for (; count > 0; --count, ++events, ++values)
725
if ((*events)->event_count >= *values) {
726
#ifdef DEBUG_ISC_SYNC
727
printf("ISC_event_blocked: FALSE (eg something to report)\n");
733
#ifdef DEBUG_ISC_SYNC
734
printf("ISC_event_blocked: TRUE (eg nothing happened yet)\n");
741
SLONG ISC_event_clear(event_t* event)
743
/**************************************
745
* I S C _ e v e n t _ c l e a r ( U N I X )
747
* not USE_POSIX_THREADS
748
**************************************
750
* Functional description
751
* Clear an event preparatory to waiting on it. The order of
752
* battle for event synchronization is:
755
* 2. Test data structure for event already completed
758
**************************************/
761
if (event->event_semid != -1) {
764
semctl(event->event_semid, event->event_semnum, SETVAL, arg);
767
return (event->event_count + 1);
771
void ISC_event_fini(event_t* event)
773
/**************************************
775
* I S C _ e v e n t _ f i n i ( U N I X )
777
* not USE_POSIX_THREADS
778
**************************************
780
* Functional description
781
* Discard an event object.
783
**************************************/
787
int ISC_event_init(event_t* event, int semid, int semnum)
789
/**************************************
791
* I S C _ e v e n t _ i n i t ( U N I X )
793
* not USE_POSIX_THREADS
794
**************************************
796
* Functional description
797
* Prepare an event object for use.
799
**************************************/
802
event->event_count = 0;
805
event->event_semid = -1;
806
event->event_semnum = 0;
809
event->event_semid = semid;
810
event->event_semnum = semnum;
813
semctl(semid, semnum, SETVAL, arg);
820
int ISC_event_post(event_t* event)
822
/**************************************
824
* I S C _ e v e n t _ p o s t ( U N I X )
826
* not USE_POSIX_THREADS
827
**************************************
829
* Functional description
830
* Post an event to wake somebody else up.
832
**************************************/
835
++event->event_count;
837
while (event->event_semid != -1) {
839
int ret = semctl(event->event_semid, event->event_semnum, SETVAL, arg);
842
if (!SYSCALL_INTERRUPTED(errno)) {
843
gds__log("ISC_event_post: semctl failed with errno = %d", errno);
857
FPTR_VOID_PTR timeout_handler, void *handler_arg)
859
/**************************************
861
* I S C _ e v e n t _ w a i t ( U N I X )
863
* not USE_POSIX_THREADS
864
**************************************
866
* Functional description
867
* Wait on an event. If timeout limit specified, return
868
* anyway after the timeout even if no event has
869
* happened. If returning due to timeout, return
870
* FB_FAILURE else return FB_SUCCESS.
872
**************************************/
873
sigset_t mask, oldmask;
875
/* If we're not blocked, the rest is a gross waste of time */
877
if (!ISC_event_blocked(count, events, values))
880
/* If this is a local semaphore, don't sweat the semaphore non-sense */
882
if ((*events)->event_semid == -1) {
884
sigprocmask(SIG_BLOCK, NULL, &oldmask);
886
sigaddset(&mask, SIGUSR1);
887
sigaddset(&mask, SIGUSR2);
888
sigaddset(&mask, SIGURG);
889
sigprocmask(SIG_BLOCK, &mask, NULL);
891
if (!ISC_event_blocked(count, events, values)) {
893
sigprocmask(SIG_SETMASK, &oldmask, NULL);
896
sigsuspend(&oldmask);
900
/* Only the internal event work is available in the SHRLIB version of pipe server
903
/* Set up for a semaphore operation */
905
int semid = (int) (*events)->event_semid;
907
/* Collect the semaphore numbers in an array */
911
int* semnum = semnums;
912
for (event_t** event = events; i < count; i++)
913
*semnum++ = (*event++)->event_semnum;
915
/* Set up timers if a timeout period was specified. */
917
struct itimerval user_timer;
918
struct sigaction user_handler;
919
if (micro_seconds > 0) {
920
if (!timeout_handler)
921
timeout_handler = alarm_handler;
923
ISC_set_timer(micro_seconds, timeout_handler, handler_arg,
924
(SLONG*)&user_timer, (void**)&user_handler);
927
/* Go into wait loop */
931
if (!ISC_event_blocked(count, events, values)) {
932
if (micro_seconds <= 0)
937
semaphore_wait_isc_sync(count, semid, semnums);
938
if (micro_seconds > 0) {
939
/* semaphore_wait_isc_sync() routine may return true if our timeout
940
handler poked the semaphore. So make sure that the event
941
actually happened. If it didn't, indicate failure. */
943
if (ISC_event_blocked(count, events, values))
951
/* Cancel the handler. We only get here if a timeout was specified. */
953
ISC_reset_timer(timeout_handler, handler_arg, (SLONG*)&user_timer, (void**)&user_handler);
963
int ISC_event_blocked(USHORT count, event_t** events, SLONG * values)
965
/**************************************
967
* I S C _ e v e n t _ b l o c k e d ( V M S )
969
**************************************
971
* Functional description
972
* If a wait would block, return TRUE.
974
**************************************/
976
for (; count; --count, events++, values++)
977
if ((*events)->event_count >= *values)
984
SLONG ISC_event_clear(event_t* event)
986
/**************************************
988
* I S C _ e v e n t _ c l e a r ( V M S )
990
**************************************
992
* Functional description
993
* Clear an event preparatory to waiting on it. The order of
994
* battle for event synchronization is:
997
* 2. Test data structure for event already completed
1000
**************************************/
1002
return event->event_count + 1;
1006
int ISC_event_init(event_t* event, int semid, int semnum)
1008
/**************************************
1010
* I S C _ e v e n t _ i n i t ( V M S )
1012
**************************************
1014
* Functional description
1015
* Prepare an event object for use.
1017
**************************************/
1020
event->event_count = 0;
1021
event->event_pid = getpid();
1027
int ISC_event_post(event_t* event)
1029
/**************************************
1031
* I S C _ e v e n t _ p o s t ( V M S )
1033
**************************************
1035
* Functional description
1036
* Post an event to wake somebody else up.
1038
**************************************/
1039
++event->event_count;
1040
ISC_wake(event->event_pid);
1050
SLONG micro_seconds,
1051
FPTR_VOID_PTR timeout_handler, void *handler_arg)
1053
/**************************************
1055
* I S C _ e v e n t _ w a i t ( V M S )
1057
**************************************
1059
* Functional description
1062
**************************************/
1063
if (!ISC_event_blocked(count, events, values))
1067
wait.wait_count = count;
1068
wait.wait_events = events;
1069
wait.wait_values = values;
1070
gds__thread_wait(event_test, &wait);
1080
int ISC_event_blocked(USHORT count, event_t** events, SLONG * values)
1082
/**************************************
1084
* I S C _ e v e n t _ b l o c k e d ( W I N _ N T )
1086
**************************************
1088
* Functional description
1089
* If a wait would block, return TRUE.
1091
**************************************/
1093
for (; count > 0; --count, ++events, ++values)
1095
const event_t* pEvent = *events;
1096
if (pEvent->event_shared) {
1097
pEvent = pEvent->event_shared;
1099
if (pEvent->event_count >= *values) {
1107
SLONG ISC_event_clear(event_t* event)
1109
/**************************************
1111
* I S C _ e v e n t _ c l e a r ( W I N _ N T )
1113
**************************************
1115
* Functional description
1116
* Clear an event preparatory to waiting on it. The order of
1117
* battle for event synchronization is:
1120
* 2. Test data structure for event already completed
1123
**************************************/
1125
ResetEvent((HANDLE) event->event_handle);
1127
const event_t* pEvent = event;
1128
if (pEvent->event_shared) {
1129
pEvent = pEvent->event_shared;
1131
return pEvent->event_count + 1;
1135
void ISC_event_fini(event_t* event)
1137
/**************************************
1139
* I S C _ e v e n t _ f i n i ( W I N _ N T )
1141
**************************************
1143
* Functional description
1144
* Discard an event object.
1146
**************************************/
1148
CloseHandle((HANDLE) event->event_handle);
1152
int ISC_event_init(event_t* event, int type, int semnum)
1154
/**************************************
1156
* I S C _ e v e n t _ i n i t ( W I N _ N T )
1158
**************************************
1160
* Functional description
1161
* Prepare an event object for use.
1163
**************************************/
1165
event->event_pid = process_id = getpid();
1166
event->event_count = 0;
1167
event->event_type = type;
1168
event->event_shared = NULL;
1170
event->event_handle = ISC_make_signal(true, true, process_id, type);
1172
return (event->event_handle) ? TRUE : FALSE;
1176
int ISC_event_init_shared(
1183
/**************************************
1185
* I S C _ e v e n t _ i n i t _ s h a r e d ( W I N _ N T )
1187
**************************************
1189
* Functional description
1190
* Prepare an event object for use.
1192
**************************************/
1193
lcl_event->event_pid = process_id = getpid();
1194
lcl_event->event_count = 0;
1195
lcl_event->event_type = type;
1196
lcl_event->event_shared = shr_event;
1198
TEXT event_name[MAXPATHLEN], type_name[16];
1199
sprintf(type_name, "_event%d", type);
1200
make_object_name(event_name, sizeof(event_name), name, type_name);
1202
(lcl_event->event_handle =
1203
CreateEvent(ISC_get_security_desc(), TRUE, FALSE,
1210
shr_event->event_pid = 0;
1211
shr_event->event_count = 0;
1212
shr_event->event_type = type;
1213
shr_event->event_handle = NULL;
1214
shr_event->event_shared = NULL;
1221
int ISC_event_post(event_t* event)
1223
/**************************************
1225
* I S C _ e v e n t _ p o s t ( W I N _ N T )
1227
**************************************
1229
* Functional description
1230
* Post an event to wake somebody else up.
1232
**************************************/
1234
if (!event->event_shared)
1235
++event->event_count;
1237
++event->event_shared->event_count;
1239
if (event->event_pid != process_id)
1240
ISC_kill(event->event_pid, event->event_type, event->event_handle);
1242
SetEvent((HANDLE) event->event_handle);
1248
int ISC_event_wait(SSHORT count,
1251
SLONG micro_seconds,
1252
FPTR_VOID_PTR timeout_handler,
1255
/**************************************
1257
* I S C _ e v e n t _ w a i t ( W I N _ N T )
1259
**************************************
1261
* Functional description
1264
**************************************/
1265
/* If we're not blocked, the rest is a gross waste of time */
1267
if (!ISC_event_blocked(count, events, values)) {
1271
#pragma FB_COMPILER_MESSAGE("Warning: B.O. with more than 16 handles")
1274
HANDLE* handle_ptr = handles;
1275
event_t** ptr = events;
1276
for (const event_t* const* const end = events + count; ptr < end;) {
1277
*handle_ptr++ = (*ptr++)->event_handle;
1280
/* Go into wait loop */
1282
const DWORD timeout = (micro_seconds > 0) ? micro_seconds / 1000 : INFINITE;
1285
if (!ISC_event_blocked(count, events, values)) {
1289
const DWORD status =
1290
WaitForMultipleObjects((DWORD) count, handles, TRUE, timeout);
1292
if (!((status >= WAIT_OBJECT_0) && (status < WAIT_OBJECT_0 + (DWORD) count)))
1304
int ISC_event_blocked(USHORT count, event_t** events, SLONG * values)
1306
/**************************************
1308
* I S C _ e v e n t _ b l o c k e d ( G E N E R I C )
1310
**************************************
1312
* Functional description
1313
* If a wait would block, return TRUE.
1315
**************************************/
1320
SLONG ISC_event_clear(event_t* event)
1322
/**************************************
1324
* I S C _ e v e n t _ c l e a r ( G E N E R I C )
1326
**************************************
1328
* Functional description
1329
* Clear an event preparatory to waiting on it. The order of
1330
* battle for event synchronization is:
1333
* 2. Test data structure for event already completed
1336
**************************************/
1342
int ISC_event_init(event_t* event, int semid, int semnum)
1344
/**************************************
1346
* I S C _ e v e n t _ i n i t ( G E N E R I C )
1348
**************************************
1350
* Functional description
1351
* Prepare an event object for use. Return FALSE if not
1354
**************************************/
1360
int ISC_event_post(event_t* event)
1362
/**************************************
1364
* I S C _ e v e n t _ p o s t ( G E N E R I C )
1366
**************************************
1368
* Functional description
1369
* Post an event to wake somebody else up.
1371
**************************************/
1377
int ISC_event_wait(SSHORT count,
1380
SLONG micro_seconds,
1381
FPTR_VOID_PTR timeout_handler,
1384
/**************************************
1386
* I S C _ e v e n t _ w a i t ( G E N E R I C )
1388
**************************************
1390
* Functional description
1393
**************************************/
1403
void ISC_exception_post(ULONG sig_num, const TEXT* err_msg)
1405
/**************************************
1407
* I S C _ e x c e p t i o n _ p o s t ( U N I X )
1409
**************************************
1411
* Functional description
1412
* When we got a sync exception, fomulate the error code
1413
* write it to the log file, and abort.
1415
* 08-Mar-2004, Nickolay Samofatov.
1416
* This function is dangerous and requires rewrite using signal-safe operations only.
1417
* Main problem is that we call a lot of signal-unsafe functions from this signal handler,
1418
* examples are gds__alloc, gds__log, etc... sprintf is safe on some BSD platforms,
1419
* but not on Linux. This may result in lock-up during signal handling.
1421
**************************************/
1422
if (!SCH_thread_enter_check())
1425
// If there's no err_msg, we asumed the switch() finds no case or we crash.
1426
// Too much goodwill put on the caller. Weak programming style.
1427
// Therefore, lifted this safety net from the NT version.
1433
TEXT* log_msg = (TEXT *) gds__alloc(strlen(err_msg) + 256);
1439
sprintf(log_msg, "%s Segmentation Fault.\n"
1440
"\t\tThe code attempted to access memory\n"
1441
"\t\twithout privilege to do so.\n"
1442
"\tThis exception will cause the Firebird server\n"
1443
"\tto terminate abnormally.", err_msg);
1446
sprintf(log_msg, "%s Bus Error.\n"
1447
"\t\tThe code caused a system bus error.\n"
1448
"\tThis exception will cause the Firebird server\n"
1449
"\tto terminate abnormally.", err_msg);
1453
sprintf(log_msg, "%s Illegal Instruction.\n"
1454
"\t\tThe code attempted to perfrom an\n"
1455
"\t\tillegal operation."
1456
"\tThis exception will cause the Firebird server\n"
1457
"\tto terminate abnormally.", err_msg);
1461
sprintf(log_msg, "%s Floating Point Error.\n"
1462
"\t\tThe code caused an arithmetic exception\n"
1463
"\t\tor floating point exception."
1464
"\tThis exception will cause the Firebird server\n"
1465
"\tto terminate abnormally.", err_msg);
1468
sprintf(log_msg, "%s Unknown Exception.\n"
1469
"\t\tException number %"ULONGFORMAT"."
1470
"\tThis exception will cause the Firebird server\n"
1471
"\tto terminate abnormally.", err_msg, sig_num);
1485
ULONG ISC_exception_post(ULONG except_code, const TEXT* err_msg)
1487
/**************************************
1489
* I S C _ e x c e p t i o n _ p o s t ( W I N _ N T )
1491
**************************************
1493
* Functional description
1494
* When we got a sync exception, fomulate the error code
1495
* write it to the log file, and abort. Note: We can not
1496
* actually call "abort" since in windows this will cause
1497
* a dialog to appear stating the obvious! Since on NT we
1498
* would not get a core file, there is actually no difference
1499
* between abort() and exit(3).
1501
**************************************/
1503
bool is_critical = true;
1505
if (!SCH_thread_enter_check ())
1510
thread_db* tdbb = JRD_get_thread_data();
1517
TEXT* log_msg = (TEXT*) gds__alloc(strlen(err_msg) + 256);
1521
switch (except_code) {
1522
case EXCEPTION_ACCESS_VIOLATION:
1523
sprintf(log_msg, "%s Access violation.\n"
1524
"\t\tThe code attempted to access a virtual\n"
1525
"\t\taddress without privilege to do so.\n"
1526
"\tThis exception will cause the Firebird server\n"
1527
"\tto terminate abnormally.", err_msg);
1529
case EXCEPTION_DATATYPE_MISALIGNMENT:
1530
sprintf(log_msg, "%s Datatype misalignment.\n"
1531
"\t\tThe attempted to read or write a value\n"
1532
"\t\tthat was not stored on a memory boundary.\n"
1533
"\tThis exception will cause the Firebird server\n"
1534
"\tto terminate abnormally.", err_msg);
1536
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
1537
sprintf(log_msg, "%s Array bounds exceeded.\n"
1538
"\t\tThe code attempted to access an array\n"
1539
"\t\telement that is out of bounds.\n"
1540
"\tThis exception will cause the Firebird server\n"
1541
"\tto terminate abnormally.", err_msg);
1543
case EXCEPTION_FLT_DENORMAL_OPERAND:
1544
sprintf(log_msg, "%s Float denormal operand.\n"
1545
"\t\tOne of the floating-point operands is too\n"
1546
"\t\tsmall to represent as a standard floating-point\n"
1548
"\tThis exception will cause the Firebird server\n"
1549
"\tto terminate abnormally.", err_msg);
1551
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
1552
sprintf(log_msg, "%s Floating-point divide by zero.\n"
1553
"\t\tThe code attempted to divide a floating-point\n"
1554
"\t\tvalue by a floating-point divisor of zero.\n"
1555
"\tThis exception will cause the Firebird server\n"
1556
"\tto terminate abnormally.", err_msg);
1558
case EXCEPTION_FLT_INEXACT_RESULT:
1559
sprintf(log_msg, "%s Floating-point inexact result.\n"
1560
"\t\tThe result of a floating-point operation cannot\n"
1561
"\t\tbe represented exactly as a decimal fraction.\n"
1562
"\tThis exception will cause the Firebird server\n"
1563
"\tto terminate abnormally.", err_msg);
1565
case EXCEPTION_FLT_INVALID_OPERATION:
1566
sprintf(log_msg, "%s Floating-point invalid operand.\n"
1567
"\t\tAn indeterminant error occurred during a\n"
1568
"\t\tfloating-point operation.\n"
1569
"\tThis exception will cause the Firebird server\n"
1570
"\tto terminate abnormally.", err_msg);
1572
case EXCEPTION_FLT_OVERFLOW:
1573
sprintf(log_msg, "%s Floating-point overflow.\n"
1574
"\t\tThe exponent of a floating-point operation\n"
1575
"\t\tis greater than the magnitude allowed.\n"
1576
"\tThis exception will cause the Firebird server\n"
1577
"\tto terminate abnormally.", err_msg);
1579
case EXCEPTION_FLT_STACK_CHECK:
1580
sprintf(log_msg, "%s Floating-point stack check.\n"
1581
"\t\tThe stack overflowed or underflowed as the\n"
1582
"result of a floating-point operation.\n"
1583
"\tThis exception will cause the Firebird server\n"
1584
"\tto terminate abnormally.", err_msg);
1586
case EXCEPTION_FLT_UNDERFLOW:
1587
sprintf(log_msg, "%s Floating-point underflow.\n"
1588
"\t\tThe exponent of a floating-point operation\n"
1589
"\t\tis less than the magnitude allowed.\n"
1590
"\tThis exception will cause the Firebird server\n"
1591
"\tto terminate abnormally.", err_msg);
1593
case EXCEPTION_INT_DIVIDE_BY_ZERO:
1594
sprintf(log_msg, "%s Integer divide by zero.\n"
1595
"\t\tThe code attempted to divide an integer value\n"
1596
"\t\tby an integer divisor of zero.\n"
1597
"\tThis exception will cause the Firebird server\n"
1598
"\tto terminate abnormally.", err_msg);
1600
case EXCEPTION_INT_OVERFLOW:
1601
sprintf(log_msg, "%s Interger overflow.\n"
1602
"\t\tThe result of an integer operation caused the\n"
1603
"\t\tmost significant bit of the result to carry.\n"
1604
"\tThis exception will cause the Firebird server\n"
1605
"\tto terminate abnormally.", err_msg);
1607
case EXCEPTION_STACK_OVERFLOW:
1608
ERR_post(isc_exception_stack_overflow, isc_arg_end);
1609
/* This will never be called, but to be safe it's here */
1610
result = (ULONG) EXCEPTION_CONTINUE_EXECUTION;
1611
is_critical = false;
1614
case EXCEPTION_BREAKPOINT:
1615
case EXCEPTION_SINGLE_STEP:
1616
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
1617
case EXCEPTION_INVALID_DISPOSITION:
1618
case EXCEPTION_PRIV_INSTRUCTION:
1619
case EXCEPTION_IN_PAGE_ERROR:
1620
case EXCEPTION_ILLEGAL_INSTRUCTION:
1621
case EXCEPTION_GUARD_PAGE:
1622
/* Pass these exception on to someone else,
1623
probably the OS or the debugger, since there
1624
isn't a dam thing we can do with them */
1625
result = EXCEPTION_CONTINUE_SEARCH;
1626
is_critical = false;
1628
case 0xE06D7363: /* E == Exception. 0x6D7363 == "msc". Intel and Borland use the same code to be compatible */
1629
/* If we've catched our own software exception,
1630
continue rewinding the stack to properly handle it
1631
and deliver an error information to the client side */
1632
result = EXCEPTION_CONTINUE_SEARCH;
1633
is_critical = false;
1636
sprintf (log_msg, "%s An exception occurred that does\n"
1637
"\t\tnot have a description. Exception number %"XLONGFORMAT".\n"
1638
"\tThis exception will cause the Firebird server\n"
1639
"\tto terminate abnormally.", err_msg, except_code);
1652
if (Config::getBugcheckAbort()) {
1653
// Pass exception to outer handler in case debugger is present to collect memory dump
1654
return EXCEPTION_CONTINUE_SEARCH;
1657
// Silently exit so guardian or service manager can restart the server.
1658
// If exception is getting out of the application Windows displays a message
1659
// asking if you want to send report to Microsoft or attach debugger,
1660
// application is not terminated until you press some button on resulting window.
1661
// This happens even if you run application as non-interactive service on
1662
// "server" OS like Windows Server 2003.
1673
#endif /* SUPERSERVER */
1677
void *ISC_make_signal(
1683
/**************************************
1685
* I S C _ m a k e _ s i g n a l ( W I N _ N T )
1687
**************************************
1689
* Functional description
1690
* Create or open a Windows/NT event.
1691
* Use the signal number and process id
1692
* in naming the object.
1694
**************************************/
1696
const BOOLEAN man_rst = manual_reset ? TRUE : FALSE;
1699
return CreateEvent(NULL, man_rst, FALSE, NULL);
1701
TEXT event_name[64];
1702
sprintf(event_name, "_firebird_process%u_signal%d", process_idL, signal_number);
1706
hEvent = CreateEvent(ISC_get_security_desc(), man_rst, FALSE, event_name);
1709
hEvent = OpenEvent(EVENT_ALL_ACCESS, TRUE, event_name);
1717
#define ISC_MAP_FILE_DEFINED
1718
UCHAR* ISC_map_file(ISC_STATUS* status_vector,
1719
const TEXT* filename,
1720
FPTR_INIT_GLOBAL_REGION init_routine,
1721
void* init_arg, SLONG length, SH_MEM shmem_data)
1723
/**************************************
1725
* I S C _ m a p _ f i l e ( V M S )
1727
**************************************
1729
* Functional description
1730
* Try to map a given file. If we are the first (i.e. only)
1731
* process to map the file, call a given initialization
1732
* routine (if given) or punt (leaving the file unmapped).
1734
**************************************/
1739
/* Must be able to handle case where zero length passed in. */
1741
fprintf(stderr, "Unimplemented feature in ISC_map_file.\n");
1745
TEXT expanded_filename[MAXPATHLEN], temp[MAXPATHLEN], hostname[64];
1746
gds__prefix(temp, filename);
1747
sprintf(expanded_filename, temp,
1748
ISC_get_host(hostname, sizeof(hostname)));
1750
/* Find section name */
1752
const TEXT* q = expanded_filename;
1755
for (p = expanded_filename; *p; p++)
1756
if (*p == ':' || *p == ']')
1760
for (p = section; *q && *q != '.';)
1765
/* Setup to open the file */
1769
fab.fab$l_fna = expanded_filename;
1770
fab.fab$b_fns = strlen(expanded_filename);
1771
fab.fab$l_fop = FAB$M_UFO;
1772
fab.fab$l_alq = length / 512;
1773
fab.fab$b_fac = FAB$M_UPD | FAB$M_PUT;
1774
fab.fab$b_shr = FAB$M_SHRGET | FAB$M_SHRPUT | FAB$M_UPI;
1775
fab.fab$b_rfm = FAB$C_UDF;
1777
/* Setup to create or map the file */
1780
inadr[0] = inadr[1] = 0;
1781
struct dsc$descriptor_s desc;
1782
ISC_make_desc(section, &desc, 0);
1783
const SLONG flags = SEC$M_GBL | SEC$M_EXPREG | SEC$M_WRT |
1784
((shmem_data->sh_mem_system_flag) ? 0 : SEC$M_SYSGBL);
1791
/* If we're a server, start by opening file.
1792
If we can't open it, create it. */
1794
status = sys$open(&fab);
1796
if (!(status & 1)) {
1797
fab.fab$l_xab = &xab;
1798
xab = cc$rms_xabpro;
1800
(XAB$M_NOEXE << XAB$V_SYS) | (XAB$M_NOEXE << XAB$V_OWN) |
1801
(XAB$M_NOEXE << XAB$V_GRP) | (XAB$M_NODEL << XAB$V_GRP) |
1802
(XAB$M_NOEXE << XAB$V_WLD) | (XAB$M_NODEL << XAB$V_WLD);
1804
status = sys$create(&fab);
1806
if (!(status & 1)) {
1807
error(status_vector, "sys$create", status);
1812
/* Create and map section */
1814
status = sys$crmpsc(inadr, retadr, 0, /* acmode */
1819
fab.fab$l_stv, /* chan */
1820
length / 512, 0, /* vbm */
1824
if (!(status & 1)) {
1825
if (status == SS$_CREATED)
1826
sys$deltva(retadr, 0, 0);
1827
sys$dassgn(fab.fab$l_stv);
1828
error(status_vector, "sys$crmpsc", status);
1833
/* We're not a server, just map the global section */
1835
status = sys$mgblsc(inadr, retadr, 0, /* acmode */
1841
if (!(status & 1)) {
1842
error(status_vector, "sys$mgblsc", status);
1847
shmem_data->sh_mem_address = retadr[0];
1848
shmem_data->sh_mem_length_mapped = length;
1849
shmem_data->sh_mem_retadr[0] = retadr[0];
1850
shmem_data->sh_mem_retadr[0] = retadr[1];
1851
shmem_data->sh_mem_channel = fab.fab$l_stv;
1852
strcpy(shmem_data->sh_mem_filename, expanded_filename);
1854
(*init_routine) (init_arg, shmem_data, status == SS$_CREATED);
1856
return (UCHAR *) retadr[0];
1863
#define ISC_MAP_FILE_DEFINED
1864
UCHAR* ISC_map_file(ISC_STATUS* status_vector,
1865
const TEXT* filename,
1866
FPTR_INIT_GLOBAL_REGION init_routine,
1867
void* init_arg, SLONG length, SH_MEM shmem_data)
1869
/**************************************
1871
* I S C _ m a p _ f i l e ( U N I X - m m a p )
1873
**************************************
1875
* Functional description
1876
* Try to map a given file. If we are the first (i.e. only)
1877
* process to map the file, call a given initialization
1878
* routine (if given) or punt (leaving the file unmapped).
1880
**************************************/
1881
TEXT expanded_filename[MAXPATHLEN], hostname[64];
1882
sprintf(expanded_filename, filename,
1883
ISC_get_host(hostname, sizeof(hostname)));
1885
/* make the complete filename for the init file this file is to be used as a
1886
master lock to eliminate possible race conditions with just a single file
1887
locking. The race condition is caused as the conversion of a EXCLUSIVE
1888
lock to a SHARED lock is not atomic*/
1890
TEXT tmp[MAXPATHLEN];
1891
gds__prefix_lock(tmp, INIT_FILE);
1892
TEXT init_filename[MAXPATHLEN]; /* to hold the complete filename
1893
of the init file. */
1894
sprintf(init_filename, tmp, hostname); /* already have the hostname! */
1896
const int oldmask = umask(0);
1897
bool trunc_flag = true;
1903
/* Produce shared memory key for file */
1906
if (!(key = find_key(status_vector, expanded_filename))) {
1911
/* open the init lock file */
1912
int fd_init; /* filedecr. for the init file */
1913
fd_init = open(init_filename, O_RDWR | O_CREAT, 0666);
1914
if (fd_init == -1) {
1915
error(status_vector, "open", errno);
1921
/* get an exclusive lock on the INIT file with a block */
1922
lock.l_type = F_WRLCK;
1926
if (fcntl(fd_init, F_SETLKW, &lock) == -1) {
1927
error(status_vector, "fcntl", errno);
1932
/* get an flock exclusive on the INIT file with blocking */
1933
if (flock(fd_init, LOCK_EX)) {
1934
/* we failed to get an exclusive lock return back */
1935
error(status_vector, "flock", errno);
1940
/* open the file to be inited */
1941
int fd = open(expanded_filename, O_RDWR | O_CREAT, 0666);
1945
error(status_vector, "open", errno);
1947
/* unlock init file */
1948
flock(fd_init, LOCK_UN);
1950
lock.l_type = F_UNLCK;
1954
fcntl(fd_init, F_SETLK, &lock);
1961
/* Get and use the existing length of the shared segment */
1963
struct stat file_stat;
1964
if (fstat(fd, &file_stat) == -1) {
1965
error(status_vector, "fstat", errno);
1968
/* unlock init file */
1969
flock(fd_init, LOCK_UN);
1971
lock.l_type = F_UNLCK;
1975
fcntl(fd_init, F_SETLK, &lock);
1977
close(fd_init); /* while we are at it close the init file also */
1980
length = file_stat.st_size;
1985
(UCHAR *) mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1987
if ((U_IPTR) address == (U_IPTR) -1) {
1988
error(status_vector, "mmap", errno);
1991
/* unlock init file */
1992
flock(fd_init, LOCK_UN);
1994
lock.l_type = F_UNLCK;
1998
fcntl(fd_init, F_SETLK, &lock);
2005
/* Get semaphore for mutex */
2007
shmem_data->sh_mem_address = address;
2008
shmem_data->sh_mem_length_mapped = length;
2011
shmem_data->sh_mem_handle = fd;
2013
/* Try to get an exclusive lock on the lock file. This will
2014
fail if somebody else has the exclusive lock */
2017
if (!flock(fd, LOCK_EX | LOCK_NB))
2019
if (!init_routine) {
2020
/* unlock both files */
2022
flock(fd_init, LOCK_UN);
2024
lock.l_type = F_WRLCK;
2028
if (fcntl(fd, F_SETLK, &lock) != -1) {
2029
if (!init_routine) {
2030
/* unlock the file and the init file to release the other process */
2031
lock.l_type = F_UNLCK;
2035
fcntl(fd, F_SETLK, &lock);
2037
lock.l_type = F_UNLCK;
2041
fcntl(fd_init, F_SETLK, &lock);
2043
munmap((char *) address, length);
2046
*status_vector++ = isc_arg_gds;
2047
*status_vector++ = isc_unavailable;
2048
*status_vector++ = isc_arg_end;
2052
// Create semaphores here
2053
#if !(defined SOLARIS_MT || defined USE_POSIX_THREADS)
2055
if (shmem_data->sh_mem_semaphores &&
2057
create_semaphores(status_vector, key,
2058
shmem_data->sh_mem_semaphores)) < 0)
2061
/* unlock both files */
2063
flock(fd_init, LOCK_UN);
2065
/* unlock the file and the init file to release the other process */
2066
lock.l_type = F_UNLCK;
2070
fcntl(fd, F_SETLK, &lock);
2072
lock.l_type = F_UNLCK;
2076
fcntl(fd_init, F_SETLK, &lock);
2078
munmap((char *) address, length);
2083
shmem_data->sh_mem_mutex_arg = semid;
2085
shmem_data->sh_mem_mutex_arg = 0;
2089
ftruncate(fd, length);
2090
(*init_routine) (init_arg, shmem_data, true);
2092
if (flock(fd, LOCK_SH)) {
2093
error(status_vector, "flock", errno);
2095
flock(fd_init, LOCK_UN);
2097
lock.l_type = F_RDLCK;
2101
if (fcntl(fd, F_SETLK, &lock) == -1)
2103
error(status_vector, "fcntl", errno);
2104
/* unlock the file */
2105
lock.l_type = F_UNLCK;
2109
fcntl(fd, F_SETLK, &lock);
2111
/* unlock the init file to release the other process */
2112
lock.l_type = F_UNLCK;
2116
fcntl(fd_init, F_SETLK, &lock);
2118
munmap((char *) address, length);
2127
if (flock(fd, LOCK_SH)) {
2128
error(status_vector, "flock", errno);
2130
flock(fd_init, LOCK_UN);
2132
lock.l_type = F_RDLCK;
2136
if (fcntl(fd, F_SETLK, &lock) == -1) {
2137
error(status_vector, "fcntl", errno);
2138
/* unlock the file */
2139
lock.l_type = F_UNLCK;
2143
fcntl(fd, F_SETLK, &lock);
2145
/* unlock the init file to release the other process */
2146
lock.l_type = F_UNLCK;
2150
fcntl(fd_init, F_SETLK, &lock);
2152
munmap((char *) address, length);
2157
// Open semaphores here
2158
#if !(defined SOLARIS_MT || defined USE_POSIX_THREADS)
2160
if (shmem_data->sh_mem_semaphores &&
2162
open_semaphores(status_vector, key,
2163
shmem_data->sh_mem_semaphores)) < 0)
2166
/* unlock both files */
2168
flock(fd_init, LOCK_UN);
2170
/* unlock the file and the init file to release the other process */
2171
lock.l_type = F_UNLCK;
2175
fcntl(fd, F_SETLK, &lock);
2177
lock.l_type = F_UNLCK;
2181
fcntl(fd_init, F_SETLK, &lock);
2183
munmap((char *) address, length);
2188
shmem_data->sh_mem_mutex_arg = semid;
2190
shmem_data->sh_mem_mutex_arg = 0;
2193
(*init_routine) (init_arg, shmem_data, false);
2197
/* unlock the init file to release the other process */
2198
flock(fd_init, LOCK_UN);
2200
/* unlock the init file to release the other process */
2201
lock.l_type = F_UNLCK;
2205
fcntl(fd_init, F_SETLK, &lock);
2207
/* close the init file_decriptor */
2217
#define ISC_MAP_FILE_DEFINED
2218
UCHAR* ISC_map_file(ISC_STATUS* status_vector,
2219
const TEXT* filename,
2220
FPTR_INIT_GLOBAL_REGION init_routine,
2221
void* init_arg, SLONG length, SH_MEM shmem_data)
2223
/**************************************
2225
* I S C _ m a p _ f i l e ( U N I X - s h m a t )
2227
**************************************
2229
* Functional description
2230
* Try to map a given file. If we are the first (i.e. only)
2231
* process to map the file, call a given initialization
2232
* routine (if given) or punt (leaving the file unmapped).
2234
**************************************/
2236
TEXT expanded_filename[512];
2238
strcpy(expanded_filename, filename);
2241
sprintf(expanded_filename, filename,
2242
ISC_get_host(hostname, sizeof(hostname)));
2244
const int oldmask = umask(0);
2245
bool init_flag = false;
2249
/* Produce shared memory key for file */
2251
const SLONG key = find_key(status_vector, expanded_filename);
2257
/* Write shared memory key into expanded_filename file */
2259
FILE* fp = fopen(expanded_filename, "w");
2263
error(status_vector, "fopen", errno);
2267
fprintf(fp, "%ld", key);
2269
/* Get an exclusive lock on the file until the initialization process
2270
is complete. That way potential race conditions are avoided. */
2273
if (lockf(fileno(fp), F_LOCK, 0)) {
2274
error(status_vector, "lockf", errno);
2276
if (flock(fileno(fp), LOCK_EX)) {
2277
error(status_vector, "flock", errno);
2283
/* Create the shared memory region if it doesn't already exist. */
2285
struct shmid_ds buf;
2287
if ((shmid = shmget(key, length, IPC_CREAT | PRIV)) == -1)
2289
if (errno == EINVAL) {
2290
/* There are two cases when shmget() returns EINVAL error:
2292
- "length" is less than the system-imposed minimum or
2293
greater than the system-imposed maximum.
2295
- A shared memory identifier exists for "key" but the
2296
size of the segment associated with it is less
2297
than "length" and "length" is not equal to zero.
2299
Let's find out what the problem is by getting the
2300
system-imposed limits.
2304
struct pst_ipcinfo pst;
2306
if (pstat_getipc(&pst, sizeof(struct pst_ipcinfo), 1, 0) == -1) {
2307
error(status_vector, "pstat_getipc", errno);
2312
if ((length < pst.psi_shmmin) || (length > pst.psi_shmmax)) {
2313
/* If pstat_getipc did not return an error "errno"
2314
is still EINVAL, exactly what we want.
2316
error(status_vector, "shmget", errno);
2322
/* If we are here then the shared memory segment already
2323
exists and the "length" we specified in shmget() is
2324
bigger than the size of the existing segment.
2326
Because the segment has to exist at this point the
2327
following shmget() does not have IPC_CREAT flag set.
2329
We need to get shmid to delete the segment. Because we
2330
do not know the size of the existing segment the easiest
2331
way to get shmid is to attach to the segment with zero
2334
if ((shmid = shmget(key, 0, PRIV)) == -1) {
2335
error(status_vector, "shmget", errno);
2340
if (shmctl(shmid, IPC_RMID, &buf) == -1) {
2341
error(status_vector, "shmctl/IPC_RMID", errno);
2346
/* We have just deleted shared memory segment and current
2347
code fragment is an atomic operation (we are holding an
2348
exclusive lock on the "isc_lock1.<machine>" file), so
2349
we use IPC_EXCL flag to get an error if by some miracle
2350
the sagment with the same key is already exists
2352
if ((shmid = shmget(key, length, IPC_CREAT | IPC_EXCL | PRIV)) ==
2355
error(status_vector, "shmget", errno);
2360
else /* if errno != EINVAL) */
2361
#endif /* SUPERSERVER */
2363
error(status_vector, "shmget", errno);
2369
/* If we are here there are two possibilities:
2371
1. we mapped the shared memory segment of the "length" size;
2372
2. we mapped the segment of the size less than "length" (but
2373
not zero length and bigger than system-imposed minimum);
2375
We want shared memory segment exactly of the "length" size.
2376
Let's find out what the size of the segment is and if it is
2377
bigger than length, we remove it and create new one with the
2379
Also, if "length" is zero (that means we have already mapped
2380
the existing segment with the zero size) remap the segment
2381
with the existing size
2383
if (shmctl(shmid, IPC_STAT, &buf) == -1) {
2384
error(status_vector, "shmctl/IPC_STAT", errno);
2389
fb_assert(length <= buf.shm_segsz);
2390
if (length < buf.shm_segsz)
2392
if (shmctl(shmid, IPC_RMID, &buf) == -1) {
2393
error(status_vector, "shmctl/IPC_RMID", errno);
2398
if ((shmid = shmget(key, length, IPC_CREAT | IPC_EXCL | PRIV)) ==
2401
error(status_vector, "shmget", errno);
2407
length = buf.shm_segsz;
2408
if ((shmid = shmget(key, length, PRIV)) == -1) {
2409
error(status_vector, "shmget", errno);
2414
#else /* !SUPERSERVER */
2417
/* Use the existing length. This should not happen for the
2418
very first attachment to the shared memory. */
2420
if (shmctl(shmid, IPC_STAT, &buf) == -1) {
2421
error(status_vector, "shmctl/IPC_STAT", errno);
2425
length = buf.shm_segsz;
2427
/* Now remap with the new-found length */
2429
if ((shmid = shmget(key, length, PRIV)) == -1) {
2430
error(status_vector, "shmget", errno);
2435
#endif /* SUPERSERVER */
2440
if (!next_shared_memory)
2441
next_shared_memory = (UCHAR *) sbrk(0) + SHMEM_DELTA;
2442
address = (UCHAR *) shmat(shmid, next_shared_memory, SHM_RND);
2443
if ((U_IPTR) address != -1)
2445
next_shared_memory = address + length;
2447
next_shared_memory = address + length + SHMLBA;
2450
address = (UCHAR *) shmat(shmid, NULL, 0);
2453
if ((U_IPTR) address == -1) {
2454
error(status_vector, "shmat", errno);
2459
if (shmctl(shmid, IPC_STAT, &buf) == -1) {
2460
error(status_vector, "shmctl/IPC_STAT", errno);
2462
next_shared_memory -= length;
2467
/* Get semaphore for mutex */
2470
/* If we're the only one with shared memory mapped, see if
2471
we can initialize it. If we can't, return failure. */
2473
if (buf.shm_nattch == 1) {
2474
if (!init_routine) {
2476
next_shared_memory -= length;
2478
*status_vector++ = isc_arg_gds;
2479
*status_vector++ = isc_unavailable;
2480
*status_vector++ = isc_arg_end;
2483
buf.shm_perm.mode = 0666;
2484
shmctl(shmid, IPC_SET, &buf);
2488
shmem_data->sh_mem_address = address;
2489
shmem_data->sh_mem_length_mapped = length;
2492
shmem_data->sh_mem_handle = shmid;
2494
#ifndef USE_POSIX_THREADS
2496
if (shmem_data->sh_mem_semaphores &&
2499
create_semaphores(status_vector, key,
2500
shmem_data->sh_mem_semaphores) :
2501
open_semaphores(status_vector, key,
2502
shmem_data->sh_mem_semaphores)) ) < 0)
2505
next_shared_memory -= length;
2509
shmem_data->sh_mem_mutex_arg = semid;
2511
shmem_data->sh_mem_mutex_arg = 0;
2515
(*init_routine) (init_arg, shmem_data, init_flag);
2517
/* When the mapped file is closed here, the lock we applied for
2518
synchronization will be released. */
2524
#endif // !HAVE_MMAP
2530
#define ISC_MAP_FILE_DEFINED
2531
UCHAR* ISC_map_file(
2532
ISC_STATUS* status_vector,
2533
const TEXT* filename,
2534
FPTR_INIT_GLOBAL_REGION init_routine,
2539
/**************************************
2541
* I S C _ m a p _ f i l e ( W I N _ N T )
2543
**************************************
2545
* Functional description
2546
* Try to map a given file. If we are the first (i.e. only)
2547
* process to map the file, call a given initialization
2548
* routine (if given) or punt (leaving the file unmapped).
2550
**************************************/
2551
TEXT expanded_filename[MAXPATHLEN], hostname[64];
2552
TEXT map_file[MAXPATHLEN];
2554
HANDLE event_handle = 0;
2555
int retry_count = 0;
2556
bool init_flag = false;
2558
/* retry to attach to mmapped file if the process initializing
2559
* dies during initialization.
2563
if (retry_count++ > 0)
2566
ISC_get_host(hostname, sizeof(hostname));
2567
sprintf(map_file, filename, hostname);
2572
file_handle = CreateFile(map_file,
2573
GENERIC_READ | GENERIC_WRITE,
2574
FILE_SHARE_READ | FILE_SHARE_WRITE,
2577
FILE_ATTRIBUTE_NORMAL,
2579
DWORD err = GetLastError();
2580
if (file_handle == INVALID_HANDLE_VALUE)
2582
if (err == ERROR_SHARING_VIOLATION)
2585
error(status_vector, "CreateFile", err);
2589
/* Check if file already exists */
2591
const bool file_exists = (err == ERROR_ALREADY_EXISTS);
2593
/* Create an event that can be used to determine if someone has already
2594
initialized shared memory. */
2596
make_object_name(expanded_filename, sizeof(expanded_filename), filename, "_event");
2599
if (!ISC_is_WinNT())
2601
CreateMutex(ISC_get_security_desc(), TRUE, expanded_filename);
2604
CreateEvent(ISC_get_security_desc(), TRUE, FALSE,
2606
if (!event_handle) {
2607
if (!ISC_is_WinNT())
2608
error(status_vector, "CreateMutex", GetLastError());
2610
error(status_vector, "CreateEvent", GetLastError());
2611
CloseHandle(file_handle);
2615
init_flag = (GetLastError() == ERROR_ALREADY_EXISTS) ? false: true;
2617
if (init_flag && !init_routine) {
2618
CloseHandle(event_handle);
2619
CloseHandle(file_handle);
2620
*status_vector++ = isc_arg_gds;
2621
*status_vector++ = isc_unavailable;
2622
*status_vector++ = isc_arg_end;
2628
/* Get and use the existing length of the shared segment */
2630
if ((length = GetFileSize(file_handle, NULL)) == -1) {
2631
error(status_vector, "GetFileSize", GetLastError());
2632
CloseHandle(event_handle);
2633
CloseHandle(file_handle);
2638
/* All but the initializer will wait until the event is set. That
2639
* is done after initialization is complete.
2640
* Close the file and wait for the event to be set or time out.
2641
* The file may be truncated.
2644
CloseHandle(file_handle);
2647
/* Wait for 10 seconds. Then retry */
2650
if (!ISC_is_WinNT()) {
2651
ret_event = WaitForSingleObject(event_handle, 10000);
2652
ReleaseMutex(event_handle);
2655
ret_event = WaitForSingleObject(event_handle, 10000);
2657
/* If we timed out, just retry. It is possible that the
2658
* process doing the initialization died before setting the
2662
if (ret_event == WAIT_TIMEOUT) {
2663
CloseHandle(event_handle);
2664
if (retry_count > 10) {
2665
error(status_vector, "WaitForSingleObject", 0);
2673
if (init_flag && file_exists)
2674
fdw_create = TRUNCATE_EXISTING;
2676
fdw_create = OPEN_ALWAYS;
2678
file_handle = CreateFile(map_file,
2679
GENERIC_READ | GENERIC_WRITE,
2680
FILE_SHARE_READ | FILE_SHARE_WRITE,
2684
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
2686
FILE_ATTRIBUTE_NORMAL,
2689
if (file_handle == INVALID_HANDLE_VALUE)
2691
const DWORD err = GetLastError();
2693
if ((err == ERROR_SHARING_VIOLATION) ||
2694
((err == ERROR_FILE_NOT_FOUND || err == ERROR_USER_MAPPED_FILE) && fdw_create == TRUNCATE_EXISTING))
2697
CloseHandle(event_handle);
2702
CloseHandle(event_handle);
2703
error(status_vector, "CreateFile", err);
2707
/* Create a file mapping object that will be used to make remapping possible.
2708
The current length of real mapped file and its name are saved in it. */
2710
make_object_name(expanded_filename, sizeof(expanded_filename), filename, "_mapping");
2712
HANDLE header_obj = CreateFileMapping ((HANDLE) -1,
2713
ISC_get_security_desc(),
2718
if (header_obj == NULL) {
2719
error(status_vector, "CreateFileMapping", GetLastError());
2720
CloseHandle(event_handle);
2721
CloseHandle(file_handle);
2725
SLONG* header_address =
2726
(SLONG*) MapViewOfFile(header_obj, FILE_MAP_WRITE, 0, 0, 0);
2728
if (header_address == NULL) {
2729
error(status_vector, "CreateFileMapping", GetLastError());
2730
CloseHandle(header_obj);
2731
CloseHandle(event_handle);
2732
CloseHandle(file_handle);
2736
/* Set or get the true length of the file depending on whether or not
2737
we are the first user. */
2740
header_address[0] = length;
2741
header_address[1] = 0;
2744
length = header_address[0];
2746
/* Create the real file mapping object. */
2749
for (p = expanded_filename; *p; p++);
2750
sprintf(p, "%"SLONGFORMAT, header_address[1]);
2753
CreateFileMapping(file_handle,
2754
ISC_get_security_desc(),
2759
if (file_obj == NULL) {
2760
error(status_vector, "CreateFileMapping", GetLastError());
2761
UnmapViewOfFile(header_address);
2762
CloseHandle(header_obj);
2763
CloseHandle(event_handle);
2764
CloseHandle(file_handle);
2769
(UCHAR*) MapViewOfFile(file_obj, FILE_MAP_WRITE, 0, 0, 0);
2771
if (address == NULL) {
2772
error(status_vector, "CreateFileMapping", GetLastError());
2773
CloseHandle(file_obj);
2774
UnmapViewOfFile(header_address);
2775
CloseHandle(header_obj);
2776
CloseHandle(event_handle);
2777
CloseHandle(file_handle);
2783
shmem_data->sh_mem_address = address;
2784
shmem_data->sh_mem_length_mapped = length;
2785
shmem_data->sh_mem_handle = file_handle;
2786
shmem_data->sh_mem_object = file_obj;
2787
shmem_data->sh_mem_interest = event_handle;
2788
shmem_data->sh_mem_hdr_object = header_obj;
2789
shmem_data->sh_mem_hdr_address = header_address;
2790
strcpy(shmem_data->sh_mem_name, expanded_filename);
2793
(*init_routine) (init_arg, shmem_data, init_flag);
2796
FlushViewOfFile(address, 0);
2797
if (!ISC_is_WinNT())
2798
ReleaseMutex(event_handle);
2800
SetEvent(event_handle);
2802
(shmem_data->sh_mem_handle, length, NULL,
2803
FILE_BEGIN) == 0xFFFFFFFF
2804
|| !SetEndOfFile(shmem_data->sh_mem_handle)
2805
|| !FlushViewOfFile(shmem_data->sh_mem_address, 0))
2807
error(status_vector, "SetFilePointer", GetLastError());
2818
#ifndef ISC_MAP_FILE_DEFINED
2819
UCHAR* ISC_map_file(ISC_STATUS* status_vector,
2820
const TEXT* filename,
2821
FPTR_INIT_GLOBAL_REGION init_routine,
2822
void* init_arg, SLONG length, SH_MEM shmem_data)
2824
/**************************************
2826
* I S C _ m a p _ f i l e ( G E N E R I C )
2828
**************************************
2830
* Functional description
2831
* Try to map a given file. If we are the first (i.e. only)
2832
* process to map the file, call a given initialization
2833
* routine (if given) or punt (leaving the file unmapped).
2835
**************************************/
2837
*status_vector++ = isc_arg_gds;
2838
*status_vector++ = isc_unavailable;
2839
*status_vector++ = isc_arg_end;
2848
#define ISC_MAP_OBJECT_DEFINED
2849
UCHAR *ISC_map_object(ISC_STATUS * status_vector,
2851
SLONG object_offset, SLONG object_length)
2853
/**************************************
2855
* I S C _ m a p _ o b j e c t
2857
**************************************
2859
* Functional description
2860
* Try to map an object given a file mapping.
2862
**************************************/
2863
/* Get system page size as this is the unit of mapping. */
2866
const SLONG page_size = sysconf(_SC_PAGESIZE);
2867
if (page_size == -1) {
2868
error(status_vector, "sysconf", errno);
2872
const SLONG page_size = (int) getpagesize();
2873
if (page_size == -1) {
2874
error(status_vector, "getpagesize", errno);
2879
/* Compute the start and end page-aligned offsets which
2880
contain the object being mapped. */
2882
const SLONG start = (object_offset / page_size) * page_size;
2883
const SLONG end = (((object_offset + object_length) / page_size) + 1) * page_size;
2884
const SLONG length = end - start;
2885
int fd = shmem_data->sh_mem_handle;
2888
(UCHAR *) mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
2891
if ((U_IPTR) address == (U_IPTR) -1) {
2892
error(status_vector, "mmap", errno);
2896
/* Return the virtual address of the mapped object. */
2898
return (address + (object_offset - start));
2904
#define ISC_UNMAP_OBJECT_DEFINED
2905
void ISC_unmap_object(ISC_STATUS * status_vector,
2907
UCHAR ** object_pointer, SLONG object_length)
2909
/**************************************
2911
* I S C _ u n m a p _ o b j e c t
2913
**************************************
2915
* Functional description
2916
* Try to unmap an object given a file mapping.
2917
* Zero the object pointer after a successful unmap.
2919
**************************************/
2920
/* Get system page size as this is the unit of mapping. */
2923
const SLONG ps = sysconf(_SC_PAGESIZE);
2925
error(status_vector, "sysconf", errno);
2929
const SLONG ps = (int) getpagesize();
2931
error(status_vector, "getpagesize", errno);
2935
const size_t page_size = (ULONG) ps;
2937
/* Compute the start and end page-aligned addresses which
2938
contain the mapped object. */
2940
UCHAR* start = (UCHAR *) ((U_IPTR) * object_pointer & ~(page_size - 1));
2943
*) ((U_IPTR) ((*object_pointer + object_length) +
2944
(page_size - 1)) & ~(page_size - 1));
2945
const size_t length = end - start;
2947
if (munmap((char *) start, length) == -1) {
2948
error(status_vector, "munmap", errno);
2952
*object_pointer = 0;
2960
int ISC_mutex_init(MTX mutex, SLONG event_flag)
2962
/**************************************
2964
* I S C _ m u t e x _ i n i t ( V M S )
2966
**************************************
2968
* Functional description
2969
* Initialize a mutex.
2971
**************************************/
2973
mutex->mtx_use_count = 0;
2974
mutex->mtx_event_count[0] = 0;
2975
mutex->mtx_event_count[1] = event_flag;
2976
mutex->mtx_wait = 0;
2982
int ISC_mutex_lock(MTX mutex)
2984
/**************************************
2986
* I S C _ m u t e x _ l o c k ( V M S )
2988
**************************************
2990
* Functional description
2993
**************************************/
2997
if (lib$bbssi(&bit, mutex->mtx_event_count))
2999
if (!lib$bbssi(&bit, mutex->mtx_event_count))
3001
gds__thread_wait(mutex_test, mutex);
3010
int ISC_mutex_unlock(MTX mutex)
3012
/**************************************
3014
* I S C _ m u t e x _ u n l o c k ( V M S )
3016
**************************************
3018
* Functional description
3021
**************************************/
3023
lib$bbcci(&bit, mutex->mtx_event_count);
3037
int ISC_mutex_init(MTX mutex, SLONG semaphore)
3039
/**************************************
3041
* I S C _ m u t e x _ i n i t ( S O L A R I S _ M T )
3043
**************************************
3045
* Functional description
3046
* Initialize a mutex.
3048
**************************************/
3050
return mutex_init(mutex->mtx_mutex, USYNC_PROCESS, NULL);
3054
int ISC_mutex_lock(MTX mutex)
3056
/**************************************
3058
* I S C _ m u t e x _ l o c k ( S O L A R I S _ M T )
3060
**************************************
3062
* Functional description
3065
**************************************/
3067
int state = mutex_lock(mutex->mtx_mutex);
3070
if (!SYSCALL_INTERRUPTED(state))
3078
int ISC_mutex_lock_cond(MTX mutex)
3080
/**************************************
3082
* 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 )
3084
**************************************
3086
* Functional description
3087
* Conditionally sieze a mutex.
3089
**************************************/
3091
int state = mutex_trylock(mutex->mtx_mutex);
3094
if (!SYSCALL_INTERRUPTED(state))
3102
int ISC_mutex_unlock(MTX mutex)
3104
/**************************************
3106
* I S C _ m u t e x _ u n l o c k ( S O L A R I S _ M T )
3108
**************************************
3110
* Functional description
3113
**************************************/
3115
/* Note use of undocumented lwp_mutex_unlock call
3116
* due to Solaris 2.4 bug */
3117
int state = _lwp_mutex_unlock(mutex->mtx_mutex);
3120
if (!SYSCALL_INTERRUPTED(state))
3126
#endif /* SOLARIS_MT */
3129
#ifdef USE_POSIX_THREADS
3131
int ISC_mutex_init(MTX mutex, SLONG semaphore)
3133
/**************************************
3135
* I S C _ m u t e x _ i n i t ( P O S I X _ T H R E A D S )
3137
**************************************
3139
* Functional description
3140
* Initialize a mutex.
3142
**************************************/
3143
pthread_mutexattr_t mattr;
3145
int state = pthread_mutexattr_init(&mattr);
3148
#if _POSIX_THREAD_PROCESS_SHARED >= 200112L
3149
pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
3151
state = pthread_mutex_init(mutex->mtx_mutex, &mattr);
3152
pthread_mutexattr_destroy(&mattr);
3162
int ISC_mutex_lock(MTX mutex)
3164
/**************************************
3166
* I S C _ m u t e x _ l o c k ( P O S I X _ T H R E A D S )
3168
**************************************
3170
* Functional description
3173
**************************************/
3175
int state = pthread_mutex_lock(mutex->mtx_mutex);
3178
fb_assert(state == -1); /* if state is not 0, it should be -1 */
3183
return pthread_mutex_lock(mutex->mtx_mutex);
3189
int ISC_mutex_lock_cond(MTX mutex)
3191
/**************************************
3193
* 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 )
3195
**************************************
3197
* Functional description
3198
* Conditionally sieze a mutex.
3200
**************************************/
3202
int state = pthread_mutex_trylock(mutex->mtx_mutex);
3204
/* HP's interpretation of return codes is different than Solaris
3205
(and Posix Standard?). Usually in case of error they return
3206
-1 and set errno to whatever error number is.
3207
pthread_mutex_trylock() is a special case:
3209
return errno description
3211
0 mutex has alreary been locked. Could not get it
3212
-1 EINVAL invalid value of mutex
3215
return -99; /* we did not get the mutex for it had already */
3216
/* been locked, let's return something which is */
3217
/* not zero and negative (errno values are positive) */
3221
fb_assert(state == -1); /* if state is not 0 or 1, it should be -1 */
3226
return pthread_mutex_trylock(mutex->mtx_mutex);
3232
int ISC_mutex_unlock(MTX mutex)
3234
/**************************************
3236
* 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 )
3238
**************************************
3240
* Functional description
3243
**************************************/
3245
int state = pthread_mutex_unlock(mutex->mtx_mutex);
3248
fb_assert(state == -1); /* if state is not 0, it should be -1 */
3253
return pthread_mutex_unlock(mutex->mtx_mutex);
3257
#endif /* USE_POSIX_THREADS */
3263
int ISC_mutex_init(MTX mutex, SLONG semaphore)
3265
/**************************************
3267
* I S C _ m u t e x _ i n i t ( U N I X )
3269
* not USE_POSIX_THREADS
3271
**************************************
3273
* Functional description
3274
* Initialize a mutex.
3276
**************************************/
3277
mutex->mtx_semid = semaphore;
3278
mutex->mtx_semnum = 0;
3282
int state = semctl((int) semaphore, 0, SETVAL, arg);
3290
int ISC_mutex_lock(MTX mutex)
3292
/**************************************
3294
* I S C _ m u t e x _ l o c k ( U N I X )
3296
* not USE_POSIX_THREADS
3298
**************************************
3300
* Functional description
3303
**************************************/
3305
sop.sem_num = mutex->mtx_semnum;
3307
sop.sem_flg = SEM_UNDO;
3310
int state = semop(mutex->mtx_semid, &sop, 1);
3313
if (!SYSCALL_INTERRUPTED(errno))
3321
int ISC_mutex_lock_cond(MTX mutex)
3323
/**************************************
3325
* I S C _ m u t e x _ l o c k _ c o n d ( U N I X )
3327
* not USE_POSIX_THREADS
3329
**************************************
3331
* Functional description
3332
* Conditionally sieze a mutex.
3334
**************************************/
3336
sop.sem_num = mutex->mtx_semnum;
3338
sop.sem_flg = SEM_UNDO | IPC_NOWAIT;
3341
int state = semop(mutex->mtx_semid, &sop, 1);
3344
if (!SYSCALL_INTERRUPTED(errno))
3352
int ISC_mutex_unlock(MTX mutex)
3354
/**************************************
3356
* I S C _ m u t e x _ u n l o c k ( U N I X )
3358
* not USE_POSIX_THREADS
3360
**************************************
3362
* Functional description
3365
**************************************/
3367
sop.sem_num = mutex->mtx_semnum;
3369
sop.sem_flg = SEM_UNDO;
3372
int state = semop(mutex->mtx_semid, &sop, 1);
3375
if (!SYSCALL_INTERRUPTED(errno))
3388
static const LPCSTR FAST_MUTEX_EVT_NAME = "%s_FM_EVT";
3389
static const LPCSTR FAST_MUTEX_MAP_NAME = "%s_FM_MAP";
3391
static const int DEFAULT_INTERLOCKED_SPIN_COUNT = 0;
3392
static const int DEFAULT_INTERLOCKED_SPIN_COUNT_SMP = 200;
3395
typedef WINBASEAPI BOOL (WINAPI *pfnSwitchToThread) ();
3396
static inline BOOL switchToThread()
3398
static pfnSwitchToThread fnSwitchToThread = NULL;
3399
static bool bInit = false;
3403
HMODULE hLib = GetModuleHandle("kernel32.dll");
3405
fnSwitchToThread = (pfnSwitchToThread) GetProcAddress(hLib, "SwitchToThread");
3411
if (fnSwitchToThread)
3413
#if !defined SUPERSERVER && !defined EMBEDDED
3414
const HANDLE hThread = GetCurrentThread();
3415
SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL);
3418
res = (*fnSwitchToThread) ();
3420
#if !defined SUPERSERVER && !defined EMBEDDED
3421
SetThreadPriority(hThread, THREAD_PRIORITY_NORMAL);
3429
// MinGW has the wrong declaration for the operating system function.
3430
#if defined __GNUC__
3431
// Cast away volatile
3432
#define FIX_TYPE(arg) const_cast<LPLONG>(arg)
3434
#define FIX_TYPE(arg) arg
3438
static inline void lockSharedSection(volatile FAST_MUTEX_SHARED_SECTION* lpSect, ULONG SpinCount)
3440
while (InterlockedExchange(FIX_TYPE(&lpSect->lSpinLock), 1) != 0)
3442
ULONG j = SpinCount;
3445
if (lpSect->lSpinLock == 0)
3454
static inline bool tryLockSharedSection(volatile FAST_MUTEX_SHARED_SECTION* lpSect)
3456
return (InterlockedExchange(FIX_TYPE(&lpSect->lSpinLock), 1) == 0);
3459
static inline void unlockSharedSection(volatile FAST_MUTEX_SHARED_SECTION* lpSect)
3461
InterlockedExchange(FIX_TYPE(&lpSect->lSpinLock), 0);
3464
static DWORD enterFastMutex(FAST_MUTEX* lpMutex, DWORD dwMilliseconds)
3466
volatile FAST_MUTEX_SHARED_SECTION* lpSect = lpMutex->lpSharedInfo;
3472
if (dwMilliseconds == 0) {
3473
if (!tryLockSharedSection(lpSect))
3474
return WAIT_TIMEOUT;
3477
lockSharedSection(lpSect, lpMutex->lSpinCount);
3480
if (lpSect->lAvailable > 0)
3482
lpSect->lAvailable--;
3484
lpSect->dwThreadId = GetCurrentThreadId();
3486
unlockSharedSection(lpSect);
3487
return WAIT_OBJECT_0;
3491
if (lpSect->dwThreadId == GetCurrentThreadId())
3494
if (dwMilliseconds == 0)
3496
unlockSharedSection(lpSect);
3497
return WAIT_TIMEOUT;
3500
InterlockedIncrement(FIX_TYPE(&lpSect->lThreadsWaiting));
3501
unlockSharedSection(lpSect);
3503
// TODO actual timeout can be of any length
3504
dwResult = WaitForSingleObject(lpMutex->hEvent, dwMilliseconds);
3505
InterlockedDecrement(FIX_TYPE(&lpSect->lThreadsWaiting));
3507
if (dwResult != WAIT_OBJECT_0)
3512
static bool leaveFastMutex(FAST_MUTEX* lpMutex)
3514
volatile FAST_MUTEX_SHARED_SECTION* lpSect = lpMutex->lpSharedInfo;
3516
lockSharedSection(lpSect, lpMutex->lSpinCount);
3517
if (lpSect->lAvailable >= 1)
3519
unlockSharedSection(lpSect);
3520
SetLastError(ERROR_INVALID_PARAMETER);
3523
lpSect->lAvailable++;
3524
if (lpSect->lThreadsWaiting)
3525
SetEvent(lpMutex->hEvent);
3526
unlockSharedSection(lpSect);
3531
static inline void deleteFastMutex(FAST_MUTEX* lpMutex)
3533
UnmapViewOfFile((FAST_MUTEX_SHARED_SECTION*)lpMutex->lpSharedInfo);
3534
CloseHandle(lpMutex->hFileMap);
3535
CloseHandle(lpMutex->hEvent);
3538
static inline void setupMutex(FAST_MUTEX* lpMutex)
3543
if (si.dwNumberOfProcessors > 1)
3544
lpMutex->lSpinCount = DEFAULT_INTERLOCKED_SPIN_COUNT_SMP;
3546
lpMutex->lSpinCount = DEFAULT_INTERLOCKED_SPIN_COUNT;
3549
static bool initializeFastMutex(FAST_MUTEX* lpMutex, LPSECURITY_ATTRIBUTES lpAttributes,
3550
BOOL bInitialState, LPCSTR lpName)
3552
char sz[MAXPATHLEN];
3553
LPCSTR name = lpName;
3556
if (strlen(lpName) + strlen(FAST_MUTEX_EVT_NAME) - 2 >= MAXPATHLEN)
3558
// this is the same error which CreateEvent will return for long name
3559
SetLastError(ERROR_FILENAME_EXCED_RANGE);
3563
setupMutex(lpMutex);
3567
sprintf(sz, FAST_MUTEX_EVT_NAME, lpName);
3571
lpMutex->hEvent = CreateEvent(lpAttributes, FALSE, FALSE, name);
3572
dwLastError = GetLastError();
3574
if (lpMutex->hEvent)
3577
sprintf(sz, FAST_MUTEX_MAP_NAME, lpName);
3579
lpMutex->hFileMap = CreateFileMapping(
3580
INVALID_HANDLE_VALUE,
3584
sizeof(FAST_MUTEX_SHARED_SECTION),
3587
dwLastError = GetLastError();
3589
if (lpMutex->hFileMap)
3591
lpMutex->lpSharedInfo = (FAST_MUTEX_SHARED_SECTION*)
3592
MapViewOfFile(lpMutex->hFileMap, FILE_MAP_WRITE, 0, 0, 0);
3594
if (lpMutex->lpSharedInfo)
3596
if (dwLastError != ERROR_ALREADY_EXISTS)
3598
lpMutex->lpSharedInfo->lSpinLock = 0;
3599
lpMutex->lpSharedInfo->lThreadsWaiting = 0;
3600
lpMutex->lpSharedInfo->lAvailable = bInitialState ? 0 : 1;
3601
InterlockedExchange(FIX_TYPE(&lpMutex->lpSharedInfo->fInitialized), 1);
3605
while (!lpMutex->lpSharedInfo->fInitialized)
3609
SetLastError(dwLastError);
3612
CloseHandle(lpMutex->hFileMap);
3614
CloseHandle(lpMutex->hEvent);
3617
SetLastError(dwLastError);
3621
static bool openFastMutex(FAST_MUTEX* lpMutex, DWORD DesiredAccess, LPCSTR lpName)
3623
char sz[MAXPATHLEN];
3624
LPCSTR name = lpName;
3627
if (strlen(lpName) + strlen(FAST_MUTEX_EVT_NAME) - 2 >= MAXPATHLEN)
3629
SetLastError(ERROR_FILENAME_EXCED_RANGE);
3633
setupMutex(lpMutex);
3637
sprintf(sz, FAST_MUTEX_EVT_NAME, lpName);
3641
lpMutex->hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, name);
3643
dwLastError = GetLastError();
3645
if (lpMutex->hEvent)
3648
sprintf(sz, FAST_MUTEX_MAP_NAME, lpName);
3650
lpMutex->hFileMap = OpenFileMapping(
3651
FILE_MAP_ALL_ACCESS,
3655
dwLastError = GetLastError();
3657
if (lpMutex->hFileMap)
3659
lpMutex->lpSharedInfo = (FAST_MUTEX_SHARED_SECTION*)
3660
MapViewOfFile(lpMutex->hFileMap, FILE_MAP_WRITE, 0, 0, 0);
3662
if (lpMutex->lpSharedInfo)
3665
CloseHandle(lpMutex->hFileMap);
3667
CloseHandle(lpMutex->hEvent);
3670
SetLastError(dwLastError);
3674
static inline void setFastMutexSpinCount(FAST_MUTEX* lpMutex, ULONG SpinCount)
3676
lpMutex->lSpinCount = SpinCount;
3680
int ISC_mutex_init(MTX mutex, const TEXT* mutex_name)
3682
/**************************************
3684
* I S C _ m u t e x _ i n i t ( W I N _ N T )
3686
**************************************
3688
* Functional description
3689
* Initialize a mutex.
3691
**************************************/
3692
char name_buffer[MAXPATHLEN];
3694
make_object_name(name_buffer, sizeof(name_buffer), mutex_name, "_mutex");
3698
return !initializeFastMutex(&mutex->mtx_fast,
3699
ISC_get_security_desc(), FALSE, name_buffer);
3703
memset(&mutex->mtx_fast, 0, sizeof(FAST_MUTEX));
3705
mutex->mtx_fast.hEvent =
3706
CreateMutex(ISC_get_security_desc(), FALSE, name_buffer);
3708
return (mutex->mtx_fast.hEvent) ? 0 : 1;
3713
void ISC_mutex_fini (struct mtx *mutex)
3715
if (mutex->mtx_fast.lpSharedInfo)
3716
deleteFastMutex(&mutex->mtx_fast);
3720
int ISC_mutex_lock(MTX mutex)
3722
/**************************************
3724
* I S C _ m u t e x _ l o c k ( W I N _ N T )
3726
**************************************
3728
* Functional description
3731
**************************************/
3733
const DWORD status = (mutex->mtx_fast.lpSharedInfo) ?
3734
enterFastMutex(&mutex->mtx_fast, INFINITE) :
3735
WaitForSingleObject(mutex->mtx_fast.hEvent, INFINITE);
3737
return (status == WAIT_OBJECT_0 || status == WAIT_ABANDONED) ? 0 : 1;
3741
int ISC_mutex_lock_cond(MTX mutex)
3743
/**************************************
3745
* I S C _ m u t e x _ l o c k _ c o n d ( W I N _ N T )
3747
**************************************
3749
* Functional description
3750
* Conditionally sieze a mutex.
3752
**************************************/
3754
const DWORD status = (mutex->mtx_fast.lpSharedInfo) ?
3755
enterFastMutex(&mutex->mtx_fast, 0) :
3756
WaitForSingleObject (mutex->mtx_fast.hEvent, 0L);
3758
return (status == WAIT_OBJECT_0 || status == WAIT_ABANDONED) ? 0 : 1;
3762
int ISC_mutex_unlock(MTX mutex)
3764
/**************************************
3766
* I S C _ m u t e x _ u n l o c k ( W I N _ N T )
3768
**************************************
3770
* Functional description
3773
**************************************/
3775
if (mutex->mtx_fast.lpSharedInfo) {
3776
return !leaveFastMutex(&mutex->mtx_fast);
3779
return !ReleaseMutex(mutex->mtx_fast.hEvent);
3784
void ISC_mutex_set_spin_count (struct mtx *mutex, ULONG spins)
3786
if (mutex->mtx_fast.lpSharedInfo)
3787
setFastMutexSpinCount(&mutex->mtx_fast, spins);
3794
int ISC_mutex_init(MTX mutex, SLONG dummy)
3796
/**************************************
3798
* I S C _ m u t e x _ i n i t ( G E N E R I C )
3800
**************************************
3802
* Functional description
3803
* Initialize a mutex.
3805
**************************************/
3811
int ISC_mutex_lock(MTX mutex)
3813
/**************************************
3815
* I S C _ m u t e x _ l o c k ( G E N E R I C )
3817
**************************************
3819
* Functional description
3822
**************************************/
3828
int ISC_mutex_unlock(MTX mutex)
3830
/**************************************
3832
* I S C _ m u t e x _ u n l o c k ( G E N E R I C )
3834
**************************************
3836
* Functional description
3839
**************************************/
3848
#define ISC_REMAP_FILE_DEFINED
3849
UCHAR *ISC_remap_file(ISC_STATUS * status_vector,
3850
SH_MEM shmem_data, SLONG new_length, bool flag)
3852
/**************************************
3854
* I S C _ r e m a p _ f i l e ( U N I X - m m a p )
3856
**************************************
3858
* Functional description
3859
* Try to re-map a given file.
3861
**************************************/
3863
ftruncate(shmem_data->sh_mem_handle, new_length);
3866
(UCHAR *) mmap(0, new_length, PROT_READ | PROT_WRITE, MAP_SHARED,
3867
shmem_data->sh_mem_handle, 0);
3868
if ((U_IPTR) address == (U_IPTR) -1)
3871
munmap((char *) shmem_data->sh_mem_address,
3872
shmem_data->sh_mem_length_mapped);
3874
shmem_data->sh_mem_address = address;
3875
shmem_data->sh_mem_length_mapped = new_length;
3884
#define ISC_REMAP_FILE_DEFINED
3885
UCHAR* ISC_remap_file(ISC_STATUS * status_vector,
3890
/**************************************
3892
* I S C _ r e m a p _ f i l e ( W I N _ N T )
3894
**************************************
3896
* Functional description
3897
* Try to re-map a given file.
3899
**************************************/
3903
(shmem_data->sh_mem_handle, new_length, NULL,
3904
FILE_BEGIN) == 0xFFFFFFFF
3905
|| !SetEndOfFile(shmem_data->sh_mem_handle)
3906
|| !FlushViewOfFile(shmem_data->sh_mem_address, 0))
3908
error(status_vector, "SetFilePointer", GetLastError());
3912
/* If the remap file exists, remap does not occur correctly.
3913
* The file number is local to the process and when it is
3914
* incremented and a new filename is created, that file may
3915
* already exist. In that case, the file is not expanded.
3916
* This will happen when the file is expanded more than once
3917
* by concurrently running processes.
3919
* The problem will be fixed by making sure that a new file name
3920
* is generated with the mapped file is created.
3926
TEXT expanded_filename[MAXPATHLEN];
3927
sprintf(expanded_filename, "%s%"SLONGFORMAT, shmem_data->sh_mem_name,
3928
shmem_data->sh_mem_hdr_address[1] + 1);
3930
file_obj = CreateFileMapping(shmem_data->sh_mem_handle,
3931
ISC_get_security_desc(),
3937
if (!((GetLastError() == ERROR_ALREADY_EXISTS) && flag))
3940
CloseHandle(file_obj);
3941
shmem_data->sh_mem_hdr_address[1]++;
3944
if (file_obj == NULL) {
3945
error(status_vector, "CreateFileMapping", GetLastError());
3949
LPVOID address = MapViewOfFile(file_obj, FILE_MAP_WRITE, 0, 0, 0);
3951
if (address == NULL) {
3952
error(status_vector, "CreateFileMapping", GetLastError());
3953
CloseHandle(file_obj);
3958
shmem_data->sh_mem_hdr_address[0] = new_length;
3959
shmem_data->sh_mem_hdr_address[1]++;
3962
UnmapViewOfFile(shmem_data->sh_mem_address);
3963
CloseHandle(shmem_data->sh_mem_object);
3965
shmem_data->sh_mem_address = static_cast<UCHAR*>(address);
3966
shmem_data->sh_mem_length_mapped = new_length;
3967
shmem_data->sh_mem_object = file_obj;
3969
return reinterpret_cast<UCHAR*>(address);
3974
#ifndef ISC_REMAP_FILE_DEFINED
3975
UCHAR* ISC_remap_file(ISC_STATUS * status_vector,
3980
/**************************************
3982
* I S C _ r e m a p _ f i l e ( G E N E R I C )
3984
**************************************
3986
* Functional description
3987
* Try to re-map a given file.
3989
**************************************/
3991
*status_vector++ = isc_arg_gds;
3992
*status_vector++ = isc_unavailable;
3993
*status_vector++ = isc_arg_end;
4001
void ISC_reset_timer(
4002
FPTR_VOID_PTR timeout_handler,
4004
SLONG * client_timer, void **client_handler)
4006
/**************************************
4008
* I S C _ r e s e t _ t i m e r
4010
**************************************
4012
* Functional description
4013
* Clear a previously established timer and restore
4014
* the previous context.
4016
**************************************/
4017
struct itimerval internal_timer;
4019
ISC_signal_cancel(SIGALRM, timeout_handler, timeout_arg);
4021
/* Cancel the timer, then restore the previous handler and alarm */
4023
timerclear(&internal_timer.it_interval);
4024
timerclear(&internal_timer.it_value);
4025
setitimer(ITIMER_REAL, &internal_timer, NULL);
4026
sigaction(SIGALRM, (struct sigaction*)client_handler, NULL);
4027
setitimer(ITIMER_REAL, (itimerval*)client_timer, NULL);
4034
SLONG micro_seconds,
4035
FPTR_VOID_PTR timeout_handler,
4037
SLONG * client_timer, void **client_handler)
4039
/**************************************
4041
* I S C _ s e t _ t i m e r
4043
**************************************
4045
* Functional description
4046
* Set a timer for the specified amount of time.
4048
**************************************/
4049
struct itimerval internal_timer;
4050
struct sigaction internal_handler;
4052
/* Start by cancelling any existing timer */
4054
timerclear(&internal_timer.it_interval);
4055
timerclear(&internal_timer.it_value);
4056
setitimer(ITIMER_REAL, &internal_timer,
4057
(struct itimerval *) client_timer);
4059
/* Now clear the signal handler while saving the existing one */
4061
internal_handler.sa_handler = SIG_DFL;
4062
sigemptyset(&internal_handler.sa_mask);
4063
internal_handler.sa_flags = SA_RESTART;
4064
sigaction(SIGALRM, &internal_handler,
4065
(struct sigaction *) client_handler);
4070
/* Next set the new alarm handler and finally set the new timer */
4072
ISC_signal(SIGALRM, timeout_handler, timeout_arg);
4074
if (micro_seconds < 1000000)
4075
internal_timer.it_value.tv_usec = micro_seconds;
4077
internal_timer.it_value.tv_sec = micro_seconds / 1000000;
4078
internal_timer.it_value.tv_usec = micro_seconds % 1000000;
4080
setitimer(ITIMER_REAL, &internal_timer, NULL);
4087
void ISC_sync_signals_set()
4089
/**************************************
4091
* I S C _ s y n c _ s i g n a l s _ s e t( U N I X )
4093
**************************************
4095
* Functional description
4096
* Set all the synchronous signals for a particular thread
4098
**************************************/
4100
sigset(SIGILL, longjmp_sig_handler);
4101
sigset(SIGFPE, longjmp_sig_handler);
4102
sigset(SIGBUS, longjmp_sig_handler);
4103
sigset(SIGSEGV, longjmp_sig_handler);
4106
#endif /* SUPERSERVER */
4111
void ISC_sync_signals_reset()
4113
/**************************************
4115
* I S C _ s y n c _ s i g n a l s _ r e s e t ( U N I X )
4117
**************************************
4119
* Functional description
4120
* Reset all the synchronous signals for a particular thread
4123
**************************************/
4125
sigset(SIGILL, SIG_DFL);
4126
sigset(SIGFPE, SIG_DFL);
4127
sigset(SIGBUS, SIG_DFL);
4128
sigset(SIGSEGV, SIG_DFL);
4131
#endif /* SUPERSERVER */
4136
void ISC_unmap_file(ISC_STATUS * status_vector, SH_MEM shmem_data, USHORT flag)
4138
/**************************************
4140
* I S C _ u n m a p _ f i l e ( U N I X - m m a p )
4142
**************************************
4144
* Functional description
4145
* Unmap a given file. Depending upon the flag,
4146
* get rid of the semaphore and/or truncate the file.
4148
**************************************/
4151
munmap((char *) shmem_data->sh_mem_address,
4152
shmem_data->sh_mem_length_mapped);
4154
if (flag & ISC_SEM_REMOVE)
4155
semctl(shmem_data->sh_mem_mutex_arg, 0, IPC_RMID, arg);
4156
if (flag & ISC_MEM_REMOVE) // never set
4157
ftruncate(shmem_data->sh_mem_handle, 0L);
4158
close(shmem_data->sh_mem_handle);
4167
void ISC_unmap_file(ISC_STATUS* status_vector, SH_MEM shmem_data, USHORT flag)
4169
/**************************************
4171
* I S C _ u n m a p _ f i l e ( U N I X - s h m a t )
4173
**************************************
4175
* Functional description
4176
* Detach from the shared memory. Depending upon the flag,
4177
* get rid of the semaphore and/or get rid of shared memory.
4179
**************************************/
4180
struct shmid_ds buf;
4183
shmdt(shmem_data->sh_mem_address);
4184
if (flag & ISC_SEM_REMOVE)
4185
semctl(shmem_data->sh_mem_mutex_arg, 0, IPC_RMID, arg);
4186
if (flag & ISC_MEM_REMOVE) // never set
4187
shmctl(shmem_data->sh_mem_handle, IPC_RMID, &buf);
4195
void ISC_unmap_file(ISC_STATUS * status_vector,
4199
/**************************************
4201
* I S C _ u n m a p _ f i l e ( W I N _ N T )
4203
**************************************
4205
* Functional description
4206
* Detach from the shared memory. Depending upon the flag,
4207
* get rid of the semaphore and/or get rid of shared memory.
4209
**************************************/
4211
CloseHandle(shmem_data->sh_mem_interest);
4212
CloseHandle((HANDLE) shmem_data->sh_mem_mutex_arg);
4213
UnmapViewOfFile(shmem_data->sh_mem_address);
4214
CloseHandle(shmem_data->sh_mem_object);
4215
if (flag & ISC_MEM_REMOVE) // never set
4216
if (SetFilePointer(shmem_data->sh_mem_handle, 0, NULL, FILE_BEGIN) != 0xFFFFFFFF)
4217
SetEndOfFile(shmem_data->sh_mem_handle);
4219
CloseHandle(shmem_data->sh_mem_handle);
4220
UnmapViewOfFile(shmem_data->sh_mem_hdr_address);
4221
CloseHandle(shmem_data->sh_mem_hdr_object);
4227
void ISC_unmap_file(ISC_STATUS * status_vector,
4231
/**************************************
4233
* I S C _ u n m a p _ f i l e ( G E N E R I C )
4235
**************************************
4237
* Functional description
4238
* unmap a given file or shared memory.
4240
**************************************/
4242
*status_vector++ = isc_arg_gds;
4243
*status_vector++ = isc_unavailable;
4244
*status_vector++ = isc_arg_end;
4249
#if defined(UNIX) && !defined(USE_POSIX_THREADS) && !defined(SOLARIS_MT)
4250
static void alarm_handler(void* arg)
4252
/**************************************
4254
* a l a r m _ h a n d l e r ( U N I X )
4256
**************************************
4258
* Functional description
4259
* Handle an alarm clock interrupt.
4261
**************************************/
4266
static void error(ISC_STATUS* status_vector, TEXT* string, ISC_STATUS status)
4268
/**************************************
4272
**************************************
4274
* Functional description
4275
* We've encountered an error, report it.
4277
**************************************/
4279
*status_vector++ = isc_arg_gds;
4280
*status_vector++ = isc_sys_request;
4281
*status_vector++ = isc_arg_string;
4282
*status_vector++ = (ISC_STATUS)(U_IPTR) string;
4283
*status_vector++ = SYS_ARG;
4284
*status_vector++ = status;
4285
*status_vector++ = isc_arg_end;
4290
static int event_test(WAIT * wait)
4292
/**************************************
4294
* e v e n t _ t e s t
4296
**************************************
4298
* Functional description
4299
* Callback routine from thread package for VMS. Returns
4300
* TRUE if wait is satified, otherwise FALSE.
4302
**************************************/
4304
return !ISC_event_blocked(wait->wait_count, wait->wait_events,
4311
static SLONG find_key(ISC_STATUS * status_vector, TEXT * filename)
4313
/**************************************
4317
**************************************
4319
* Functional description
4320
* Find the semaphore/shared memory key for a file.
4322
**************************************/
4326
/* Produce shared memory key for file */
4328
if ((key = ftok(filename, FTOK_KEY)) == -1) {
4329
if ((fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, PRIV)) == -1) {
4330
error(status_vector, "open", errno);
4334
if ((key = ftok(filename, FTOK_KEY)) == -1) {
4335
error(status_vector, "ftok", errno);
4345
#if defined(UNIX) && !defined(USE_POSIX_THREADS) && !defined(SOLARIS_MT)
4346
static SLONG open_semaphores(
4347
ISC_STATUS * status_vector,
4348
SLONG key, int& semaphores)
4350
/**************************************
4352
* o p e n _ s e m a p h o r e s ( U N I X )
4354
**************************************
4356
* Functional description
4357
* Open existing block of semaphores.
4359
**************************************/
4360
// Open semaphore set
4361
SLONG semid = semget(key, 0, 0);
4363
error(status_vector, "semget", errno);
4371
// Get number of semaphores in opened set
4372
if (semctl(semid, 0, IPC_STAT, arg) == -1) {
4373
error(status_vector, "semctl", errno);
4376
if (semaphores > (int) buf.sem_nsems) {
4377
gds__log("Number of requested semaphores (%d) "
4378
"is greater then size of the existing semaphore set (%d)",
4379
semaphores, buf.sem_nsems);
4380
semaphores = buf.sem_nsems;
4387
static SLONG create_semaphores(
4388
ISC_STATUS * status_vector,
4389
SLONG key, int semaphores)
4391
/**************************************
4393
* c r e a t e _ s e m a p h o r e s ( U N I X )
4395
**************************************
4397
* Functional description
4398
* Create or find a block of semaphores.
4400
**************************************/
4404
// Try to open existing semaphore set
4405
semid = semget(key, 0, 0);
4407
if (errno != ENOENT) {
4408
error(status_vector, "semget", errno);
4417
// Get number of semaphores in opened set
4418
if (semctl(semid, 0, IPC_STAT, arg) == -1) {
4419
error(status_vector, "semctl", errno);
4422
if ((int) buf.sem_nsems >= semaphores)
4424
// Number of semaphores in existing set is too small. Discard it.
4425
if (semctl(semid, 0, IPC_RMID) == -1) {
4426
error(status_vector, "semctl", errno);
4431
// Try to create new semaphore set
4432
semid = semget(key, semaphores, IPC_CREAT | IPC_EXCL | PRIV);
4435
// We want to limit access to semaphores, created here
4436
// Reasonable access rights to them - exactly like security database has
4437
char secDb[MAXPATHLEN];
4438
SecurityDatabase::getPath(secDb);
4440
if (stat(secDb, &st) == 0)
4445
ds.sem_perm.uid = geteuid() == 0 ? st.st_uid : geteuid();
4446
ds.sem_perm.gid = st.st_gid;
4447
ds.sem_perm.mode = st.st_mode;
4448
semctl(semid, 0, IPC_SET, arg);
4454
if (errno != EEXIST) {
4455
error(status_vector, "semget", errno);
4466
void longjmp_sig_handler(int sig_num)
4468
/**************************************
4470
* l o n g j m p _ s i g _ h a n d l e r
4472
**************************************
4474
* Functional description
4475
* The generic signal handler for all signals in a thread.
4477
**************************************/
4479
/* Note: we can only do this since we know that we
4480
will only be going to JRD, specifically fun and blf.
4481
If we were to make this generic, we would need to
4482
actually hang the sigsetjmp menber off of THDD, and
4483
make sure that it is set properly for all sub-systems. */
4485
thread_db* tdbb = JRD_get_thread_data();
4487
siglongjmp(tdbb->tdbb_sigsetjmp, sig_num);
4490
#endif /* SUPERSERVER */
4494
static BOOLEAN mutex_test(MTX mutex)
4496
/**************************************
4498
* m u t e x _ t e s t
4500
**************************************
4502
* Functional description
4503
* Callback routine from thread package for VMS. Returns
4504
* TRUE if mutex has been granted, otherwise FALSE.
4506
**************************************/
4508
return (mutex->mtx_event_count[0] & 1) ? FALSE : TRUE;
4514
static void make_object_name(
4517
const TEXT* object_name,
4518
const TEXT* object_type)
4520
/**************************************
4522
* m a k e _ o b j e c t _ n a m e ( W I N _ N T )
4524
**************************************
4526
* Functional description
4527
* Create an object name from a name and type.
4528
* Also replace the file separator with "_".
4530
**************************************/
4532
_snprintf(buffer, bufsize, object_name, ISC_get_host(hostname, sizeof(hostname)));
4533
buffer[bufsize - 1] = 0;
4537
for (p = buffer; c = *p; p++)
4538
if (c == '/' || c == '\\' || c == ':')
4540
strcpy(p, object_type);
4542
// hvlad: windows file systems use case-insensitive file names
4543
// while kernel objects such as events use case-sensitive names.
4544
// Since we use root directory as part of kernel objects names
4545
// we must use lower (or upper) register for object name to avoid
4546
// misunderstanding between processes
4550
fb_utils::prefix_kernel_object_name(buffer, bufsize);
4556
// Making this function bool reversed the returned value, but nobody reads it.
4557
#if defined(UNIX) && !defined(USE_POSIX_THREADS) && !defined(SOLARIS_MT)
4558
static bool semaphore_wait_isc_sync(int count, int semid, int *semnums)
4560
/**************************************
4562
* s e m a p h o r e _ w a i t _ i s c _ s y n c
4564
* (formerly known as: s e m a p h o r e _ w a i t)
4566
**************************************
4568
* Functional description
4569
* Wait on the given semaphores. Return FB_FAILURE if
4570
* interrupted (including timeout) before any
4571
* semaphore was poked else return FB_SUCCESS.
4573
**************************************/
4574
#pragma FB_COMPILER_MESSAGE("Warning: B.O. with more than 16 inputs")
4576
struct sembuf semops[16];
4577
struct sembuf* semptr = semops;
4578
for (int i = 0; i < count; ++semptr, i++) {
4580
semptr->sem_flg = 0;
4581
semptr->sem_num = *semnums++;
4583
int ret = semop(semid, semops, count);
4585
if (ret == -1 && SYSCALL_INTERRUPTED(errno))