~ubuntu-branches/ubuntu/oneiric/firebird2.1/oneiric

« back to all changes in this revision

Viewing changes to .pc/separate-file-and-sem-perms.patch/src/jrd/isc_sync.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Damyan Ivanov
  • Date: 2011-04-22 18:59:44 UTC
  • mfrom: (2.1.24 sid)
  • Revision ID: james.westby@ubuntu.com-20110422185944-egwy9r5xynjddku5
Tags: 2.1.4.18393-0.ds2-2
* apply patch from upstream SVN fixing ICU collations
* remove lintian overrides about manpages shipped in dependency package
* claim compliancy with Policy 3.9.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *      PROGRAM:        JRD Access Method
 
3
 *      MODULE:         isc_sync.cpp
 
4
 *      DESCRIPTION:    General purpose but non-user routines.
 
5
 *
 
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
 
10
 *
 
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.
 
15
 *
 
16
 * The Original Code was created by Inprise Corporation
 
17
 * and its predecessors. Portions created by Inprise Corporation are
 
18
 * Copyright (C) Inprise Corporation.
 
19
 *
 
20
 * All Rights Reserved.
 
21
 * Contributor(s): ______________________________________.
 
22
 *
 
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
 
26
 *
 
27
 * 2002-02-23 Sean Leyne - Code Cleanup, removed old M88K and NCR3000 port
 
28
 *
 
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
 
31
 *
 
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
 
35
 *
 
36
 * 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
 
37
 *
 
38
 */
 
39
 
 
40
#include "firebird.h"
 
41
#include <stdio.h>
 
42
#include <stdlib.h>
 
43
#include <string.h>
 
44
 
 
45
#ifdef SOLARIS
 
46
#ifndef DEV_BUILD
 
47
#define NDEBUG                                 // Turn off fb_assert() macros
 
48
#endif
 
49
#include "../jrd/gdsassert.h"
 
50
#endif
 
51
 
 
52
#ifdef HPUX
 
53
#include <sys/pstat.h>
 
54
#endif
 
55
 
 
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"
 
74
 
 
75
#if defined(SIG_RESTART) || defined(UNIX) 
 
76
static ULONG inhibit_restart;
 
77
#endif
 
78
#ifndef REQUESTER
 
79
static int process_id;
 
80
#endif
 
81
#ifdef UNIX
 
82
static UCHAR *next_shared_memory;
 
83
#endif
 
84
 
 
85
/* VMS Specific Stuff */
 
86
 
 
87
#ifdef VMS
 
88
 
 
89
#include <rms.h>
 
90
#include <descrip.h>
 
91
#include <ssdef.h>
 
92
#include <jpidef.h>
 
93
#include <prvdef.h>
 
94
#include <secdef.h>
 
95
#include <lckdef.h>
 
96
#include "../jrd/lnmdef.h"
 
97
#include <signal.h>
 
98
 
 
99
#include "../jrd/prv_m_bypass.h"
 
100
#endif /* of ifdef VMS */
 
101
 
 
102
 
 
103
/* Unix specific stuff */
 
104
 
 
105
#ifdef UNIX
 
106
#include <sys/types.h>
 
107
#include <sys/stat.h>
 
108
#include <sys/file.h>
 
109
 
 
110
#ifdef HAVE_SIGNAL_H
 
111
#include <signal.h>
 
112
#endif
 
113
 
 
114
#ifdef HAVE_SYS_SIGNAL_H
 
115
#include <sys/signal.h>
 
116
#endif
 
117
 
 
118
#include <errno.h>
 
119
#ifdef HAVE_UNISTD_H
 
120
#include <unistd.h>
 
121
#endif
 
122
#include <sys/ipc.h>
 
123
#include <sys/shm.h>
 
124
#include <sys/sem.h>
 
125
 
 
126
#ifndef O_RDWR
 
127
#include <fcntl.h>
 
128
#endif
 
129
 
 
130
#ifdef HAVE_MMAP
 
131
#include <sys/mman.h>
 
132
#endif
 
133
 
 
134
#define FTOK_KEY        15
 
135
#define PRIV            0666
 
136
 
 
137
#ifndef SHMEM_DELTA
 
138
#define SHMEM_DELTA     (1 << 22)
 
139
#endif
 
140
 
 
141
#ifndef SIGURG
 
142
#define SIGURG          SIGINT
 
143
#endif
 
144
 
 
145
#ifndef HAVE_SEMUN
 
146
union semun
 
147
{
 
148
        int val;
 
149
        struct semid_ds *buf;
 
150
        ushort *array;
 
151
};
 
152
#endif
 
153
#endif /* UNIX */
 
154
 
 
155
#ifdef HAVE_SYS_PARAM_H
 
156
#include <sys/param.h>
 
157
#endif
 
158
 
 
159
#ifndef HAVE_GETPAGESIZE
 
160
static size_t getpagesize(void)
 
161
{
 
162
        return PAGESIZE;
 
163
}
 
164
#endif
 
165
 
 
166
 
 
167
/* Windows NT */
 
168
 
 
169
#ifdef WIN_NT
 
170
 
 
171
#include <process.h>
 
172
#include <signal.h>
 
173
#include <windows.h>
 
174
 
 
175
#endif
 
176
 
 
177
using namespace Jrd;
 
178
 
 
179
static void             error(ISC_STATUS*, TEXT*, ISC_STATUS);
 
180
 
 
181
#ifdef UNIX
 
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 *);
 
188
#endif
 
189
#ifdef SUPERSERVER
 
190
static void             longjmp_sig_handler(int);
 
191
#endif
 
192
#endif // UNIX
 
193
 
 
194
#ifdef VMS
 
195
static int event_test(WAIT *);
 
196
static BOOLEAN mutex_test(MTX);
 
197
#endif
 
198
 
 
199
#if defined(WIN_NT)
 
200
static void make_object_name(TEXT*, size_t, const TEXT*, const TEXT*);
 
201
#endif
 
202
 
 
203
#if defined FREEBSD || defined NETBSD || defined DARWIN || defined HPUX
 
204
#define sigset      signal
 
205
#endif
 
206
 
 
207
 
 
208
#ifdef SIG_RESTART
 
209
BOOLEAN ISC_check_restart(void)
 
210
{
 
211
/**************************************
 
212
 *
 
213
 *      I S C _ c h e c k _ r e s t a r t
 
214
 *
 
215
 **************************************
 
216
 *
 
217
 * Functional description
 
218
 *      Return a flag that indicats whether
 
219
 *      or not to restart an interrupted
 
220
 *      system call.
 
221
 *
 
222
 **************************************/
 
223
 
 
224
        return (inhibit_restart) ? FALSE : TRUE;
 
225
}
 
226
#endif /* SIG_RESTART */
 
227
 
 
228
 
 
229
#ifdef SOLARIS_MT
 
230
#define EVENTS
 
231
int ISC_event_blocked(USHORT count, event_t** events, SLONG* values)
 
232
{
 
233
/**************************************
 
234
 *
 
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 )
 
236
 *
 
237
 **************************************
 
238
 *
 
239
 * Functional description
 
240
 *      If a wait would block, return TRUE.
 
241
 *
 
242
 **************************************/
 
243
 
 
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");
 
248
                        fflush(stdout);
 
249
#endif
 
250
                        return FALSE;
 
251
                }
 
252
 
 
253
#ifdef DEBUG_ISC_SYNC
 
254
        printf("ISC_event_blocked: TRUE (eg nothing happened yet)\n");
 
255
        fflush(stdout);
 
256
#endif
 
257
        return TRUE;
 
258
}
 
259
 
 
260
 
 
261
SLONG ISC_event_clear(event_t* event)
 
262
{
 
263
/**************************************
 
264
 *
 
265
 *      I S C _ e v e n t _ c l e a r   ( S O L A R I S _ M T )
 
266
 *
 
267
 **************************************
 
268
 *
 
269
 * Functional description
 
270
 *      Clear an event preparatory to waiting on it.  The order of
 
271
 *      battle for event synchronization is:
 
272
 *
 
273
 *          1.  Clear event.
 
274
 *          2.  Test data structure for event already completed
 
275
 *          3.  Wait on event.
 
276
 *
 
277
 **************************************/
 
278
        mutex_lock(event->event_mutex);
 
279
        const SLONG ret = event->event_count + 1;
 
280
        mutex_unlock(event->event_mutex);
 
281
        return ret;
 
282
}
 
283
 
 
284
 
 
285
void ISC_event_fini(event_t* event)
 
286
{
 
287
/**************************************
 
288
 *
 
289
 *      I S C _ e v e n t _ f i n i     ( S O L A R I S _ M T )
 
290
 *
 
291
 **************************************
 
292
 *
 
293
 * Functional description
 
294
 *      Discard an event object.
 
295
 *
 
296
 **************************************/
 
297
 
 
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);
 
302
        }
 
303
}
 
304
 
 
305
 
 
306
int ISC_event_init(event_t* event, int semid, int semnum)
 
307
{
 
308
/**************************************
 
309
 *
 
310
 *      I S C _ e v e n t _ i n i t     ( S O L A R I S _ M T )
 
311
 *
 
312
 **************************************
 
313
 *
 
314
 * Functional description
 
315
 *      Prepare an event object for use.
 
316
 *
 
317
 **************************************/
 
318
        //SLONG key, n;
 
319
        //union semun arg;
 
320
 
 
321
        event->event_count = 0;
 
322
 
 
323
        if (!semnum) {
 
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);
 
328
        }
 
329
        else {
 
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);
 
334
        }
 
335
 
 
336
        return TRUE;
 
337
}
 
338
 
 
339
 
 
340
int ISC_event_post(event_t* event)
 
341
{
 
342
/**************************************
 
343
 *
 
344
 *      I S C _ e v e n t _ p o s t     ( S O L A R I S _ M T )
 
345
 *
 
346
 **************************************
 
347
 *
 
348
 * Functional description
 
349
 *      Post an event to wake somebody else up.
 
350
 *
 
351
 **************************************/
 
352
/* For Solaris, we use cond_broadcast rather than cond_signal so that
 
353
   all waiters on the event are notified and awakened */
 
354
 
 
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);
 
359
        if (ret)
 
360
                gds__log("ISC_event_post: cond_broadcast failed with errno = %d",
 
361
                                 ret);
 
362
        return ret;
 
363
}
 
364
 
 
365
 
 
366
int ISC_event_wait(SSHORT       count,
 
367
                                   event_t**    events,
 
368
                                   SLONG*       values,
 
369
                                   SLONG        micro_seconds,
 
370
                                   FPTR_VOID_PTR timeout_handler,
 
371
                                   void*        handler_arg)
 
372
{
 
373
/**************************************
 
374
 *
 
375
 *      I S C _ e v e n t _ w a i t     ( S O L A R I S _ M T )
 
376
 *
 
377
 **************************************
 
378
 *
 
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.
 
384
 *
 
385
 **************************************/
 
386
 
 
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);
 
392
 
 
393
/* If we're not blocked, the rest is a gross waste of time */
 
394
 
 
395
        if (!ISC_event_blocked(count, events, values))
 
396
                return FB_SUCCESS;
 
397
 
 
398
/* Set up timers if a timeout period was specified. */
 
399
 
 
400
        timestruc_t timer;
 
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);
 
405
        }
 
406
 
 
407
        int ret = FB_SUCCESS;
 
408
        mutex_lock((*events)->event_mutex);
 
409
        for (;;) {
 
410
                if (!ISC_event_blocked(count, events, values)) {
 
411
                        ret = FB_SUCCESS;
 
412
                        break;
 
413
                }
 
414
 
 
415
                /* The Solaris cond_wait & cond_timedwait calls atomically release
 
416
                   the mutex and start a wait.  The mutex is reacquired before the
 
417
                   call returns. */
 
418
 
 
419
                if (micro_seconds > 0)
 
420
                        ret =
 
421
                                cond_timedwait((*events)->event_semnum,
 
422
                                                           (*events)->event_mutex, &timer);
 
423
                else
 
424
                        ret = cond_wait((*events)->event_semnum, (*events)->event_mutex);
 
425
                if (micro_seconds > 0 && (ret == ETIME)) {
 
426
 
 
427
                        /* The timer expired - see if the event occured and return
 
428
                           FB_SUCCESS or FB_FAILURE accordingly. */
 
429
 
 
430
                        if (ISC_event_blocked(count, events, values))
 
431
                                ret = FB_FAILURE;
 
432
                        else
 
433
                                ret = FB_SUCCESS;
 
434
                        break;
 
435
                }
 
436
        }
 
437
        mutex_unlock((*events)->event_mutex);
 
438
        return ret;
 
439
}
 
440
#endif /* SOLARIS_MT */
 
441
 
 
442
 
 
443
#ifdef USE_POSIX_THREADS
 
444
#define EVENTS
 
445
int ISC_event_blocked(USHORT count, event_t** events, SLONG * values)
 
446
{
 
447
/**************************************
 
448
 *
 
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 )
 
450
 *
 
451
 **************************************
 
452
 *
 
453
 * Functional description
 
454
 *      If a wait would block, return TRUE.
 
455
 *
 
456
 **************************************/
 
457
 
 
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");
 
462
                        fflush(stdout);
 
463
#endif
 
464
                        return FALSE;
 
465
                }
 
466
 
 
467
#ifdef DEBUG_ISC_SYNC
 
468
        printf("ISC_event_blocked: TRUE (eg nothing happened yet)\n");
 
469
        fflush(stdout);
 
470
#endif
 
471
        return TRUE;
 
472
}
 
473
 
 
474
 
 
475
SLONG ISC_event_clear(event_t* event)
 
476
{
 
477
/**************************************
 
478
 *
 
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 )
 
480
 *
 
481
 **************************************
 
482
 *
 
483
 * Functional description
 
484
 *      Clear an event preparatory to waiting on it.  The order of
 
485
 *      battle for event synchronization is:
 
486
 *
 
487
 *          1.  Clear event.
 
488
 *          2.  Test data structure for event already completed
 
489
 *          3.  Wait on event.
 
490
 *
 
491
 **************************************/
 
492
        pthread_mutex_lock(event->event_mutex);
 
493
        const SLONG ret = event->event_count + 1;
 
494
        pthread_mutex_unlock(event->event_mutex);
 
495
        return ret;
 
496
}
 
497
 
 
498
 
 
499
void ISC_event_fini(event_t* event)
 
500
{
 
501
/**************************************
 
502
 *
 
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 )
 
504
 *
 
505
 **************************************
 
506
 *
 
507
 * Functional description
 
508
 *      Discard an event object.
 
509
 *
 
510
 **************************************/
 
511
 
 
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);
 
516
        }
 
517
}
 
518
 
 
519
 
 
520
int ISC_event_init(event_t* event, int semid, int semnum)
 
521
{
 
522
/**************************************
 
523
 *
 
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 )
 
525
 *
 
526
 **************************************
 
527
 *
 
528
 * Functional description
 
529
 *      Prepare an event object for use.
 
530
 *
 
531
 **************************************/
 
532
        //SLONG key, n;
 
533
        //union semun arg;
 
534
        pthread_mutexattr_t mattr;
 
535
        pthread_condattr_t cattr;
 
536
 
 
537
        event->event_count = 0;
 
538
 
 
539
        if (!semnum) {
 
540
                /* Prepare an Inter-Thread event block */
 
541
                event->event_semid = -1;
 
542
 
 
543
                /* Default attribute objects initialize sync. primitives
 
544
                   to be used to sync thread within one process only.
 
545
                 */
 
546
#ifdef HP10
 
547
                pthread_mutex_init(event->event_mutex, pthread_mutexattr_default);
 
548
                pthread_cond_init(event->event_semnum, pthread_condattr_default);
 
549
#else
 
550
                pthread_mutex_init(event->event_mutex, NULL);
 
551
                pthread_cond_init(event->event_semnum, NULL);
 
552
#endif /* HP10 */
 
553
        }
 
554
        else {
 
555
                /* Prepare an Inter-Process event block */
 
556
                event->event_semid = semid;
 
557
 
 
558
                pthread_mutexattr_init(&mattr);
 
559
#if _POSIX_THREAD_PROCESS_SHARED >= 200112L
 
560
                pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
 
561
#endif
 
562
                pthread_mutex_init(event->event_mutex, &mattr);
 
563
                pthread_mutexattr_destroy(&mattr);
 
564
 
 
565
                pthread_condattr_init(&cattr);
 
566
#if _POSIX_THREAD_PROCESS_SHARED >= 200112L
 
567
                pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
 
568
#endif
 
569
                pthread_cond_init(event->event_semnum, &cattr);
 
570
                pthread_condattr_destroy(&cattr);
 
571
        }
 
572
 
 
573
        return TRUE;
 
574
}
 
575
 
 
576
 
 
577
int ISC_event_post(event_t* event)
 
578
{
 
579
/**************************************
 
580
 *
 
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 )
 
582
 *
 
583
 **************************************
 
584
 *
 
585
 * Functional description
 
586
 *      Post an event to wake somebody else up.
 
587
 *
 
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);
 
593
        if (ret)
 
594
#ifdef HP10
 
595
 
 
596
        {
 
597
                fb_assert(ret == -1);
 
598
                gds__log
 
599
                        ("ISC_event_post: pthread_cond_broadcast failed with errno = %d",
 
600
                         errno);
 
601
                return errno;
 
602
        }
 
603
        return 0;
 
604
 
 
605
#else
 
606
 
 
607
                gds__log
 
608
                        ("ISC_event_post: pthread_cond_broadcast failed with errno = %d",
 
609
                         ret);
 
610
        return ret;
 
611
 
 
612
#endif /* HP10 */
 
613
}
 
614
 
 
615
 
 
616
int ISC_event_wait(
 
617
                                   SSHORT count,
 
618
                                   event_t** events,
 
619
                                   SLONG * values,
 
620
                                   SLONG micro_seconds,
 
621
                                   FPTR_VOID_PTR timeout_handler, void *handler_arg)
 
622
{
 
623
/**************************************
 
624
 *
 
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 )
 
626
 *
 
627
 **************************************
 
628
 *
 
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.
 
634
 *
 
635
 **************************************/
 
636
 
 
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);
 
642
 
 
643
/* If we're not blocked, the rest is a gross waste of time */
 
644
 
 
645
        if (!ISC_event_blocked(count, events, values))
 
646
                return FB_SUCCESS;
 
647
 
 
648
/* Set up timers if a timeout period was specified. */
 
649
 
 
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);
 
655
        }
 
656
 
 
657
        int ret = FB_SUCCESS;
 
658
        pthread_mutex_lock((*events)->event_mutex);
 
659
        for (;;) {
 
660
                if (!ISC_event_blocked(count, events, values)) {
 
661
                        ret = FB_SUCCESS;
 
662
                        break;
 
663
                }
 
664
 
 
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.
 
668
                 */
 
669
                if (micro_seconds > 0)
 
670
                {
 
671
                        ret =
 
672
                                pthread_cond_timedwait((*events)->event_semnum,
 
673
                                                                           (*events)->event_mutex, &timer);
 
674
 
 
675
#ifdef HP10
 
676
                        if ((ret == -1) && (errno == EAGAIN))
 
677
#else
 
678
#if (defined LINUX || defined DARWIN || defined HP11 || defined FREEBSD)
 
679
                        if (ret == ETIMEDOUT)
 
680
#else
 
681
                        if (ret == ETIME)
 
682
#endif
 
683
#endif
 
684
                        {
 
685
 
 
686
                                /* The timer expired - see if the event occured and return
 
687
                                   FB_SUCCESS or FB_FAILURE accordingly. */
 
688
 
 
689
                                if (ISC_event_blocked(count, events, values))
 
690
                                        ret = FB_FAILURE;
 
691
                                else
 
692
                                        ret = FB_SUCCESS;
 
693
                                break;
 
694
                        }
 
695
                }
 
696
                else
 
697
                        ret =
 
698
                                pthread_cond_wait((*events)->event_semnum,
 
699
                                                                  (*events)->event_mutex);
 
700
        }
 
701
        pthread_mutex_unlock((*events)->event_mutex);
 
702
        return ret;
 
703
}
 
704
#endif /* USE_POSIX_THREADS */
 
705
 
 
706
 
 
707
#ifdef UNIX
 
708
#ifndef EVENTS
 
709
#define EVENTS
 
710
int ISC_event_blocked(USHORT count, event_t** events, SLONG * values)
 
711
{
 
712
/**************************************
 
713
 *
 
714
 *      I S C _ e v e n t _ b l o c k e d       ( U N I X )
 
715
 *                                             not SOLARIS
 
716
 *                                             not USE_POSIX_THREADS
 
717
 **************************************
 
718
 *
 
719
 * Functional description
 
720
 *      If a wait would block, return TRUE.
 
721
 *
 
722
 **************************************/
 
723
 
 
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");
 
728
                        fflush(stdout);
 
729
#endif
 
730
                        return FALSE;
 
731
                }
 
732
 
 
733
#ifdef DEBUG_ISC_SYNC
 
734
        printf("ISC_event_blocked: TRUE (eg nothing happened yet)\n");
 
735
        fflush(stdout);
 
736
#endif
 
737
        return TRUE;
 
738
}
 
739
 
 
740
 
 
741
SLONG ISC_event_clear(event_t* event)
 
742
{
 
743
/**************************************
 
744
 *
 
745
 *      I S C _ e v e n t _ c l e a r   ( U N I X )
 
746
 *                                             not SOLARIS
 
747
 *                                             not USE_POSIX_THREADS
 
748
 **************************************
 
749
 *
 
750
 * Functional description
 
751
 *      Clear an event preparatory to waiting on it.  The order of
 
752
 *      battle for event synchronization is:
 
753
 *
 
754
 *          1.  Clear event.
 
755
 *          2.  Test data structure for event already completed
 
756
 *          3.  Wait on event.
 
757
 *
 
758
 **************************************/
 
759
        union semun arg;
 
760
 
 
761
        if (event->event_semid != -1) {
 
762
                arg.val = 1;
 
763
                // int ret =
 
764
                semctl(event->event_semid, event->event_semnum, SETVAL, arg);
 
765
        }
 
766
 
 
767
        return (event->event_count + 1);
 
768
}
 
769
 
 
770
 
 
771
void ISC_event_fini(event_t* event)
 
772
{
 
773
/**************************************
 
774
 *
 
775
 *      I S C _ e v e n t _ f i n i     ( U N I X )
 
776
 *                                             not SOLARIS
 
777
 *                                             not USE_POSIX_THREADS
 
778
 **************************************
 
779
 *
 
780
 * Functional description
 
781
 *      Discard an event object.
 
782
 *
 
783
 **************************************/
 
784
}
 
785
 
 
786
 
 
787
int ISC_event_init(event_t* event, int semid, int semnum)
 
788
{
 
789
/**************************************
 
790
 *
 
791
 *      I S C _ e v e n t _ i n i t     ( U N I X )
 
792
 *                                             not SOLARIS
 
793
 *                                             not USE_POSIX_THREADS
 
794
 **************************************
 
795
 *
 
796
 * Functional description
 
797
 *      Prepare an event object for use.
 
798
 *
 
799
 **************************************/
 
800
        union semun arg;
 
801
 
 
802
        event->event_count = 0;
 
803
 
 
804
        if (!semnum) {
 
805
                event->event_semid = -1;
 
806
                event->event_semnum = 0;
 
807
        }
 
808
        else {
 
809
                event->event_semid = semid;
 
810
                event->event_semnum = semnum;
 
811
                arg.val = 0;
 
812
                //SLONG n =
 
813
                semctl(semid, semnum, SETVAL, arg);
 
814
        }
 
815
 
 
816
        return TRUE;
 
817
}
 
818
 
 
819
 
 
820
int ISC_event_post(event_t* event)
 
821
{
 
822
/**************************************
 
823
 *
 
824
 *      I S C _ e v e n t _ p o s t     ( U N I X )
 
825
 *                                             not SOLARIS
 
826
 *                                             not USE_POSIX_THREADS
 
827
 **************************************
 
828
 *
 
829
 * Functional description
 
830
 *      Post an event to wake somebody else up.
 
831
 *
 
832
 **************************************/
 
833
        union semun arg;
 
834
 
 
835
        ++event->event_count;
 
836
 
 
837
        while (event->event_semid != -1) {
 
838
                arg.val = 0;
 
839
                int ret = semctl(event->event_semid, event->event_semnum, SETVAL, arg);
 
840
                if (ret != -1)
 
841
                        return 0;
 
842
                if (!SYSCALL_INTERRUPTED(errno)) {
 
843
                        gds__log("ISC_event_post: semctl failed with errno = %d", errno);
 
844
                        return errno;
 
845
                }
 
846
        }
 
847
 
 
848
        return 0;
 
849
}
 
850
 
 
851
 
 
852
int ISC_event_wait(
 
853
                                   SSHORT count,
 
854
                                   event_t** events,
 
855
                                   SLONG * values,
 
856
                                   SLONG micro_seconds,
 
857
                                   FPTR_VOID_PTR timeout_handler, void *handler_arg)
 
858
{
 
859
/**************************************
 
860
 *
 
861
 *      I S C _ e v e n t _ w a i t     ( U N I X )
 
862
 *                                             not SOLARIS
 
863
 *                                             not USE_POSIX_THREADS
 
864
 **************************************
 
865
 *
 
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.
 
871
 *
 
872
 **************************************/
 
873
        sigset_t mask, oldmask;
 
874
 
 
875
/* If we're not blocked, the rest is a gross waste of time */
 
876
 
 
877
        if (!ISC_event_blocked(count, events, values))
 
878
                return FB_SUCCESS;
 
879
 
 
880
/* If this is a local semaphore, don't sweat the semaphore non-sense */
 
881
 
 
882
        if ((*events)->event_semid == -1) {
 
883
                ++inhibit_restart;
 
884
                sigprocmask(SIG_BLOCK, NULL, &oldmask);
 
885
                mask = oldmask;
 
886
                sigaddset(&mask, SIGUSR1);
 
887
                sigaddset(&mask, SIGUSR2);
 
888
                sigaddset(&mask, SIGURG);
 
889
                sigprocmask(SIG_BLOCK, &mask, NULL);
 
890
                for (;;) {
 
891
                        if (!ISC_event_blocked(count, events, values)) {
 
892
                                --inhibit_restart;
 
893
                                sigprocmask(SIG_SETMASK, &oldmask, NULL);
 
894
                                return FB_SUCCESS;
 
895
                        }
 
896
                        sigsuspend(&oldmask);
 
897
                }
 
898
        }
 
899
 
 
900
/* Only the internal event work is available in the SHRLIB version of pipe server
 
901
 */
 
902
 
 
903
/* Set up for a semaphore operation */
 
904
 
 
905
        int semid = (int) (*events)->event_semid;
 
906
 
 
907
/* Collect the semaphore numbers in an array */
 
908
 
 
909
        int i = 0;
 
910
        int semnums[16];
 
911
        int* semnum = semnums;
 
912
        for (event_t** event = events; i < count; i++)
 
913
                *semnum++ = (*event++)->event_semnum;
 
914
 
 
915
/* Set up timers if a timeout period was specified. */
 
916
 
 
917
        struct itimerval user_timer;
 
918
        struct sigaction user_handler;
 
919
        if (micro_seconds > 0) {
 
920
                if (!timeout_handler)
 
921
                        timeout_handler = alarm_handler;
 
922
 
 
923
                ISC_set_timer(micro_seconds, timeout_handler, handler_arg,
 
924
                                          (SLONG*)&user_timer, (void**)&user_handler);
 
925
        }
 
926
 
 
927
/* Go into wait loop */
 
928
 
 
929
        int ret;
 
930
        for (;;) {
 
931
                if (!ISC_event_blocked(count, events, values)) {
 
932
                        if (micro_seconds <= 0)
 
933
                                return FB_SUCCESS;
 
934
                        ret = FB_SUCCESS;
 
935
                        break;
 
936
                }
 
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. */
 
942
 
 
943
                        if (ISC_event_blocked(count, events, values))
 
944
                                ret = FB_FAILURE;
 
945
                        else
 
946
                                ret = FB_SUCCESS;
 
947
                        break;
 
948
                }
 
949
        }
 
950
 
 
951
/* Cancel the handler.  We only get here if a timeout was specified. */
 
952
 
 
953
        ISC_reset_timer(timeout_handler, handler_arg, (SLONG*)&user_timer, (void**)&user_handler);
 
954
 
 
955
        return ret;
 
956
}
 
957
#endif /* EVENTS */
 
958
#endif /* UNIX */
 
959
 
 
960
 
 
961
#ifdef VMS
 
962
#define EVENTS
 
963
int ISC_event_blocked(USHORT count, event_t** events, SLONG * values)
 
964
{
 
965
/**************************************
 
966
 *
 
967
 *      I S C _ e v e n t _ b l o c k e d       ( V M S )
 
968
 *
 
969
 **************************************
 
970
 *
 
971
 * Functional description
 
972
 *      If a wait would block, return TRUE.
 
973
 *
 
974
 **************************************/
 
975
 
 
976
        for (; count; --count, events++, values++)
 
977
                if ((*events)->event_count >= *values)
 
978
                        return FALSE;
 
979
 
 
980
        return TRUE;
 
981
}
 
982
 
 
983
 
 
984
SLONG ISC_event_clear(event_t* event)
 
985
{
 
986
/**************************************
 
987
 *
 
988
 *      I S C _ e v e n t _ c l e a r   ( V M S )
 
989
 *
 
990
 **************************************
 
991
 *
 
992
 * Functional description
 
993
 *      Clear an event preparatory to waiting on it.  The order of
 
994
 *      battle for event synchronization is:
 
995
 *
 
996
 *          1.  Clear event.
 
997
 *          2.  Test data structure for event already completed
 
998
 *          3.  Wait on event.
 
999
 *
 
1000
 **************************************/
 
1001
 
 
1002
        return event->event_count + 1;
 
1003
}
 
1004
 
 
1005
 
 
1006
int ISC_event_init(event_t* event, int semid, int semnum)
 
1007
{
 
1008
/**************************************
 
1009
 *
 
1010
 *      I S C _ e v e n t _ i n i t     ( V M S )
 
1011
 *
 
1012
 **************************************
 
1013
 *
 
1014
 * Functional description
 
1015
 *      Prepare an event object for use.
 
1016
 *
 
1017
 **************************************/
 
1018
 
 
1019
        gds__wake_init();
 
1020
        event->event_count = 0;
 
1021
        event->event_pid = getpid();
 
1022
 
 
1023
        return TRUE;
 
1024
}
 
1025
 
 
1026
 
 
1027
int ISC_event_post(event_t* event)
 
1028
{
 
1029
/**************************************
 
1030
 *
 
1031
 *      I S C _ e v e n t _ p o s t     ( V M S )
 
1032
 *
 
1033
 **************************************
 
1034
 *
 
1035
 * Functional description
 
1036
 *      Post an event to wake somebody else up.
 
1037
 *
 
1038
 **************************************/
 
1039
        ++event->event_count;
 
1040
        ISC_wake(event->event_pid);
 
1041
 
 
1042
        return 0;
 
1043
}
 
1044
 
 
1045
 
 
1046
int ISC_event_wait(
 
1047
                                   SSHORT count,
 
1048
                                   event_t** events,
 
1049
                                   SLONG * values,
 
1050
                                   SLONG micro_seconds,
 
1051
                                   FPTR_VOID_PTR timeout_handler, void *handler_arg)
 
1052
{
 
1053
/**************************************
 
1054
 *
 
1055
 *      I S C _ e v e n t _ w a i t     ( V M S )
 
1056
 *
 
1057
 **************************************
 
1058
 *
 
1059
 * Functional description
 
1060
 *      Wait on an event.
 
1061
 *
 
1062
 **************************************/
 
1063
        if (!ISC_event_blocked(count, events, values))
 
1064
                return 0;
 
1065
 
 
1066
        WAIT wait;
 
1067
        wait.wait_count = count;
 
1068
        wait.wait_events = events;
 
1069
        wait.wait_values = values;
 
1070
        gds__thread_wait(event_test, &wait);
 
1071
 
 
1072
        return 0;
 
1073
}
 
1074
#endif
 
1075
 
 
1076
 
 
1077
#ifdef WIN_NT
 
1078
 
 
1079
#define EVENTS
 
1080
int ISC_event_blocked(USHORT count, event_t** events, SLONG * values)
 
1081
{
 
1082
/**************************************
 
1083
 *
 
1084
 *      I S C _ e v e n t _ b l o c k e d       ( W I N _ N T )
 
1085
 *
 
1086
 **************************************
 
1087
 *
 
1088
 * Functional description
 
1089
 *      If a wait would block, return TRUE.
 
1090
 *
 
1091
 **************************************/
 
1092
 
 
1093
        for (; count > 0; --count, ++events, ++values)
 
1094
        {
 
1095
                const event_t* pEvent = *events;
 
1096
                if (pEvent->event_shared) {
 
1097
                        pEvent = pEvent->event_shared;
 
1098
                }
 
1099
                if (pEvent->event_count >= *values) {
 
1100
                        return FALSE;
 
1101
                }
 
1102
        }
 
1103
        return TRUE;
 
1104
}
 
1105
 
 
1106
 
 
1107
SLONG ISC_event_clear(event_t* event)
 
1108
{
 
1109
/**************************************
 
1110
 *
 
1111
 *      I S C _ e v e n t _ c l e a r   ( W I N _ N T )
 
1112
 *
 
1113
 **************************************
 
1114
 *
 
1115
 * Functional description
 
1116
 *      Clear an event preparatory to waiting on it.  The order of
 
1117
 *      battle for event synchronization is:
 
1118
 *
 
1119
 *          1.  Clear event.
 
1120
 *          2.  Test data structure for event already completed
 
1121
 *          3.  Wait on event.
 
1122
 *
 
1123
 **************************************/
 
1124
 
 
1125
        ResetEvent((HANDLE) event->event_handle);
 
1126
 
 
1127
        const event_t* pEvent = event;
 
1128
        if (pEvent->event_shared) {
 
1129
                pEvent = pEvent->event_shared;
 
1130
        }
 
1131
        return pEvent->event_count + 1;
 
1132
}
 
1133
 
 
1134
 
 
1135
void ISC_event_fini(event_t* event)
 
1136
{
 
1137
/**************************************
 
1138
 *
 
1139
 *      I S C _ e v e n t _ f i n i     ( W I N _ N T )
 
1140
 *
 
1141
 **************************************
 
1142
 *
 
1143
 * Functional description
 
1144
 *      Discard an event object.
 
1145
 *
 
1146
 **************************************/
 
1147
 
 
1148
        CloseHandle((HANDLE) event->event_handle);
 
1149
}
 
1150
 
 
1151
 
 
1152
int ISC_event_init(event_t* event, int type, int semnum)
 
1153
{
 
1154
/**************************************
 
1155
 *
 
1156
 *      I S C _ e v e n t _ i n i t     ( W I N _ N T )
 
1157
 *
 
1158
 **************************************
 
1159
 *
 
1160
 * Functional description
 
1161
 *      Prepare an event object for use.
 
1162
 *
 
1163
 **************************************/
 
1164
 
 
1165
        event->event_pid = process_id = getpid();
 
1166
        event->event_count = 0;
 
1167
        event->event_type = type;
 
1168
        event->event_shared = NULL;
 
1169
 
 
1170
        event->event_handle = ISC_make_signal(true, true, process_id, type);
 
1171
 
 
1172
        return (event->event_handle) ? TRUE : FALSE;
 
1173
}
 
1174
 
 
1175
 
 
1176
int ISC_event_init_shared(
 
1177
        event_t* lcl_event,
 
1178
        int type,
 
1179
        const TEXT* name,
 
1180
        event_t* shr_event,
 
1181
        bool init_flag)
 
1182
{
 
1183
/**************************************
 
1184
 *
 
1185
 *      I S C _ e v e n t _ i n i t _ s h a r e d       ( W I N _ N T )
 
1186
 *
 
1187
 **************************************
 
1188
 *
 
1189
 * Functional description
 
1190
 *      Prepare an event object for use.
 
1191
 *
 
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;
 
1197
 
 
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);
 
1201
        if (!
 
1202
                (lcl_event->event_handle =
 
1203
                 CreateEvent(ISC_get_security_desc(), TRUE, FALSE,
 
1204
                                         event_name)))
 
1205
        {
 
1206
                return FALSE;
 
1207
        }
 
1208
 
 
1209
        if (init_flag) {
 
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;
 
1215
        }
 
1216
 
 
1217
        return TRUE;
 
1218
}
 
1219
 
 
1220
 
 
1221
int ISC_event_post(event_t* event)
 
1222
{
 
1223
/**************************************
 
1224
 *
 
1225
 *      I S C _ e v e n t _ p o s t     ( W I N _ N T )
 
1226
 *
 
1227
 **************************************
 
1228
 *
 
1229
 * Functional description
 
1230
 *      Post an event to wake somebody else up.
 
1231
 *
 
1232
 **************************************/
 
1233
 
 
1234
        if (!event->event_shared)
 
1235
                ++event->event_count;
 
1236
        else
 
1237
                ++event->event_shared->event_count;
 
1238
 
 
1239
        if (event->event_pid != process_id)
 
1240
                ISC_kill(event->event_pid, event->event_type, event->event_handle);
 
1241
        else
 
1242
                SetEvent((HANDLE) event->event_handle);
 
1243
 
 
1244
        return 0;
 
1245
}
 
1246
 
 
1247
 
 
1248
int ISC_event_wait(SSHORT count,
 
1249
                                        event_t** events,
 
1250
                                        SLONG* values,
 
1251
                                        SLONG micro_seconds,
 
1252
                                        FPTR_VOID_PTR timeout_handler,
 
1253
                                        void* handler_arg)
 
1254
{
 
1255
/**************************************
 
1256
 *
 
1257
 *      I S C _ e v e n t _ w a i t     ( W I N _ N T )
 
1258
 *
 
1259
 **************************************
 
1260
 *
 
1261
 * Functional description
 
1262
 *      Wait on an event.
 
1263
 *
 
1264
 **************************************/
 
1265
        /* If we're not blocked, the rest is a gross waste of time */
 
1266
 
 
1267
        if (!ISC_event_blocked(count, events, values)) {
 
1268
                return 0;
 
1269
        }
 
1270
 
 
1271
#pragma FB_COMPILER_MESSAGE("Warning: B.O. with more than 16 handles")
 
1272
 
 
1273
        HANDLE handles[16];
 
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;
 
1278
        }
 
1279
 
 
1280
        /* Go into wait loop */
 
1281
 
 
1282
        const DWORD timeout = (micro_seconds > 0) ? micro_seconds / 1000 : INFINITE;
 
1283
 
 
1284
        for (;;) {
 
1285
                if (!ISC_event_blocked(count, events, values)) {
 
1286
                        return 0;
 
1287
                }
 
1288
 
 
1289
                const DWORD status =
 
1290
                        WaitForMultipleObjects((DWORD) count, handles, TRUE, timeout);
 
1291
 
 
1292
                if (!((status >= WAIT_OBJECT_0) && (status < WAIT_OBJECT_0 + (DWORD) count)))
 
1293
                {
 
1294
                        return status;
 
1295
                }
 
1296
        }
 
1297
}
 
1298
 
 
1299
#endif // WIN_NT
 
1300
 
 
1301
 
 
1302
#ifndef REQUESTER
 
1303
#ifndef EVENTS
 
1304
int ISC_event_blocked(USHORT count, event_t** events, SLONG * values)
 
1305
{
 
1306
/**************************************
 
1307
 *
 
1308
 *      I S C _ e v e n t _ b l o c k e d       ( G E N E R I C )
 
1309
 *
 
1310
 **************************************
 
1311
 *
 
1312
 * Functional description
 
1313
 *      If a wait would block, return TRUE.
 
1314
 *
 
1315
 **************************************/
 
1316
        return 0;
 
1317
}
 
1318
 
 
1319
 
 
1320
SLONG ISC_event_clear(event_t* event)
 
1321
{
 
1322
/**************************************
 
1323
 *
 
1324
 *      I S C _ e v e n t _ c l e a r   ( G E N E R I C )
 
1325
 *
 
1326
 **************************************
 
1327
 *
 
1328
 * Functional description
 
1329
 *      Clear an event preparatory to waiting on it.  The order of
 
1330
 *      battle for event synchronization is:
 
1331
 *
 
1332
 *          1.  Clear event.
 
1333
 *          2.  Test data structure for event already completed
 
1334
 *          3.  Wait on event.
 
1335
 *
 
1336
 **************************************/
 
1337
 
 
1338
        return 0L;
 
1339
}
 
1340
 
 
1341
 
 
1342
int ISC_event_init(event_t* event, int semid, int semnum)
 
1343
{
 
1344
/**************************************
 
1345
 *
 
1346
 *      I S C _ e v e n t _ i n i t     ( G E N E R I C )
 
1347
 *
 
1348
 **************************************
 
1349
 *
 
1350
 * Functional description
 
1351
 *      Prepare an event object for use.  Return FALSE if not
 
1352
 *      supported.
 
1353
 *
 
1354
 **************************************/
 
1355
 
 
1356
        return FALSE;
 
1357
}
 
1358
 
 
1359
 
 
1360
int ISC_event_post(event_t* event)
 
1361
{
 
1362
/**************************************
 
1363
 *
 
1364
 *      I S C _ e v e n t _ p o s t     ( G E N E R I C )
 
1365
 *
 
1366
 **************************************
 
1367
 *
 
1368
 * Functional description
 
1369
 *      Post an event to wake somebody else up.
 
1370
 *
 
1371
 **************************************/
 
1372
 
 
1373
        return 0;
 
1374
}
 
1375
 
 
1376
 
 
1377
int ISC_event_wait(SSHORT count,
 
1378
                                        event_t** events,
 
1379
                                        SLONG * values,
 
1380
                                        SLONG micro_seconds,
 
1381
                                        FPTR_VOID_PTR timeout_handler, 
 
1382
                                        void *handler_arg)
 
1383
{
 
1384
/**************************************
 
1385
 *
 
1386
 *      I S C _ e v e n t _ w a i t     ( G E N E R I C )
 
1387
 *
 
1388
 **************************************
 
1389
 *
 
1390
 * Functional description
 
1391
 *      Wait on an event.
 
1392
 *
 
1393
 **************************************/
 
1394
 
 
1395
        return 0;
 
1396
}
 
1397
#endif
 
1398
#endif
 
1399
 
 
1400
 
 
1401
#ifdef SUPERSERVER
 
1402
#ifdef UNIX
 
1403
void ISC_exception_post(ULONG sig_num, const TEXT* err_msg)
 
1404
{
 
1405
/**************************************
 
1406
 *
 
1407
 *      I S C _ e x c e p t i o n _ p o s t ( U N I X )
 
1408
 *
 
1409
 **************************************
 
1410
 *
 
1411
 * Functional description
 
1412
 *     When we got a sync exception, fomulate the error code
 
1413
 *     write it to the log file, and abort.
 
1414
 *
 
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.
 
1420
 *
 
1421
 **************************************/
 
1422
        if (!SCH_thread_enter_check())
 
1423
                THREAD_ENTER();
 
1424
 
 
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.
 
1428
        if (!err_msg)
 
1429
        {
 
1430
                err_msg = "";
 
1431
        }
 
1432
 
 
1433
        TEXT* log_msg = (TEXT *) gds__alloc(strlen(err_msg) + 256);
 
1434
        // NOMEM: crash!
 
1435
        log_msg[0] = '\0';
 
1436
 
 
1437
        switch (sig_num) {
 
1438
        case SIGSEGV:
 
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);
 
1444
                break;
 
1445
        case SIGBUS:
 
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);
 
1450
                break;
 
1451
        case SIGILL:
 
1452
 
 
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);
 
1458
                break;
 
1459
 
 
1460
        case SIGFPE:
 
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);
 
1466
                break;
 
1467
        default:
 
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);
 
1472
                break;
 
1473
        }
 
1474
 
 
1475
        if (err_msg) {
 
1476
                gds__log(log_msg);
 
1477
                gds__free(log_msg);
 
1478
        }
 
1479
        abort();
 
1480
}
 
1481
#endif /* UNIX */
 
1482
 
 
1483
 
 
1484
#ifdef WIN_NT
 
1485
ULONG ISC_exception_post(ULONG except_code, const TEXT* err_msg)
 
1486
{
 
1487
/**************************************
 
1488
 *
 
1489
 *      I S C _ e x c e p t i o n _ p o s t ( W I N _ N T )
 
1490
 *
 
1491
 **************************************
 
1492
 *
 
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).
 
1500
 *
 
1501
 **************************************/
 
1502
        ULONG result = 0;
 
1503
        bool is_critical = true;
 
1504
        
 
1505
        if (!SCH_thread_enter_check ())
 
1506
        {
 
1507
                THREAD_ENTER();
 
1508
        }
 
1509
 
 
1510
        thread_db* tdbb = JRD_get_thread_data();
 
1511
 
 
1512
        if (!err_msg)
 
1513
        {
 
1514
                err_msg = "";
 
1515
        }
 
1516
 
 
1517
        TEXT* log_msg = (TEXT*) gds__alloc(strlen(err_msg) + 256);
 
1518
        // NOMEM: crash!
 
1519
        log_msg[0] = '\0';
 
1520
 
 
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);
 
1528
                break;
 
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);
 
1535
                break;
 
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);
 
1542
                break;
 
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"
 
1547
                                "\t\tvalue.\n"
 
1548
                                "\tThis exception will cause the Firebird server\n"
 
1549
                                "\tto terminate abnormally.", err_msg);
 
1550
                break;
 
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);
 
1557
                break;
 
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);
 
1564
                break;
 
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);
 
1571
                break;
 
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);
 
1578
                break;
 
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);
 
1585
                break;
 
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);
 
1592
                break;
 
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);
 
1599
                break;
 
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);
 
1606
                break;
 
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;
 
1612
                break;
 
1613
 
 
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;
 
1627
                break;
 
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;
 
1634
                break;
 
1635
        default:
 
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);
 
1640
                break; 
 
1641
        }
 
1642
 
 
1643
        if (is_critical)
 
1644
        {
 
1645
                gds__log(log_msg);
 
1646
        }
 
1647
 
 
1648
        gds__free(log_msg);
 
1649
 
 
1650
        if (is_critical)
 
1651
        {
 
1652
                if (Config::getBugcheckAbort()) {
 
1653
                        // Pass exception to outer handler in case debugger is present to collect memory dump
 
1654
                        return EXCEPTION_CONTINUE_SEARCH;
 
1655
                }
 
1656
                else {
 
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.
 
1663
                        exit(3);
 
1664
                }
 
1665
        }
 
1666
        else
 
1667
        {
 
1668
                return result;
 
1669
        }
 
1670
}
 
1671
 
 
1672
#endif /* WIN_NT */
 
1673
#endif /* SUPERSERVER */
 
1674
 
 
1675
 
 
1676
#ifdef WIN_NT
 
1677
void *ISC_make_signal(
 
1678
          bool create_flag,
 
1679
          bool manual_reset,
 
1680
          int process_idL,
 
1681
          int signal_number)
 
1682
{
 
1683
/**************************************
 
1684
 *
 
1685
 *      I S C _ m a k e _ s i g n a l           ( W I N _ N T )
 
1686
 *
 
1687
 **************************************
 
1688
 *
 
1689
 * Functional description
 
1690
 *      Create or open a Windows/NT event.
 
1691
 *      Use the signal number and process id
 
1692
 *      in naming the object.
 
1693
 *
 
1694
 **************************************/
 
1695
 
 
1696
        const BOOLEAN man_rst = manual_reset ? TRUE : FALSE;
 
1697
        
 
1698
        if (!signal_number)
 
1699
                return CreateEvent(NULL, man_rst, FALSE, NULL);
 
1700
 
 
1701
        TEXT event_name[64];
 
1702
        sprintf(event_name, "_firebird_process%u_signal%d", process_idL, signal_number);
 
1703
 
 
1704
        HANDLE hEvent;
 
1705
        if (create_flag) {
 
1706
                hEvent = CreateEvent(ISC_get_security_desc(), man_rst, FALSE, event_name);
 
1707
        }
 
1708
        else {
 
1709
                hEvent = OpenEvent(EVENT_ALL_ACCESS, TRUE, event_name);
 
1710
        }
 
1711
        return hEvent;
 
1712
}
 
1713
#endif
 
1714
 
 
1715
 
 
1716
#ifdef VMS
 
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)
 
1722
{
 
1723
/**************************************
 
1724
 *
 
1725
 *      I S C _ m a p _ f i l e         ( V M S )
 
1726
 *
 
1727
 **************************************
 
1728
 *
 
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).
 
1733
 *
 
1734
 **************************************/
 
1735
        if (length < 0)
 
1736
                length = -length;
 
1737
 
 
1738
        if (length == 0) {
 
1739
                /* Must be able to handle case where zero length passed in. */
 
1740
 
 
1741
                fprintf(stderr, "Unimplemented feature in ISC_map_file.\n");
 
1742
                abort();
 
1743
        }
 
1744
 
 
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)));
 
1749
 
 
1750
/* Find section name */
 
1751
 
 
1752
        const TEXT* q = expanded_filename;
 
1753
        TEXT* p;
 
1754
 
 
1755
        for (p = expanded_filename; *p; p++)
 
1756
                if (*p == ':' || *p == ']')
 
1757
                        q = p + 1;
 
1758
 
 
1759
        TEXT section[64];
 
1760
        for (p = section; *q && *q != '.';)
 
1761
                *p++ = *q++;
 
1762
 
 
1763
        *p = 0;
 
1764
 
 
1765
/* Setup to open the file */
 
1766
 
 
1767
        struct FAB fab;
 
1768
        fab = cc$rms_fab;
 
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;
 
1776
 
 
1777
/* Setup to create or map the file */
 
1778
 
 
1779
        SLONG inadr[2];
 
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);
 
1785
 
 
1786
        ISC_STATUS status;
 
1787
        struct XABPRO xab;
 
1788
        SLONG retadr[2];
 
1789
        
 
1790
        if (init_routine) {
 
1791
                /* If we're a server, start by opening file.
 
1792
                   If we can't open it, create it. */
 
1793
 
 
1794
                status = sys$open(&fab);
 
1795
 
 
1796
                if (!(status & 1)) {
 
1797
                        fab.fab$l_xab = &xab;
 
1798
                        xab = cc$rms_xabpro;
 
1799
                        xab.xab$w_pro =
 
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);
 
1803
 
 
1804
                        status = sys$create(&fab);
 
1805
 
 
1806
                        if (!(status & 1)) {
 
1807
                                error(status_vector, "sys$create", status);
 
1808
                                return NULL;
 
1809
                        }
 
1810
                }
 
1811
 
 
1812
                /* Create and map section */
 
1813
 
 
1814
                status = sys$crmpsc(inadr, retadr, 0,   /* acmode */
 
1815
                                                        flags,  /* flags */
 
1816
                                                        &desc,  /* gsdnam */
 
1817
                                                        0,      /* ident */
 
1818
                                                        0,      /* relpag */
 
1819
                                                        fab.fab$l_stv,  /* chan */
 
1820
                                                        length / 512, 0,        /* vbm */
 
1821
                                                        0,      /* prot */
 
1822
                                                        0);     /* pfc */
 
1823
 
 
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);
 
1829
                        return NULL;
 
1830
                }
 
1831
        }
 
1832
        else {
 
1833
                /* We're not a server, just map the global section */
 
1834
 
 
1835
                status = sys$mgblsc(inadr, retadr, 0,   /* acmode */
 
1836
                                                        flags,  /* flags */
 
1837
                                                        &desc,  /* gsdnam */
 
1838
                                                        0,      /* ident */
 
1839
                                                        0);     /* relpag */
 
1840
 
 
1841
                if (!(status & 1)) {
 
1842
                        error(status_vector, "sys$mgblsc", status);
 
1843
                        return NULL;
 
1844
                }
 
1845
        }
 
1846
 
 
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);
 
1853
        if (init_routine)
 
1854
                (*init_routine) (init_arg, shmem_data, status == SS$_CREATED);
 
1855
 
 
1856
        return (UCHAR *) retadr[0];
 
1857
}
 
1858
#endif
 
1859
 
 
1860
 
 
1861
#ifdef UNIX
 
1862
#ifdef HAVE_MMAP
 
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)
 
1868
{
 
1869
/**************************************
 
1870
 *
 
1871
 *      I S C _ m a p _ f i l e         ( U N I X - m m a p )
 
1872
 *
 
1873
 **************************************
 
1874
 *
 
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).
 
1879
 *
 
1880
 **************************************/
 
1881
        TEXT expanded_filename[MAXPATHLEN], hostname[64];
 
1882
        sprintf(expanded_filename, filename,
 
1883
                        ISC_get_host(hostname, sizeof(hostname)));
 
1884
 
 
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*/
 
1889
 
 
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! */
 
1895
 
 
1896
        const int oldmask = umask(0);
 
1897
        bool trunc_flag = true;
 
1898
        if (length < 0) {
 
1899
                length = -length;
 
1900
                trunc_flag = false;
 
1901
        }
 
1902
 
 
1903
/* Produce shared memory key for file */
 
1904
 
 
1905
        SLONG key;
 
1906
        if (!(key = find_key(status_vector, expanded_filename))) {
 
1907
                umask(oldmask);
 
1908
                return NULL;
 
1909
        }
 
1910
 
 
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);
 
1916
                return NULL;
 
1917
        }
 
1918
 
 
1919
#ifndef HAVE_FLOCK
 
1920
        struct flock lock;
 
1921
/* get an exclusive lock on the INIT file with a block */
 
1922
        lock.l_type = F_WRLCK;
 
1923
        lock.l_whence = 0;
 
1924
        lock.l_start = 0;
 
1925
        lock.l_len = 0;
 
1926
        if (fcntl(fd_init, F_SETLKW, &lock) == -1) {
 
1927
                error(status_vector, "fcntl", errno);
 
1928
                close(fd_init);
 
1929
                return NULL;
 
1930
        }
 
1931
#else
 
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);
 
1936
                close(fd_init);
 
1937
                return NULL;
 
1938
        }
 
1939
#endif
 
1940
/* open the file to be inited */
 
1941
        int fd = open(expanded_filename, O_RDWR | O_CREAT, 0666);
 
1942
        umask(oldmask);
 
1943
 
 
1944
        if (fd == -1) {
 
1945
                error(status_vector, "open", errno);
 
1946
#ifdef HAVE_FLOCK
 
1947
                /* unlock init file */
 
1948
                flock(fd_init, LOCK_UN);
 
1949
#else
 
1950
                lock.l_type = F_UNLCK;
 
1951
                lock.l_whence = 0;
 
1952
                lock.l_start = 0;
 
1953
                lock.l_len = 0;
 
1954
                fcntl(fd_init, F_SETLK, &lock);
 
1955
#endif
 
1956
                close(fd_init);
 
1957
                return NULL;
 
1958
        }
 
1959
 
 
1960
        if (length == 0) {
 
1961
                /* Get and use the existing length of the shared segment */
 
1962
 
 
1963
                struct stat file_stat;
 
1964
                if (fstat(fd, &file_stat) == -1) {
 
1965
                        error(status_vector, "fstat", errno);
 
1966
                        close(fd);
 
1967
#ifdef HAVE_FLOCK
 
1968
                        /* unlock init file */
 
1969
                        flock(fd_init, LOCK_UN);
 
1970
#else
 
1971
                        lock.l_type = F_UNLCK;
 
1972
                        lock.l_whence = 0;
 
1973
                        lock.l_start = 0;
 
1974
                        lock.l_len = 0;
 
1975
                        fcntl(fd_init, F_SETLK, &lock);
 
1976
#endif
 
1977
                        close(fd_init);         /* while we are at it close the init file also */
 
1978
                        return NULL;
 
1979
                }
 
1980
                length = file_stat.st_size;
 
1981
        }
 
1982
 
 
1983
 
 
1984
        UCHAR* address =
 
1985
                (UCHAR *) mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
 
1986
 
 
1987
        if ((U_IPTR) address == (U_IPTR) -1) {
 
1988
                error(status_vector, "mmap", errno);
 
1989
                close(fd);
 
1990
#ifdef HAVE_FLOCK
 
1991
                /* unlock init file */
 
1992
                flock(fd_init, LOCK_UN);
 
1993
#else
 
1994
                lock.l_type = F_UNLCK;
 
1995
                lock.l_whence = 0;
 
1996
                lock.l_start = 0;
 
1997
                lock.l_len = 0;
 
1998
                fcntl(fd_init, F_SETLK, &lock);
 
1999
#endif
 
2000
 
 
2001
                close(fd_init);
 
2002
                return NULL;
 
2003
        }
 
2004
 
 
2005
/* Get semaphore for mutex */
 
2006
 
 
2007
        shmem_data->sh_mem_address = address;
 
2008
        shmem_data->sh_mem_length_mapped = length;
 
2009
 
 
2010
 
 
2011
        shmem_data->sh_mem_handle = fd;
 
2012
 
 
2013
/* Try to get an exclusive lock on the lock file.  This will
 
2014
   fail if somebody else has the exclusive lock */
 
2015
 
 
2016
#ifdef HAVE_FLOCK
 
2017
        if (!flock(fd, LOCK_EX | LOCK_NB))
 
2018
        {
 
2019
                if (!init_routine) {
 
2020
                        /* unlock both files */
 
2021
                        flock(fd, LOCK_UN);
 
2022
                        flock(fd_init, LOCK_UN);
 
2023
#else
 
2024
        lock.l_type = F_WRLCK;
 
2025
        lock.l_whence = 0;
 
2026
        lock.l_start = 0;
 
2027
        lock.l_len = 0;
 
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;
 
2032
                        lock.l_whence = 0;
 
2033
                        lock.l_start = 0;
 
2034
                        lock.l_len = 0;
 
2035
                        fcntl(fd, F_SETLK, &lock);
 
2036
 
 
2037
                        lock.l_type = F_UNLCK;
 
2038
                        lock.l_whence = 0;
 
2039
                        lock.l_start = 0;
 
2040
                        lock.l_len = 0;
 
2041
                        fcntl(fd_init, F_SETLK, &lock);
 
2042
#endif
 
2043
                        munmap((char *) address, length);
 
2044
                        close(fd);
 
2045
                        close(fd_init);
 
2046
                        *status_vector++ = isc_arg_gds;
 
2047
                        *status_vector++ = isc_unavailable;
 
2048
                        *status_vector++ = isc_arg_end;
 
2049
                        return NULL;
 
2050
                }
 
2051
 
 
2052
                // Create semaphores here
 
2053
#if !(defined SOLARIS_MT || defined USE_POSIX_THREADS)
 
2054
                SLONG semid;
 
2055
                if (shmem_data->sh_mem_semaphores &&
 
2056
                        (semid =
 
2057
                         create_semaphores(status_vector, key,
 
2058
                                                         shmem_data->sh_mem_semaphores)) < 0)
 
2059
                {
 
2060
#ifdef HAVE_FLOCK
 
2061
                        /* unlock both files */
 
2062
                        flock(fd, LOCK_UN);
 
2063
                        flock(fd_init, LOCK_UN);
 
2064
#else
 
2065
                        /* unlock the file and the init file to release the other process */
 
2066
                        lock.l_type = F_UNLCK;
 
2067
                        lock.l_whence = 0;
 
2068
                        lock.l_start = 0;
 
2069
                        lock.l_len = 0;
 
2070
                        fcntl(fd, F_SETLK, &lock);
 
2071
 
 
2072
                        lock.l_type = F_UNLCK;
 
2073
                        lock.l_whence = 0;
 
2074
                        lock.l_start = 0;
 
2075
                        lock.l_len = 0;
 
2076
                        fcntl(fd_init, F_SETLK, &lock);
 
2077
#endif
 
2078
                        munmap((char *) address, length);
 
2079
                        close(fd);
 
2080
                        close(fd_init);
 
2081
                        return NULL;
 
2082
                }
 
2083
                shmem_data->sh_mem_mutex_arg = semid;
 
2084
#else
 
2085
                shmem_data->sh_mem_mutex_arg = 0;
 
2086
#endif
 
2087
 
 
2088
                if (trunc_flag)
 
2089
                        ftruncate(fd, length);
 
2090
                (*init_routine) (init_arg, shmem_data, true);
 
2091
#ifdef HAVE_FLOCK
 
2092
                if (flock(fd, LOCK_SH)) {
 
2093
                        error(status_vector, "flock", errno);
 
2094
                        flock(fd, LOCK_UN);
 
2095
                        flock(fd_init, LOCK_UN);
 
2096
#else
 
2097
                lock.l_type = F_RDLCK;
 
2098
                lock.l_whence = 0;
 
2099
                lock.l_start = 0;
 
2100
                lock.l_len = 0;
 
2101
                if (fcntl(fd, F_SETLK, &lock) == -1)
 
2102
                {
 
2103
                        error(status_vector, "fcntl", errno);
 
2104
                        /* unlock the file */
 
2105
                        lock.l_type = F_UNLCK;
 
2106
                        lock.l_whence = 0;
 
2107
                        lock.l_start = 0;
 
2108
                        lock.l_len = 0;
 
2109
                        fcntl(fd, F_SETLK, &lock);
 
2110
 
 
2111
                        /* unlock the init file to release the other process */
 
2112
                        lock.l_type = F_UNLCK;
 
2113
                        lock.l_whence = 0;
 
2114
                        lock.l_start = 0;
 
2115
                        lock.l_len = 0;
 
2116
                        fcntl(fd_init, F_SETLK, &lock);
 
2117
#endif
 
2118
                        munmap((char *) address, length);
 
2119
 
 
2120
                        close(fd_init);
 
2121
                        close(fd);
 
2122
                        return NULL;
 
2123
                }
 
2124
        }
 
2125
        else {
 
2126
#ifdef HAVE_FLOCK
 
2127
                if (flock(fd, LOCK_SH)) {
 
2128
                        error(status_vector, "flock", errno);
 
2129
                        flock(fd, LOCK_UN);
 
2130
                        flock(fd_init, LOCK_UN);
 
2131
#else
 
2132
                lock.l_type = F_RDLCK;
 
2133
                lock.l_whence = 0;
 
2134
                lock.l_start = 0;
 
2135
                lock.l_len = 0;
 
2136
                if (fcntl(fd, F_SETLK, &lock) == -1) {
 
2137
                        error(status_vector, "fcntl", errno);
 
2138
                        /* unlock the file */
 
2139
                        lock.l_type = F_UNLCK;
 
2140
                        lock.l_whence = 0;
 
2141
                        lock.l_start = 0;
 
2142
                        lock.l_len = 0;
 
2143
                        fcntl(fd, F_SETLK, &lock);
 
2144
 
 
2145
                        /* unlock the init file to release the other process */
 
2146
                        lock.l_type = F_UNLCK;
 
2147
                        lock.l_whence = 0;
 
2148
                        lock.l_start = 0;
 
2149
                        lock.l_len = 0;
 
2150
                        fcntl(fd_init, F_SETLK, &lock);
 
2151
#endif
 
2152
                        munmap((char *) address, length);
 
2153
                        close(fd_init);
 
2154
                        close(fd);
 
2155
                        return NULL;
 
2156
                }
 
2157
                // Open semaphores here
 
2158
#if !(defined SOLARIS_MT || defined USE_POSIX_THREADS)
 
2159
                SLONG semid;
 
2160
                if (shmem_data->sh_mem_semaphores &&
 
2161
                        (semid =
 
2162
                         open_semaphores(status_vector, key,
 
2163
                                                         shmem_data->sh_mem_semaphores)) < 0)
 
2164
                {
 
2165
#ifdef HAVE_FLOCK
 
2166
                        /* unlock both files */
 
2167
                        flock(fd, LOCK_UN);
 
2168
                        flock(fd_init, LOCK_UN);
 
2169
#else
 
2170
                        /* unlock the file and the init file to release the other process */
 
2171
                        lock.l_type = F_UNLCK;
 
2172
                        lock.l_whence = 0;
 
2173
                        lock.l_start = 0;
 
2174
                        lock.l_len = 0;
 
2175
                        fcntl(fd, F_SETLK, &lock);
 
2176
 
 
2177
                        lock.l_type = F_UNLCK;
 
2178
                        lock.l_whence = 0;
 
2179
                        lock.l_start = 0;
 
2180
                        lock.l_len = 0;
 
2181
                        fcntl(fd_init, F_SETLK, &lock);
 
2182
#endif
 
2183
                        munmap((char *) address, length);
 
2184
                        close(fd);
 
2185
                        close(fd_init);
 
2186
                        return NULL;
 
2187
                }
 
2188
                shmem_data->sh_mem_mutex_arg = semid;
 
2189
#else
 
2190
                shmem_data->sh_mem_mutex_arg = 0;
 
2191
#endif
 
2192
                if (init_routine)
 
2193
                        (*init_routine) (init_arg, shmem_data, false);
 
2194
        }
 
2195
 
 
2196
#ifdef HAVE_FLOCK
 
2197
/* unlock the init file to release the other process */
 
2198
        flock(fd_init, LOCK_UN);
 
2199
#else
 
2200
/* unlock the init file to release the other process */
 
2201
        lock.l_type = F_UNLCK;
 
2202
        lock.l_whence = 0;
 
2203
        lock.l_start = 0;
 
2204
        lock.l_len = 0;
 
2205
        fcntl(fd_init, F_SETLK, &lock);
 
2206
#endif
 
2207
/* close the init file_decriptor */
 
2208
        close(fd_init);
 
2209
        return address;
 
2210
}
 
2211
#endif
 
2212
#endif
 
2213
 
 
2214
 
 
2215
#ifdef UNIX
 
2216
#ifndef HAVE_MMAP
 
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)
 
2222
{
 
2223
/**************************************
 
2224
 *
 
2225
 *      I S C _ m a p _ f i l e         ( U N I X - s h m a t )
 
2226
 *
 
2227
 **************************************
 
2228
 *
 
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).
 
2233
 *
 
2234
 **************************************/
 
2235
        //SSHORT count;
 
2236
        TEXT expanded_filename[512];
 
2237
#ifdef NOHOSTNAME
 
2238
        strcpy(expanded_filename, filename);
 
2239
#else
 
2240
        TEXT hostname[64];
 
2241
        sprintf(expanded_filename, filename,
 
2242
                        ISC_get_host(hostname, sizeof(hostname)));
 
2243
#endif
 
2244
        const int oldmask = umask(0);
 
2245
        bool init_flag = false;
 
2246
        if (length < 0)
 
2247
                length = -length;
 
2248
 
 
2249
/* Produce shared memory key for file */
 
2250
 
 
2251
        const SLONG key = find_key(status_vector, expanded_filename);
 
2252
        if (!key) {
 
2253
                umask(oldmask);
 
2254
                return NULL;
 
2255
        }
 
2256
 
 
2257
/* Write shared memory key into expanded_filename file */
 
2258
 
 
2259
        FILE* fp = fopen(expanded_filename, "w");
 
2260
        umask(oldmask);
 
2261
 
 
2262
        if (!fp) {
 
2263
                error(status_vector, "fopen", errno);
 
2264
                return NULL;
 
2265
        }
 
2266
 
 
2267
        fprintf(fp, "%ld", key);
 
2268
 
 
2269
/* Get an exclusive lock on the file until the initialization process
 
2270
   is complete.  That way potential race conditions are avoided. */
 
2271
 
 
2272
#ifndef HAVE_FLOCK
 
2273
        if (lockf(fileno(fp), F_LOCK, 0)) {
 
2274
                error(status_vector, "lockf", errno);
 
2275
#else
 
2276
        if (flock(fileno(fp), LOCK_EX)) {
 
2277
                error(status_vector, "flock", errno);
 
2278
#endif
 
2279
                fclose(fp);
 
2280
                return NULL;
 
2281
        }
 
2282
 
 
2283
/* Create the shared memory region if it doesn't already exist. */
 
2284
 
 
2285
        struct shmid_ds buf;
 
2286
        SLONG shmid;
 
2287
        if ((shmid = shmget(key, length, IPC_CREAT | PRIV)) == -1)
 
2288
#ifdef SUPERSERVER
 
2289
                if (errno == EINVAL) {
 
2290
                        /* There are two cases when shmget() returns EINVAL error:
 
2291
 
 
2292
                           - "length" is less than the system-imposed minimum or
 
2293
                           greater than the system-imposed maximum.
 
2294
 
 
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.
 
2298
 
 
2299
                           Let's find out what the problem is by getting the
 
2300
                           system-imposed limits.
 
2301
                         */
 
2302
 
 
2303
#ifdef HP10
 
2304
                        struct pst_ipcinfo pst;
 
2305
 
 
2306
                        if (pstat_getipc(&pst, sizeof(struct pst_ipcinfo), 1, 0) == -1) {
 
2307
                                error(status_vector, "pstat_getipc", errno);
 
2308
                                fclose(fp);
 
2309
                                return NULL;
 
2310
                        }
 
2311
 
 
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.
 
2315
                                 */
 
2316
                                error(status_vector, "shmget", errno);
 
2317
                                fclose(fp);
 
2318
                                return NULL;
 
2319
                        }
 
2320
#endif /* HP10 */
 
2321
 
 
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.
 
2325
 
 
2326
                           Because the segment has to exist at this point the
 
2327
                           following shmget() does not have IPC_CREAT flag set.
 
2328
 
 
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
 
2332
                           length
 
2333
                         */
 
2334
                        if ((shmid = shmget(key, 0, PRIV)) == -1) {
 
2335
                                error(status_vector, "shmget", errno);
 
2336
                                fclose(fp);
 
2337
                                return NULL;
 
2338
                        }
 
2339
 
 
2340
                        if (shmctl(shmid, IPC_RMID, &buf) == -1) {
 
2341
                                error(status_vector, "shmctl/IPC_RMID", errno);
 
2342
                                fclose(fp);
 
2343
                                return NULL;
 
2344
                        }
 
2345
 
 
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
 
2351
                         */
 
2352
                        if ((shmid = shmget(key, length, IPC_CREAT | IPC_EXCL | PRIV)) ==
 
2353
                                -1)
 
2354
                        {
 
2355
                                error(status_vector, "shmget", errno);
 
2356
                                fclose(fp);
 
2357
                                return NULL;
 
2358
                        }
 
2359
                }
 
2360
                else                                    /* if errno != EINVAL) */
 
2361
#endif /* SUPERSERVER */
 
2362
                {
 
2363
                        error(status_vector, "shmget", errno);
 
2364
                        fclose(fp);
 
2365
                        return NULL;
 
2366
                }
 
2367
 
 
2368
#ifdef SUPERSERVER
 
2369
/* If we are here there are two possibilities:
 
2370
 
 
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);
 
2374
 
 
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
 
2378
   size "length".
 
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
 
2382
*/
 
2383
        if (shmctl(shmid, IPC_STAT, &buf) == -1) {
 
2384
                error(status_vector, "shmctl/IPC_STAT", errno);
 
2385
                fclose(fp);
 
2386
                return NULL;
 
2387
        }
 
2388
 
 
2389
        fb_assert(length <= buf.shm_segsz);
 
2390
        if (length < buf.shm_segsz)
 
2391
                if (length) {
 
2392
                        if (shmctl(shmid, IPC_RMID, &buf) == -1) {
 
2393
                                error(status_vector, "shmctl/IPC_RMID", errno);
 
2394
                                fclose(fp);
 
2395
                                return NULL;
 
2396
                        }
 
2397
 
 
2398
                        if ((shmid = shmget(key, length, IPC_CREAT | IPC_EXCL | PRIV)) ==
 
2399
                                -1)
 
2400
                        {
 
2401
                                error(status_vector, "shmget", errno);
 
2402
                                fclose(fp);
 
2403
                                return NULL;
 
2404
                        }
 
2405
                }
 
2406
                else {
 
2407
                        length = buf.shm_segsz;
 
2408
                        if ((shmid = shmget(key, length, PRIV)) == -1) {
 
2409
                                error(status_vector, "shmget", errno);
 
2410
                                fclose(fp);
 
2411
                                return NULL;
 
2412
                        }
 
2413
                }
 
2414
#else /* !SUPERSERVER */
 
2415
 
 
2416
        if (length == 0) {
 
2417
                /* Use the existing length.  This should not happen for the
 
2418
                   very first attachment to the shared memory.  */
 
2419
 
 
2420
                if (shmctl(shmid, IPC_STAT, &buf) == -1) {
 
2421
                        error(status_vector, "shmctl/IPC_STAT", errno);
 
2422
                        fclose(fp);
 
2423
                        return NULL;
 
2424
                }
 
2425
                length = buf.shm_segsz;
 
2426
 
 
2427
                /* Now remap with the new-found length */
 
2428
 
 
2429
                if ((shmid = shmget(key, length, PRIV)) == -1) {
 
2430
                        error(status_vector, "shmget", errno);
 
2431
                        fclose(fp);
 
2432
                        return NULL;
 
2433
                }
 
2434
        }
 
2435
#endif /* SUPERSERVER */
 
2436
 
 
2437
 
 
2438
        UCHAR* address = 0;
 
2439
#ifdef SHMEM_PICKY
 
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)
 
2444
#ifndef SYSV_SHMEM
 
2445
                next_shared_memory = address + length;
 
2446
#else
 
2447
                next_shared_memory = address + length + SHMLBA;
 
2448
#endif
 
2449
#else
 
2450
        address = (UCHAR *) shmat(shmid, NULL, 0);
 
2451
#endif
 
2452
 
 
2453
        if ((U_IPTR) address == -1) {
 
2454
                error(status_vector, "shmat", errno);
 
2455
                fclose(fp);
 
2456
                return NULL;
 
2457
        }
 
2458
 
 
2459
        if (shmctl(shmid, IPC_STAT, &buf) == -1) {
 
2460
                error(status_vector, "shmctl/IPC_STAT", errno);
 
2461
                shmdt(address);
 
2462
                next_shared_memory -= length;
 
2463
                fclose(fp);
 
2464
                return NULL;
 
2465
        }
 
2466
 
 
2467
/* Get semaphore for mutex */
 
2468
 
 
2469
 
 
2470
/* If we're the only one with shared memory mapped, see if
 
2471
   we can initialize it.  If we can't, return failure. */
 
2472
 
 
2473
        if (buf.shm_nattch == 1) {
 
2474
                if (!init_routine) {
 
2475
                        shmdt(address);
 
2476
                        next_shared_memory -= length;
 
2477
                        fclose(fp);
 
2478
                        *status_vector++ = isc_arg_gds;
 
2479
                        *status_vector++ = isc_unavailable;
 
2480
                        *status_vector++ = isc_arg_end;
 
2481
                        return NULL;
 
2482
                }
 
2483
                buf.shm_perm.mode = 0666;
 
2484
                shmctl(shmid, IPC_SET, &buf);
 
2485
                init_flag = true;
 
2486
        }
 
2487
 
 
2488
        shmem_data->sh_mem_address = address;
 
2489
        shmem_data->sh_mem_length_mapped = length;
 
2490
 
 
2491
 
 
2492
        shmem_data->sh_mem_handle = shmid;
 
2493
 
 
2494
#ifndef USE_POSIX_THREADS
 
2495
        SLONG semid;
 
2496
        if (shmem_data->sh_mem_semaphores &&
 
2497
                (semid =
 
2498
                 (init_flag ? 
 
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) 
 
2503
        {
 
2504
                shmdt(address);
 
2505
                next_shared_memory -= length;
 
2506
                fclose(fp);
 
2507
                return NULL;
 
2508
        }
 
2509
        shmem_data->sh_mem_mutex_arg = semid;
 
2510
#else
 
2511
        shmem_data->sh_mem_mutex_arg = 0;
 
2512
#endif
 
2513
 
 
2514
        if (init_routine)
 
2515
                (*init_routine) (init_arg, shmem_data, init_flag);
 
2516
 
 
2517
/* When the mapped file is closed here, the lock we applied for
 
2518
   synchronization will be released. */
 
2519
 
 
2520
        fclose(fp);
 
2521
 
 
2522
        return address;
 
2523
}
 
2524
#endif // !HAVE_MMAP
 
2525
 
 
2526
#endif // UNIX
 
2527
 
 
2528
 
 
2529
#ifdef WIN_NT
 
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,
 
2535
           void* init_arg,
 
2536
           SLONG length,
 
2537
           SH_MEM shmem_data)
 
2538
{
 
2539
/**************************************
 
2540
 *
 
2541
 *      I S C _ m a p _ f i l e         ( W I N _ N T )
 
2542
 *
 
2543
 **************************************
 
2544
 *
 
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).
 
2549
 *
 
2550
 **************************************/
 
2551
        TEXT expanded_filename[MAXPATHLEN], hostname[64];
 
2552
        TEXT map_file[MAXPATHLEN];
 
2553
        HANDLE file_handle;
 
2554
        HANDLE event_handle = 0;
 
2555
        int retry_count = 0;
 
2556
        bool init_flag = false;
 
2557
 
 
2558
/* retry to attach to mmapped file if the process initializing
 
2559
 * dies during initialization.
 
2560
 */
 
2561
 
 
2562
  retry:
 
2563
        if (retry_count++ > 0) 
 
2564
                THREAD_SLEEP(10);
 
2565
 
 
2566
        ISC_get_host(hostname, sizeof(hostname));
 
2567
        sprintf(map_file, filename, hostname);
 
2568
 
 
2569
        if (length < 0)
 
2570
                length = -length;
 
2571
 
 
2572
        file_handle = CreateFile(map_file,
 
2573
                                 GENERIC_READ | GENERIC_WRITE,
 
2574
                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
 
2575
                                 NULL,
 
2576
                                 OPEN_ALWAYS,
 
2577
                                 FILE_ATTRIBUTE_NORMAL,
 
2578
                                 NULL);
 
2579
        DWORD err = GetLastError();
 
2580
        if (file_handle == INVALID_HANDLE_VALUE) 
 
2581
        {
 
2582
                if (err == ERROR_SHARING_VIOLATION)
 
2583
                        goto retry;
 
2584
 
 
2585
                error(status_vector, "CreateFile", err);
 
2586
                return NULL;
 
2587
        }
 
2588
 
 
2589
/* Check if file already exists */
 
2590
 
 
2591
        const bool file_exists = (err == ERROR_ALREADY_EXISTS);
 
2592
 
 
2593
/* Create an event that can be used to determine if someone has already
 
2594
   initialized shared memory. */
 
2595
 
 
2596
        make_object_name(expanded_filename, sizeof(expanded_filename), filename, "_event");
 
2597
        if (!init_flag)
 
2598
        {
 
2599
                if (!ISC_is_WinNT())
 
2600
                        event_handle =
 
2601
                                CreateMutex(ISC_get_security_desc(), TRUE, expanded_filename);
 
2602
                else
 
2603
                        event_handle =
 
2604
                                CreateEvent(ISC_get_security_desc(), TRUE, FALSE,
 
2605
                                                        expanded_filename);
 
2606
                if (!event_handle) {
 
2607
                        if (!ISC_is_WinNT())
 
2608
                                error(status_vector, "CreateMutex", GetLastError());
 
2609
                        else
 
2610
                                error(status_vector, "CreateEvent", GetLastError());
 
2611
                        CloseHandle(file_handle);
 
2612
                        return NULL;
 
2613
                }
 
2614
 
 
2615
                init_flag = (GetLastError() == ERROR_ALREADY_EXISTS) ? false: true;
 
2616
 
 
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;
 
2623
                        return NULL;
 
2624
                }
 
2625
        }
 
2626
 
 
2627
        if (length == 0) {
 
2628
                /* Get and use the existing length of the shared segment */
 
2629
 
 
2630
                if ((length = GetFileSize(file_handle, NULL)) == -1) {
 
2631
                        error(status_vector, "GetFileSize", GetLastError());
 
2632
                        CloseHandle(event_handle);
 
2633
                        CloseHandle(file_handle);
 
2634
                        return NULL;
 
2635
                }
 
2636
        }
 
2637
 
 
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.
 
2642
 */
 
2643
 
 
2644
        CloseHandle(file_handle);
 
2645
 
 
2646
        if (!init_flag) {
 
2647
                /* Wait for 10 seconds.  Then retry */
 
2648
 
 
2649
                DWORD ret_event;
 
2650
                if (!ISC_is_WinNT()) {
 
2651
                        ret_event = WaitForSingleObject(event_handle, 10000);
 
2652
                        ReleaseMutex(event_handle);
 
2653
                }
 
2654
                else
 
2655
                        ret_event = WaitForSingleObject(event_handle, 10000);
 
2656
 
 
2657
                /* If we timed out, just retry.  It is possible that the
 
2658
                 * process doing the initialization died before setting the
 
2659
                 * event.
 
2660
                 */
 
2661
 
 
2662
                if (ret_event == WAIT_TIMEOUT) {
 
2663
                        CloseHandle(event_handle);
 
2664
                        if (retry_count > 10) {
 
2665
                                error(status_vector, "WaitForSingleObject", 0);
 
2666
                                return NULL;
 
2667
                        }
 
2668
                        goto retry;
 
2669
                }
 
2670
        }
 
2671
 
 
2672
        DWORD fdw_create;
 
2673
        if (init_flag && file_exists)
 
2674
                fdw_create = TRUNCATE_EXISTING;
 
2675
        else
 
2676
                fdw_create = OPEN_ALWAYS;
 
2677
 
 
2678
        file_handle = CreateFile(map_file,
 
2679
                                 GENERIC_READ | GENERIC_WRITE,
 
2680
                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
 
2681
                                 NULL,
 
2682
                                 fdw_create,
 
2683
#ifdef EMBEDDED
 
2684
                                 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
 
2685
#else
 
2686
                                 FILE_ATTRIBUTE_NORMAL,
 
2687
#endif
 
2688
                                 NULL);
 
2689
        if (file_handle == INVALID_HANDLE_VALUE)
 
2690
        {
 
2691
                const DWORD err = GetLastError();
 
2692
 
 
2693
                if ((err == ERROR_SHARING_VIOLATION) || 
 
2694
                        ((err == ERROR_FILE_NOT_FOUND || err == ERROR_USER_MAPPED_FILE) && fdw_create == TRUNCATE_EXISTING))
 
2695
                {
 
2696
                        if (!init_flag) {
 
2697
                                CloseHandle(event_handle);
 
2698
                        }
 
2699
                        goto retry;
 
2700
                }
 
2701
                
 
2702
                CloseHandle(event_handle);
 
2703
                error(status_vector, "CreateFile", err);
 
2704
                return NULL;
 
2705
        }
 
2706
 
 
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. */
 
2709
 
 
2710
        make_object_name(expanded_filename, sizeof(expanded_filename), filename, "_mapping");
 
2711
 
 
2712
        HANDLE header_obj = CreateFileMapping ((HANDLE) -1,
 
2713
                                ISC_get_security_desc(),
 
2714
                                PAGE_READWRITE,
 
2715
                                0,
 
2716
                                2 * sizeof (SLONG),
 
2717
                                expanded_filename);
 
2718
        if (header_obj == NULL) {
 
2719
                error(status_vector, "CreateFileMapping", GetLastError());
 
2720
                CloseHandle(event_handle);
 
2721
                CloseHandle(file_handle);
 
2722
                return NULL;
 
2723
        }
 
2724
 
 
2725
        SLONG* header_address =
 
2726
                (SLONG*) MapViewOfFile(header_obj, FILE_MAP_WRITE, 0, 0, 0);
 
2727
 
 
2728
        if (header_address == NULL) {
 
2729
                error(status_vector, "CreateFileMapping", GetLastError());
 
2730
                CloseHandle(header_obj);
 
2731
                CloseHandle(event_handle);
 
2732
                CloseHandle(file_handle);
 
2733
                return NULL;
 
2734
        }
 
2735
 
 
2736
/* Set or get the true length of the file depending on whether or not
 
2737
   we are the first user. */
 
2738
 
 
2739
        if (init_flag) {
 
2740
                header_address[0] = length;
 
2741
                header_address[1] = 0;
 
2742
        }
 
2743
        else
 
2744
                length = header_address[0];
 
2745
 
 
2746
/* Create the real file mapping object. */
 
2747
 
 
2748
        TEXT* p;
 
2749
        for (p = expanded_filename; *p; p++);
 
2750
        sprintf(p, "%"SLONGFORMAT, header_address[1]);
 
2751
 
 
2752
        HANDLE file_obj =
 
2753
                CreateFileMapping(file_handle,
 
2754
                                  ISC_get_security_desc(),
 
2755
                                  PAGE_READWRITE,
 
2756
                                  0,
 
2757
                                  length,
 
2758
                                  expanded_filename);
 
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);
 
2765
                return NULL;
 
2766
        }
 
2767
 
 
2768
        UCHAR* address =
 
2769
                (UCHAR*) MapViewOfFile(file_obj, FILE_MAP_WRITE, 0, 0, 0);
 
2770
 
 
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);
 
2778
                return NULL;
 
2779
        }
 
2780
 
 
2781
        *p = 0;
 
2782
 
 
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);
 
2791
 
 
2792
        if (init_routine)
 
2793
                (*init_routine) (init_arg, shmem_data, init_flag);
 
2794
 
 
2795
        if (init_flag) {
 
2796
                FlushViewOfFile(address, 0);
 
2797
                if (!ISC_is_WinNT())
 
2798
                        ReleaseMutex(event_handle);
 
2799
                else
 
2800
                        SetEvent(event_handle);
 
2801
                if (SetFilePointer
 
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))
 
2806
                {
 
2807
                        error(status_vector, "SetFilePointer", GetLastError());
 
2808
                        return NULL;
 
2809
                }
 
2810
        }
 
2811
 
 
2812
        return address;
 
2813
}
 
2814
#endif
 
2815
 
 
2816
 
 
2817
#ifndef REQUESTER
 
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)
 
2823
{
 
2824
/**************************************
 
2825
 *
 
2826
 *      I S C _ m a p _ f i l e         ( G E N E R I C )
 
2827
 *
 
2828
 **************************************
 
2829
 *
 
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).
 
2834
 *
 
2835
 **************************************/
 
2836
 
 
2837
        *status_vector++ = isc_arg_gds;
 
2838
        *status_vector++ = isc_unavailable;
 
2839
        *status_vector++ = isc_arg_end;
 
2840
 
 
2841
        return NULL;
 
2842
}
 
2843
#endif
 
2844
#endif
 
2845
 
 
2846
 
 
2847
#ifdef HAVE_MMAP
 
2848
#define ISC_MAP_OBJECT_DEFINED
 
2849
UCHAR *ISC_map_object(ISC_STATUS * status_vector,
 
2850
                                          SH_MEM shmem_data,
 
2851
                                          SLONG object_offset, SLONG object_length)
 
2852
{
 
2853
/**************************************
 
2854
 *
 
2855
 *      I S C _ m a p _ o b j e c t
 
2856
 *
 
2857
 **************************************
 
2858
 *
 
2859
 * Functional description
 
2860
 *      Try to map an object given a file mapping.
 
2861
 *
 
2862
 **************************************/
 
2863
/* Get system page size as this is the unit of mapping. */
 
2864
 
 
2865
#ifdef SOLARIS
 
2866
        const SLONG page_size = sysconf(_SC_PAGESIZE);
 
2867
        if (page_size == -1) {
 
2868
                error(status_vector, "sysconf", errno);
 
2869
                return NULL;
 
2870
        }
 
2871
#else
 
2872
        const SLONG page_size = (int) getpagesize();
 
2873
        if (page_size == -1) {
 
2874
                error(status_vector, "getpagesize", errno);
 
2875
                return NULL;
 
2876
        }
 
2877
#endif
 
2878
 
 
2879
/* Compute the start and end page-aligned offsets which
 
2880
   contain the object being mapped. */
 
2881
 
 
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;
 
2886
 
 
2887
        UCHAR* address =
 
2888
                (UCHAR *) mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
 
2889
                                           start);
 
2890
 
 
2891
        if ((U_IPTR) address == (U_IPTR) -1) {
 
2892
                error(status_vector, "mmap", errno);
 
2893
                return NULL;
 
2894
        }
 
2895
 
 
2896
/* Return the virtual address of the mapped object. */
 
2897
 
 
2898
        return (address + (object_offset - start));
 
2899
}
 
2900
#endif
 
2901
 
 
2902
 
 
2903
#ifdef HAVE_MMAP
 
2904
#define ISC_UNMAP_OBJECT_DEFINED
 
2905
void ISC_unmap_object(ISC_STATUS * status_vector,
 
2906
                                                 SH_MEM shmem_data,
 
2907
                                                 UCHAR ** object_pointer, SLONG object_length)
 
2908
{
 
2909
/**************************************
 
2910
 *
 
2911
 *      I S C _ u n m a p _ o b j e c t
 
2912
 *
 
2913
 **************************************
 
2914
 *
 
2915
 * Functional description
 
2916
 *      Try to unmap an object given a file mapping.
 
2917
 *      Zero the object pointer after a successful unmap.
 
2918
 *
 
2919
 **************************************/
 
2920
/* Get system page size as this is the unit of mapping. */
 
2921
 
 
2922
#ifdef SOLARIS
 
2923
        const SLONG ps = sysconf(_SC_PAGESIZE);
 
2924
        if (ps == -1) {
 
2925
                error(status_vector, "sysconf", errno);
 
2926
                return; // false;
 
2927
        }
 
2928
#else
 
2929
        const SLONG ps = (int) getpagesize();
 
2930
        if (ps == -1) {
 
2931
                error(status_vector, "getpagesize", errno);
 
2932
                return; // false;
 
2933
        }
 
2934
#endif
 
2935
    const size_t page_size = (ULONG) ps;
 
2936
 
 
2937
/* Compute the start and end page-aligned addresses which
 
2938
   contain the mapped object. */
 
2939
 
 
2940
        UCHAR* start = (UCHAR *) ((U_IPTR) * object_pointer & ~(page_size - 1));
 
2941
        const UCHAR* end =
 
2942
                (UCHAR
 
2943
                 *) ((U_IPTR) ((*object_pointer + object_length) +
 
2944
                                           (page_size - 1)) & ~(page_size - 1));
 
2945
        const size_t length = end - start;
 
2946
 
 
2947
        if (munmap((char *) start, length) == -1) {
 
2948
                error(status_vector, "munmap", errno);
 
2949
                return; // false;
 
2950
        }
 
2951
 
 
2952
        *object_pointer = 0;
 
2953
        return; // true;
 
2954
}
 
2955
#endif
 
2956
 
 
2957
 
 
2958
#ifdef VMS
 
2959
#define MUTEX
 
2960
int ISC_mutex_init(MTX mutex, SLONG event_flag)
 
2961
{
 
2962
/**************************************
 
2963
 *
 
2964
 *      I S C _ m u t e x _ i n i t     ( V M S )
 
2965
 *
 
2966
 **************************************
 
2967
 *
 
2968
 * Functional description
 
2969
 *      Initialize a mutex.
 
2970
 *
 
2971
 **************************************/
 
2972
 
 
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;
 
2977
 
 
2978
        return 0;
 
2979
}
 
2980
 
 
2981
 
 
2982
int ISC_mutex_lock(MTX mutex)
 
2983
{
 
2984
/**************************************
 
2985
 *
 
2986
 *      I S C _ m u t e x _ l o c k     ( V M S )
 
2987
 *
 
2988
 **************************************
 
2989
 *
 
2990
 * Functional description
 
2991
 *      Sieze a mutex.
 
2992
 *
 
2993
 **************************************/
 
2994
        SLONG bit = 0;
 
2995
        ++mutex->mtx_wait;
 
2996
 
 
2997
        if (lib$bbssi(&bit, mutex->mtx_event_count))
 
2998
                for (;;) {
 
2999
                        if (!lib$bbssi(&bit, mutex->mtx_event_count))
 
3000
                                break;
 
3001
                        gds__thread_wait(mutex_test, mutex);
 
3002
                }
 
3003
 
 
3004
        --mutex->mtx_wait;
 
3005
 
 
3006
        return 0;
 
3007
}
 
3008
 
 
3009
 
 
3010
int ISC_mutex_unlock(MTX mutex)
 
3011
{
 
3012
/**************************************
 
3013
 *
 
3014
 *      I S C _ m u t e x _ u n l o c k         ( V M S )
 
3015
 *
 
3016
 **************************************
 
3017
 *
 
3018
 * Functional description
 
3019
 *      Release a mutex.
 
3020
 *
 
3021
 **************************************/
 
3022
        SLONG bit = 0;
 
3023
        lib$bbcci(&bit, mutex->mtx_event_count);
 
3024
#ifndef __ALPHA
 
3025
        sys$wake(0, 0);
 
3026
#else
 
3027
        THREAD_wakeup();
 
3028
#endif
 
3029
 
 
3030
        return 0;
 
3031
}
 
3032
#endif
 
3033
 
 
3034
 
 
3035
#ifdef SOLARIS_MT
 
3036
#define MUTEX
 
3037
int ISC_mutex_init(MTX mutex, SLONG semaphore)
 
3038
{
 
3039
/**************************************
 
3040
 *
 
3041
 *      I S C _ m u t e x _ i n i t     ( S O L A R I S _ M T )
 
3042
 *
 
3043
 **************************************
 
3044
 *
 
3045
 * Functional description
 
3046
 *      Initialize a mutex.
 
3047
 *
 
3048
 **************************************/
 
3049
 
 
3050
        return mutex_init(mutex->mtx_mutex, USYNC_PROCESS, NULL);
 
3051
}
 
3052
 
 
3053
 
 
3054
int ISC_mutex_lock(MTX mutex)
 
3055
{
 
3056
/**************************************
 
3057
 *
 
3058
 *      I S C _ m u t e x _ l o c k     ( S O L A R I S _ M T )
 
3059
 *
 
3060
 **************************************
 
3061
 *
 
3062
 * Functional description
 
3063
 *      Sieze a mutex.
 
3064
 *
 
3065
 **************************************/
 
3066
        for (;;) {
 
3067
                int state = mutex_lock(mutex->mtx_mutex);
 
3068
                if (!state)
 
3069
                        break;
 
3070
                if (!SYSCALL_INTERRUPTED(state))
 
3071
                        return state;
 
3072
        }
 
3073
 
 
3074
        return 0;
 
3075
}
 
3076
 
 
3077
 
 
3078
int ISC_mutex_lock_cond(MTX mutex)
 
3079
{
 
3080
/**************************************
 
3081
 *
 
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 )
 
3083
 *
 
3084
 **************************************
 
3085
 *
 
3086
 * Functional description
 
3087
 *      Conditionally sieze a mutex.
 
3088
 *
 
3089
 **************************************/
 
3090
        for (;;) {
 
3091
                int state = mutex_trylock(mutex->mtx_mutex);
 
3092
                if (!state)
 
3093
                        break;
 
3094
                if (!SYSCALL_INTERRUPTED(state))
 
3095
                        return state;
 
3096
        }
 
3097
 
 
3098
        return 0;
 
3099
}
 
3100
 
 
3101
 
 
3102
int ISC_mutex_unlock(MTX mutex)
 
3103
{
 
3104
/**************************************
 
3105
 *
 
3106
 *      I S C _ m u t e x _ u n l o c k         ( S O L A R I S _ M T )
 
3107
 *
 
3108
 **************************************
 
3109
 *
 
3110
 * Functional description
 
3111
 *      Release a mutex.
 
3112
 *
 
3113
 **************************************/
 
3114
        for (;;) {
 
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);
 
3118
                if (!state)
 
3119
                        break;
 
3120
                if (!SYSCALL_INTERRUPTED(state))
 
3121
                        return state;
 
3122
        }
 
3123
 
 
3124
        return 0;
 
3125
}
 
3126
#endif /* SOLARIS_MT */
 
3127
 
 
3128
 
 
3129
#ifdef USE_POSIX_THREADS
 
3130
#define MUTEX
 
3131
int ISC_mutex_init(MTX mutex, SLONG semaphore)
 
3132
{
 
3133
/**************************************
 
3134
 *
 
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 )
 
3136
 *
 
3137
 **************************************
 
3138
 *
 
3139
 * Functional description
 
3140
 *      Initialize a mutex.
 
3141
 *
 
3142
 **************************************/
 
3143
        pthread_mutexattr_t mattr;
 
3144
 
 
3145
        int state = pthread_mutexattr_init(&mattr);
 
3146
        if (state == 0)
 
3147
        {
 
3148
#if _POSIX_THREAD_PROCESS_SHARED >= 200112L
 
3149
                pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
 
3150
#endif
 
3151
                state = pthread_mutex_init(mutex->mtx_mutex, &mattr);
 
3152
                pthread_mutexattr_destroy(&mattr);
 
3153
        }
 
3154
#ifdef HP10
 
3155
        if (state != 0)
 
3156
                state = errno;
 
3157
#endif
 
3158
        return state;
 
3159
}
 
3160
 
 
3161
 
 
3162
int ISC_mutex_lock(MTX mutex)
 
3163
{
 
3164
/**************************************
 
3165
 *
 
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 )
 
3167
 *
 
3168
 **************************************
 
3169
 *
 
3170
 * Functional description
 
3171
 *      Sieze a mutex.
 
3172
 *
 
3173
 **************************************/
 
3174
#ifdef HP10
 
3175
        int state = pthread_mutex_lock(mutex->mtx_mutex);
 
3176
        if (!state)
 
3177
                return 0;
 
3178
        fb_assert(state == -1);         /* if state is not 0, it should be -1 */
 
3179
        return errno;
 
3180
 
 
3181
#else
 
3182
 
 
3183
        return pthread_mutex_lock(mutex->mtx_mutex);
 
3184
 
 
3185
#endif /* HP10 */
 
3186
}
 
3187
 
 
3188
 
 
3189
int ISC_mutex_lock_cond(MTX mutex)
 
3190
{
 
3191
/**************************************
 
3192
 *
 
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 )
 
3194
 *
 
3195
 **************************************
 
3196
 *
 
3197
 * Functional description
 
3198
 *      Conditionally sieze a mutex.
 
3199
 *
 
3200
 **************************************/
 
3201
#ifdef HP10
 
3202
        int state = pthread_mutex_trylock(mutex->mtx_mutex);
 
3203
 
 
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:
 
3208
 
 
3209
        return  errno   description
 
3210
          1             Success
 
3211
          0             mutex has alreary been locked. Could not get it
 
3212
         -1     EINVAL  invalid value of mutex
 
3213
*/
 
3214
        if (!state)
 
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) */
 
3218
        if (state == 1)
 
3219
                return 0;
 
3220
 
 
3221
        fb_assert(state == -1);         /* if state is not 0 or 1, it should be -1 */
 
3222
        return errno;
 
3223
 
 
3224
#else
 
3225
 
 
3226
        return pthread_mutex_trylock(mutex->mtx_mutex);
 
3227
 
 
3228
#endif /* HP10 */
 
3229
}
 
3230
 
 
3231
 
 
3232
int ISC_mutex_unlock(MTX mutex)
 
3233
{
 
3234
/**************************************
 
3235
 *
 
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 )
 
3237
 *
 
3238
 **************************************
 
3239
 *
 
3240
 * Functional description
 
3241
 *      Release a mutex.
 
3242
 *
 
3243
 **************************************/
 
3244
#ifdef HP10
 
3245
        int state = pthread_mutex_unlock(mutex->mtx_mutex);
 
3246
        if (!state)
 
3247
                return 0;
 
3248
        fb_assert(state == -1);         /* if state is not 0, it should be -1 */
 
3249
        return errno;
 
3250
 
 
3251
#else
 
3252
 
 
3253
        return pthread_mutex_unlock(mutex->mtx_mutex);
 
3254
 
 
3255
#endif /* HP10 */
 
3256
}
 
3257
#endif /* USE_POSIX_THREADS */
 
3258
 
 
3259
 
 
3260
#ifdef UNIX
 
3261
#ifndef MUTEX
 
3262
#define MUTEX
 
3263
int ISC_mutex_init(MTX mutex, SLONG semaphore)
 
3264
{
 
3265
/**************************************
 
3266
 *
 
3267
 *      I S C _ m u t e x _ i n i t     ( U N I X )
 
3268
 *                                             not SOLARIS
 
3269
 *                                             not USE_POSIX_THREADS
 
3270
 *
 
3271
 **************************************
 
3272
 *
 
3273
 * Functional description
 
3274
 *      Initialize a mutex.
 
3275
 *
 
3276
 **************************************/
 
3277
        mutex->mtx_semid = semaphore;
 
3278
        mutex->mtx_semnum = 0;
 
3279
 
 
3280
        union semun arg;
 
3281
        arg.val = 1;
 
3282
        int state = semctl((int) semaphore, 0, SETVAL, arg);
 
3283
        if (state == -1)
 
3284
                return errno;
 
3285
 
 
3286
        return 0;
 
3287
}
 
3288
 
 
3289
 
 
3290
int ISC_mutex_lock(MTX mutex)
 
3291
{
 
3292
/**************************************
 
3293
 *
 
3294
 *      I S C _ m u t e x _ l o c k     ( U N I X )
 
3295
 *                                             not SOLARIS
 
3296
 *                                             not USE_POSIX_THREADS
 
3297
 *
 
3298
 **************************************
 
3299
 *
 
3300
 * Functional description
 
3301
 *      Sieze a mutex.
 
3302
 *
 
3303
 **************************************/
 
3304
        struct sembuf sop;
 
3305
        sop.sem_num = mutex->mtx_semnum;
 
3306
        sop.sem_op = -1;
 
3307
        sop.sem_flg = SEM_UNDO;
 
3308
 
 
3309
        for (;;) {
 
3310
                int state = semop(mutex->mtx_semid, &sop, 1);
 
3311
                if (state != -1)
 
3312
                        break;
 
3313
                if (!SYSCALL_INTERRUPTED(errno))
 
3314
                        return errno;
 
3315
        }
 
3316
 
 
3317
        return 0;
 
3318
}
 
3319
 
 
3320
 
 
3321
int ISC_mutex_lock_cond(MTX mutex)
 
3322
{
 
3323
/**************************************
 
3324
 *
 
3325
 *      I S C _ m u t e x _ l o c k _ c o n d   ( U N I X )
 
3326
 *                                             not SOLARIS
 
3327
 *                                             not USE_POSIX_THREADS
 
3328
 *
 
3329
 **************************************
 
3330
 *
 
3331
 * Functional description
 
3332
 *      Conditionally sieze a mutex.
 
3333
 *
 
3334
 **************************************/
 
3335
        struct sembuf sop;
 
3336
        sop.sem_num = mutex->mtx_semnum;
 
3337
        sop.sem_op = -1;
 
3338
        sop.sem_flg = SEM_UNDO | IPC_NOWAIT;
 
3339
 
 
3340
        for (;;) {
 
3341
                int state = semop(mutex->mtx_semid, &sop, 1);
 
3342
                if (state != -1)
 
3343
                        break;
 
3344
                if (!SYSCALL_INTERRUPTED(errno))
 
3345
                        return errno;
 
3346
        }
 
3347
 
 
3348
        return 0;
 
3349
}
 
3350
 
 
3351
 
 
3352
int ISC_mutex_unlock(MTX mutex)
 
3353
{
 
3354
/**************************************
 
3355
 *
 
3356
 *      I S C _ m u t e x _ u n l o c k         ( U N I X )
 
3357
 *                                             not SOLARIS
 
3358
 *                                             not USE_POSIX_THREADS
 
3359
 *
 
3360
 **************************************
 
3361
 *
 
3362
 * Functional description
 
3363
 *      Release a mutex.
 
3364
 *
 
3365
 **************************************/
 
3366
        struct sembuf sop;
 
3367
        sop.sem_num = mutex->mtx_semnum;
 
3368
        sop.sem_op = 1;
 
3369
        sop.sem_flg = SEM_UNDO;
 
3370
 
 
3371
        for (;;) {
 
3372
                int state = semop(mutex->mtx_semid, &sop, 1);
 
3373
                if (state != -1)
 
3374
                        break;
 
3375
                if (!SYSCALL_INTERRUPTED(errno))
 
3376
                        return errno;
 
3377
        }
 
3378
 
 
3379
        return 0;
 
3380
}
 
3381
#endif
 
3382
#endif
 
3383
 
 
3384
 
 
3385
#ifdef WIN_NT
 
3386
#define MUTEX
 
3387
 
 
3388
static const LPCSTR FAST_MUTEX_EVT_NAME = "%s_FM_EVT";
 
3389
static const LPCSTR FAST_MUTEX_MAP_NAME = "%s_FM_MAP";
 
3390
 
 
3391
static const int DEFAULT_INTERLOCKED_SPIN_COUNT = 0;
 
3392
static const int DEFAULT_INTERLOCKED_SPIN_COUNT_SMP     = 200;
 
3393
 
 
3394
 
 
3395
typedef WINBASEAPI BOOL (WINAPI *pfnSwitchToThread) ();
 
3396
static inline BOOL switchToThread()
 
3397
{
 
3398
        static pfnSwitchToThread fnSwitchToThread = NULL;
 
3399
        static bool bInit = false;
 
3400
 
 
3401
        if (!bInit)
 
3402
        {
 
3403
                HMODULE hLib = GetModuleHandle("kernel32.dll");
 
3404
                if (hLib) {
 
3405
                        fnSwitchToThread = (pfnSwitchToThread) GetProcAddress(hLib, "SwitchToThread");
 
3406
                }
 
3407
                bInit = true;
 
3408
        }
 
3409
 
 
3410
        BOOL res = FALSE;
 
3411
        if (fnSwitchToThread) 
 
3412
        {
 
3413
#if !defined SUPERSERVER && !defined EMBEDDED
 
3414
                const HANDLE hThread = GetCurrentThread();
 
3415
                SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL);
 
3416
#endif
 
3417
 
 
3418
                res = (*fnSwitchToThread) ();
 
3419
 
 
3420
#if !defined SUPERSERVER && !defined EMBEDDED
 
3421
                SetThreadPriority(hThread, THREAD_PRIORITY_NORMAL);
 
3422
#endif
 
3423
        }
 
3424
 
 
3425
        return res;
 
3426
}
 
3427
 
 
3428
 
 
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)
 
3433
#else
 
3434
#define FIX_TYPE(arg) arg
 
3435
#endif
 
3436
 
 
3437
 
 
3438
static inline void lockSharedSection(volatile FAST_MUTEX_SHARED_SECTION* lpSect, ULONG SpinCount)
 
3439
{
 
3440
        while (InterlockedExchange(FIX_TYPE(&lpSect->lSpinLock), 1) != 0)
 
3441
        {
 
3442
                ULONG j = SpinCount; 
 
3443
                while (j != 0)
 
3444
                {
 
3445
                        if (lpSect->lSpinLock == 0)
 
3446
                                goto next;
 
3447
                        j--;
 
3448
                }
 
3449
                switchToThread();
 
3450
next:;
 
3451
        }
 
3452
}
 
3453
 
 
3454
static inline bool tryLockSharedSection(volatile FAST_MUTEX_SHARED_SECTION* lpSect)
 
3455
{
 
3456
        return (InterlockedExchange(FIX_TYPE(&lpSect->lSpinLock), 1) == 0);
 
3457
}
 
3458
 
 
3459
static inline void unlockSharedSection(volatile FAST_MUTEX_SHARED_SECTION* lpSect)
 
3460
{
 
3461
        InterlockedExchange(FIX_TYPE(&lpSect->lSpinLock), 0);
 
3462
}
 
3463
 
 
3464
static DWORD enterFastMutex(FAST_MUTEX* lpMutex, DWORD dwMilliseconds)
 
3465
{
 
3466
        volatile FAST_MUTEX_SHARED_SECTION* lpSect = lpMutex->lpSharedInfo;
 
3467
 
 
3468
        while (true)
 
3469
        {
 
3470
                DWORD dwResult;
 
3471
                
 
3472
                if (dwMilliseconds == 0) {
 
3473
                        if (!tryLockSharedSection(lpSect))
 
3474
                                return WAIT_TIMEOUT;
 
3475
                }
 
3476
                else {
 
3477
                        lockSharedSection(lpSect, lpMutex->lSpinCount);
 
3478
                }
 
3479
 
 
3480
                if (lpSect->lAvailable > 0)
 
3481
                {
 
3482
                        lpSect->lAvailable--;
 
3483
#ifdef _DEBUG
 
3484
                        lpSect->dwThreadId = GetCurrentThreadId();
 
3485
#endif
 
3486
                        unlockSharedSection(lpSect);
 
3487
                        return WAIT_OBJECT_0;
 
3488
                }
 
3489
 
 
3490
#ifdef _DEBUG
 
3491
                if (lpSect->dwThreadId == GetCurrentThreadId())
 
3492
                        DebugBreak();
 
3493
#endif
 
3494
                if (dwMilliseconds == 0)
 
3495
                {
 
3496
                        unlockSharedSection(lpSect);
 
3497
                        return WAIT_TIMEOUT;
 
3498
                }
 
3499
 
 
3500
                InterlockedIncrement(FIX_TYPE(&lpSect->lThreadsWaiting));
 
3501
                unlockSharedSection(lpSect);
 
3502
                
 
3503
                // TODO actual timeout can be of any length
 
3504
                dwResult = WaitForSingleObject(lpMutex->hEvent, dwMilliseconds);
 
3505
                InterlockedDecrement(FIX_TYPE(&lpSect->lThreadsWaiting));
 
3506
                
 
3507
                if (dwResult != WAIT_OBJECT_0)
 
3508
                        return dwResult;
 
3509
        }
 
3510
}
 
3511
 
 
3512
static bool leaveFastMutex(FAST_MUTEX* lpMutex)
 
3513
{
 
3514
        volatile FAST_MUTEX_SHARED_SECTION* lpSect = lpMutex->lpSharedInfo;
 
3515
 
 
3516
        lockSharedSection(lpSect, lpMutex->lSpinCount);
 
3517
        if (lpSect->lAvailable >= 1)
 
3518
        {
 
3519
                unlockSharedSection(lpSect);
 
3520
                SetLastError(ERROR_INVALID_PARAMETER);
 
3521
                return false;
 
3522
        }
 
3523
        lpSect->lAvailable++;
 
3524
        if (lpSect->lThreadsWaiting)
 
3525
                SetEvent(lpMutex->hEvent);
 
3526
        unlockSharedSection(lpSect);
 
3527
 
 
3528
        return true;
 
3529
}
 
3530
 
 
3531
static inline void deleteFastMutex(FAST_MUTEX* lpMutex)
 
3532
{
 
3533
        UnmapViewOfFile((FAST_MUTEX_SHARED_SECTION*)lpMutex->lpSharedInfo);
 
3534
        CloseHandle(lpMutex->hFileMap);
 
3535
        CloseHandle(lpMutex->hEvent);
 
3536
}
 
3537
 
 
3538
static inline void setupMutex(FAST_MUTEX* lpMutex)
 
3539
{
 
3540
        SYSTEM_INFO si;
 
3541
        GetSystemInfo(&si);
 
3542
 
 
3543
        if (si.dwNumberOfProcessors > 1)
 
3544
                lpMutex->lSpinCount = DEFAULT_INTERLOCKED_SPIN_COUNT_SMP;
 
3545
        else
 
3546
                lpMutex->lSpinCount = DEFAULT_INTERLOCKED_SPIN_COUNT;
 
3547
}
 
3548
 
 
3549
static bool initializeFastMutex(FAST_MUTEX* lpMutex, LPSECURITY_ATTRIBUTES lpAttributes, 
 
3550
                                                                BOOL bInitialState, LPCSTR lpName)
 
3551
{
 
3552
        char sz[MAXPATHLEN];
 
3553
        LPCSTR name = lpName;
 
3554
        DWORD dwLastError; 
 
3555
 
 
3556
        if (strlen(lpName) + strlen(FAST_MUTEX_EVT_NAME) - 2 >= MAXPATHLEN)
 
3557
        {
 
3558
                // this is the same error which CreateEvent will return for long name
 
3559
                SetLastError(ERROR_FILENAME_EXCED_RANGE);
 
3560
                return false;
 
3561
        }
 
3562
 
 
3563
        setupMutex(lpMutex);
 
3564
 
 
3565
        if (lpName)
 
3566
        {
 
3567
                sprintf(sz, FAST_MUTEX_EVT_NAME, lpName);
 
3568
                name = sz;
 
3569
        }
 
3570
 
 
3571
        lpMutex->hEvent = CreateEvent(lpAttributes, FALSE, FALSE, name);
 
3572
        dwLastError = GetLastError();
 
3573
 
 
3574
        if (lpMutex->hEvent)
 
3575
        {
 
3576
                if (lpName)
 
3577
                        sprintf(sz, FAST_MUTEX_MAP_NAME, lpName);
 
3578
 
 
3579
                lpMutex->hFileMap = CreateFileMapping(
 
3580
                        INVALID_HANDLE_VALUE, 
 
3581
                        lpAttributes, 
 
3582
                        PAGE_READWRITE, 
 
3583
                        0, 
 
3584
                        sizeof(FAST_MUTEX_SHARED_SECTION), 
 
3585
                        name);
 
3586
 
 
3587
                dwLastError = GetLastError();
 
3588
 
 
3589
                if (lpMutex->hFileMap)
 
3590
                {
 
3591
                        lpMutex->lpSharedInfo = (FAST_MUTEX_SHARED_SECTION*) 
 
3592
                                MapViewOfFile(lpMutex->hFileMap, FILE_MAP_WRITE, 0, 0, 0);
 
3593
 
 
3594
                        if (lpMutex->lpSharedInfo)
 
3595
                        {
 
3596
                                if (dwLastError != ERROR_ALREADY_EXISTS)
 
3597
                                {
 
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);
 
3602
                                }
 
3603
                                else
 
3604
                                {
 
3605
                                        while (!lpMutex->lpSharedInfo->fInitialized) 
 
3606
                                                switchToThread();
 
3607
                                }
 
3608
 
 
3609
                                SetLastError(dwLastError);
 
3610
                                return true;
 
3611
                        }
 
3612
                        CloseHandle(lpMutex->hFileMap);
 
3613
                }
 
3614
                CloseHandle(lpMutex->hEvent);
 
3615
        }
 
3616
 
 
3617
        SetLastError(dwLastError);
 
3618
        return false;
 
3619
}
 
3620
 
 
3621
static bool openFastMutex(FAST_MUTEX* lpMutex, DWORD DesiredAccess, LPCSTR lpName)
 
3622
{
 
3623
        char sz[MAXPATHLEN];
 
3624
        LPCSTR name = lpName;
 
3625
        DWORD dwLastError; 
 
3626
 
 
3627
        if (strlen(lpName) + strlen(FAST_MUTEX_EVT_NAME) - 2 >= MAXPATHLEN)
 
3628
        {
 
3629
                SetLastError(ERROR_FILENAME_EXCED_RANGE);
 
3630
                return false;
 
3631
        }
 
3632
 
 
3633
        setupMutex(lpMutex);
 
3634
 
 
3635
        if (lpName)
 
3636
        {
 
3637
                sprintf(sz, FAST_MUTEX_EVT_NAME, lpName);
 
3638
                name = sz;
 
3639
        }
 
3640
        
 
3641
        lpMutex->hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, name);
 
3642
        
 
3643
        dwLastError = GetLastError();
 
3644
        
 
3645
        if (lpMutex->hEvent)
 
3646
        {
 
3647
                if (lpName)
 
3648
                        sprintf(sz, FAST_MUTEX_MAP_NAME, lpName);
 
3649
                
 
3650
                lpMutex->hFileMap = OpenFileMapping(
 
3651
                        FILE_MAP_ALL_ACCESS, 
 
3652
                        FALSE, 
 
3653
                        name);
 
3654
                
 
3655
                dwLastError = GetLastError();
 
3656
        
 
3657
                if (lpMutex->hFileMap)
 
3658
                {
 
3659
                        lpMutex->lpSharedInfo = (FAST_MUTEX_SHARED_SECTION*) 
 
3660
                                MapViewOfFile(lpMutex->hFileMap, FILE_MAP_WRITE, 0, 0, 0);
 
3661
                        
 
3662
                        if (lpMutex->lpSharedInfo)
 
3663
                                return true;
 
3664
 
 
3665
                        CloseHandle(lpMutex->hFileMap);
 
3666
                }
 
3667
                CloseHandle(lpMutex->hEvent);
 
3668
        }
 
3669
 
 
3670
        SetLastError(dwLastError);
 
3671
        return false;
 
3672
}
 
3673
 
 
3674
static inline void setFastMutexSpinCount(FAST_MUTEX* lpMutex, ULONG SpinCount)
 
3675
{
 
3676
        lpMutex->lSpinCount = SpinCount;
 
3677
}
 
3678
 
 
3679
 
 
3680
int ISC_mutex_init(MTX mutex, const TEXT* mutex_name)
 
3681
{
 
3682
/**************************************
 
3683
 *
 
3684
 *      I S C _ m u t e x _ i n i t     ( W I N _ N T )
 
3685
 *
 
3686
 **************************************
 
3687
 *
 
3688
 * Functional description
 
3689
 *      Initialize a mutex.
 
3690
 *
 
3691
 **************************************/
 
3692
        char name_buffer[MAXPATHLEN];
 
3693
 
 
3694
        make_object_name(name_buffer, sizeof(name_buffer), mutex_name, "_mutex");
 
3695
 
 
3696
        if (ISC_is_WinNT())
 
3697
        {
 
3698
                return !initializeFastMutex(&mutex->mtx_fast, 
 
3699
                        ISC_get_security_desc(), FALSE, name_buffer);
 
3700
        }
 
3701
        else
 
3702
        {
 
3703
                memset(&mutex->mtx_fast, 0, sizeof(FAST_MUTEX));
 
3704
 
 
3705
                mutex->mtx_fast.hEvent =
 
3706
                        CreateMutex(ISC_get_security_desc(), FALSE, name_buffer);
 
3707
 
 
3708
                return (mutex->mtx_fast.hEvent) ? 0 : 1;
 
3709
        }
 
3710
}
 
3711
 
 
3712
 
 
3713
void ISC_mutex_fini (struct mtx *mutex)
 
3714
{
 
3715
        if (mutex->mtx_fast.lpSharedInfo)
 
3716
                deleteFastMutex(&mutex->mtx_fast);
 
3717
}
 
3718
 
 
3719
 
 
3720
int ISC_mutex_lock(MTX mutex)
 
3721
{
 
3722
/**************************************
 
3723
 *
 
3724
 *      I S C _ m u t e x _ l o c k     ( W I N _ N T )
 
3725
 *
 
3726
 **************************************
 
3727
 *
 
3728
 * Functional description
 
3729
 *      Sieze a mutex.
 
3730
 *
 
3731
 **************************************/
 
3732
 
 
3733
        const DWORD status = (mutex->mtx_fast.lpSharedInfo) ?
 
3734
                enterFastMutex(&mutex->mtx_fast, INFINITE) :
 
3735
                WaitForSingleObject(mutex->mtx_fast.hEvent, INFINITE);
 
3736
 
 
3737
    return (status == WAIT_OBJECT_0 || status == WAIT_ABANDONED) ? 0 : 1;
 
3738
}
 
3739
 
 
3740
 
 
3741
int ISC_mutex_lock_cond(MTX mutex)
 
3742
{
 
3743
/**************************************
 
3744
 *
 
3745
 *      I S C _ m u t e x _ l o c k _ c o n d   ( W I N _ N T )
 
3746
 *
 
3747
 **************************************
 
3748
 *
 
3749
 * Functional description
 
3750
 *      Conditionally sieze a mutex.
 
3751
 *
 
3752
 **************************************/
 
3753
 
 
3754
        const DWORD status = (mutex->mtx_fast.lpSharedInfo) ? 
 
3755
                enterFastMutex(&mutex->mtx_fast, 0) :
 
3756
                WaitForSingleObject (mutex->mtx_fast.hEvent, 0L);
 
3757
 
 
3758
    return (status == WAIT_OBJECT_0 || status == WAIT_ABANDONED) ? 0 : 1;
 
3759
}
 
3760
 
 
3761
 
 
3762
int ISC_mutex_unlock(MTX mutex)
 
3763
{
 
3764
/**************************************
 
3765
 *
 
3766
 *      I S C _ m u t e x _ u n l o c k         ( W I N _ N T )
 
3767
 *
 
3768
 **************************************
 
3769
 *
 
3770
 * Functional description
 
3771
 *      Release a mutex.
 
3772
 *
 
3773
 **************************************/
 
3774
 
 
3775
        if (mutex->mtx_fast.lpSharedInfo) {
 
3776
                return !leaveFastMutex(&mutex->mtx_fast);
 
3777
        }
 
3778
        else {
 
3779
                return !ReleaseMutex(mutex->mtx_fast.hEvent);
 
3780
        }
 
3781
}
 
3782
 
 
3783
 
 
3784
void ISC_mutex_set_spin_count (struct mtx *mutex, ULONG spins)
 
3785
{
 
3786
        if (mutex->mtx_fast.lpSharedInfo) 
 
3787
                setFastMutexSpinCount(&mutex->mtx_fast, spins);
 
3788
}
 
3789
 
 
3790
#endif // WIN_NT
 
3791
 
 
3792
 
 
3793
#ifndef MUTEX
 
3794
int ISC_mutex_init(MTX mutex, SLONG dummy)
 
3795
{
 
3796
/**************************************
 
3797
 *
 
3798
 *      I S C _ m u t e x _ i n i t     ( G E N E R I C )
 
3799
 *
 
3800
 **************************************
 
3801
 *
 
3802
 * Functional description
 
3803
 *      Initialize a mutex.
 
3804
 *
 
3805
 **************************************/
 
3806
 
 
3807
        return 0;
 
3808
}
 
3809
 
 
3810
 
 
3811
int ISC_mutex_lock(MTX mutex)
 
3812
{
 
3813
/**************************************
 
3814
 *
 
3815
 *      I S C _ m u t e x _ l o c k     ( G E N E R I C )
 
3816
 *
 
3817
 **************************************
 
3818
 *
 
3819
 * Functional description
 
3820
 *      Sieze a mutex.
 
3821
 *
 
3822
 **************************************/
 
3823
 
 
3824
        return 0;
 
3825
}
 
3826
 
 
3827
 
 
3828
int ISC_mutex_unlock(MTX mutex)
 
3829
{
 
3830
/**************************************
 
3831
 *
 
3832
 *      I S C _ m u t e x _ u n l o c k         ( G E N E R I C )
 
3833
 *
 
3834
 **************************************
 
3835
 *
 
3836
 * Functional description
 
3837
 *      Release a mutex.
 
3838
 *
 
3839
 **************************************/
 
3840
 
 
3841
        return 0;
 
3842
}
 
3843
#endif
 
3844
 
 
3845
 
 
3846
#ifdef UNIX
 
3847
#ifdef HAVE_MMAP
 
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)
 
3851
{
 
3852
/**************************************
 
3853
 *
 
3854
 *      I S C _ r e m a p _ f i l e             ( U N I X - m m a p )
 
3855
 *
 
3856
 **************************************
 
3857
 *
 
3858
 * Functional description
 
3859
 *      Try to re-map a given file.
 
3860
 *
 
3861
 **************************************/
 
3862
        if (flag)
 
3863
                ftruncate(shmem_data->sh_mem_handle, new_length);
 
3864
 
 
3865
        UCHAR* address =
 
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)
 
3869
                return NULL;
 
3870
 
 
3871
        munmap((char *) shmem_data->sh_mem_address,
 
3872
                   shmem_data->sh_mem_length_mapped);
 
3873
 
 
3874
        shmem_data->sh_mem_address = address;
 
3875
        shmem_data->sh_mem_length_mapped = new_length;
 
3876
 
 
3877
        return address;
 
3878
}
 
3879
#endif
 
3880
#endif
 
3881
 
 
3882
 
 
3883
#ifdef WIN_NT
 
3884
#define ISC_REMAP_FILE_DEFINED
 
3885
UCHAR* ISC_remap_file(ISC_STATUS * status_vector,
 
3886
                                        SH_MEM shmem_data,
 
3887
                                        SLONG new_length,
 
3888
                                        bool flag)
 
3889
{
 
3890
/**************************************
 
3891
 *
 
3892
 *      I S C _ r e m a p _ f i l e             ( W I N _ N T )
 
3893
 *
 
3894
 **************************************
 
3895
 *
 
3896
 * Functional description
 
3897
 *      Try to re-map a given file.
 
3898
 *
 
3899
 **************************************/
 
3900
 
 
3901
        if (flag)
 
3902
                if (SetFilePointer
 
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))
 
3907
                {
 
3908
                        error(status_vector, "SetFilePointer", GetLastError());
 
3909
                        return NULL;
 
3910
                }
 
3911
 
 
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.
 
3918
 *
 
3919
 * The problem will be fixed by making sure that a new file name
 
3920
 * is generated with the mapped file is created.
 
3921
 */
 
3922
 
 
3923
        HANDLE file_obj;
 
3924
 
 
3925
        while (true) {
 
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);
 
3929
 
 
3930
                file_obj = CreateFileMapping(shmem_data->sh_mem_handle,
 
3931
                                             ISC_get_security_desc(),
 
3932
                                             PAGE_READWRITE,
 
3933
                                             0,
 
3934
                                             new_length,
 
3935
                                             expanded_filename);
 
3936
 
 
3937
                if (!((GetLastError() == ERROR_ALREADY_EXISTS) && flag))
 
3938
                        break;
 
3939
 
 
3940
                CloseHandle(file_obj);
 
3941
                shmem_data->sh_mem_hdr_address[1]++;
 
3942
        }
 
3943
 
 
3944
        if (file_obj == NULL) {
 
3945
                error(status_vector, "CreateFileMapping", GetLastError());
 
3946
                return NULL;
 
3947
        }
 
3948
 
 
3949
        LPVOID address = MapViewOfFile(file_obj, FILE_MAP_WRITE, 0, 0, 0);
 
3950
 
 
3951
        if (address == NULL) {
 
3952
                error(status_vector, "CreateFileMapping", GetLastError());
 
3953
                CloseHandle(file_obj);
 
3954
                return NULL;
 
3955
        }
 
3956
 
 
3957
        if (flag) {
 
3958
                shmem_data->sh_mem_hdr_address[0] = new_length;
 
3959
                shmem_data->sh_mem_hdr_address[1]++;
 
3960
        }
 
3961
 
 
3962
        UnmapViewOfFile(shmem_data->sh_mem_address);
 
3963
        CloseHandle(shmem_data->sh_mem_object);
 
3964
 
 
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;
 
3968
 
 
3969
        return reinterpret_cast<UCHAR*>(address);
 
3970
}
 
3971
#endif
 
3972
 
 
3973
 
 
3974
#ifndef ISC_REMAP_FILE_DEFINED
 
3975
UCHAR* ISC_remap_file(ISC_STATUS * status_vector,
 
3976
                                                SH_MEM shmem_data,
 
3977
                                                SLONG new_length,
 
3978
                                                bool flag)
 
3979
{
 
3980
/**************************************
 
3981
 *
 
3982
 *      I S C _ r e m a p _ f i l e             ( G E N E R I C )
 
3983
 *
 
3984
 **************************************
 
3985
 *
 
3986
 * Functional description
 
3987
 *      Try to re-map a given file.
 
3988
 *
 
3989
 **************************************/
 
3990
 
 
3991
        *status_vector++ = isc_arg_gds;
 
3992
        *status_vector++ = isc_unavailable;
 
3993
        *status_vector++ = isc_arg_end;
 
3994
 
 
3995
        return NULL;
 
3996
}
 
3997
#endif
 
3998
 
 
3999
 
 
4000
#if (defined UNIX)
 
4001
void ISC_reset_timer(
 
4002
                                         FPTR_VOID_PTR timeout_handler,
 
4003
                                         void *timeout_arg,
 
4004
                                         SLONG * client_timer, void **client_handler)
 
4005
{
 
4006
/**************************************
 
4007
 *
 
4008
 *      I S C _ r e s e t _ t i m e r
 
4009
 *
 
4010
 **************************************
 
4011
 *
 
4012
 * Functional description
 
4013
 *      Clear a previously established timer and restore
 
4014
 *      the previous context.
 
4015
 *
 
4016
 **************************************/
 
4017
        struct itimerval internal_timer;
 
4018
 
 
4019
        ISC_signal_cancel(SIGALRM, timeout_handler, timeout_arg);
 
4020
 
 
4021
/* Cancel the timer, then restore the previous handler and alarm */
 
4022
 
 
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);
 
4028
}
 
4029
#endif
 
4030
 
 
4031
 
 
4032
#if (defined UNIX)
 
4033
void ISC_set_timer(
 
4034
                                   SLONG micro_seconds,
 
4035
                                   FPTR_VOID_PTR timeout_handler,
 
4036
                                   void *timeout_arg,
 
4037
                                   SLONG * client_timer, void **client_handler)
 
4038
{
 
4039
/**************************************
 
4040
 *
 
4041
 *      I S C _ s e t _ t i m e r
 
4042
 *
 
4043
 **************************************
 
4044
 *
 
4045
 * Functional description
 
4046
 *      Set a timer for the specified amount of time.
 
4047
 *
 
4048
 **************************************/
 
4049
        struct itimerval internal_timer;
 
4050
        struct sigaction internal_handler;
 
4051
 
 
4052
/* Start by cancelling any existing timer */
 
4053
 
 
4054
        timerclear(&internal_timer.it_interval);
 
4055
        timerclear(&internal_timer.it_value);
 
4056
        setitimer(ITIMER_REAL, &internal_timer,
 
4057
                          (struct itimerval *) client_timer);
 
4058
 
 
4059
/* Now clear the signal handler while saving the existing one */
 
4060
 
 
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);
 
4066
 
 
4067
        if (!micro_seconds)
 
4068
                return;
 
4069
 
 
4070
/* Next set the new alarm handler and finally set the new timer */
 
4071
 
 
4072
        ISC_signal(SIGALRM, timeout_handler, timeout_arg);
 
4073
 
 
4074
        if (micro_seconds < 1000000)
 
4075
                internal_timer.it_value.tv_usec = micro_seconds;
 
4076
        else {
 
4077
                internal_timer.it_value.tv_sec = micro_seconds / 1000000;
 
4078
                internal_timer.it_value.tv_usec = micro_seconds % 1000000;
 
4079
        }
 
4080
        setitimer(ITIMER_REAL, &internal_timer, NULL);
 
4081
}
 
4082
#endif
 
4083
 
 
4084
 
 
4085
#ifdef SUPERSERVER
 
4086
#ifdef UNIX
 
4087
void ISC_sync_signals_set()
 
4088
{
 
4089
/**************************************
 
4090
 *
 
4091
 *      I S C _ s y n c _ s i g n a l s _ s e t( U N I X )
 
4092
 *
 
4093
 **************************************
 
4094
 *
 
4095
 * Functional description
 
4096
 *      Set all the synchronous signals for a particular thread
 
4097
 *
 
4098
 **************************************/
 
4099
 
 
4100
        sigset(SIGILL, longjmp_sig_handler);
 
4101
        sigset(SIGFPE, longjmp_sig_handler);
 
4102
        sigset(SIGBUS, longjmp_sig_handler);
 
4103
        sigset(SIGSEGV, longjmp_sig_handler);
 
4104
}
 
4105
#endif /* UNIX */
 
4106
#endif /* SUPERSERVER */
 
4107
 
 
4108
 
 
4109
#ifdef SUPERSERVER
 
4110
#ifdef UNIX
 
4111
void ISC_sync_signals_reset()
 
4112
{
 
4113
/**************************************
 
4114
 *
 
4115
 *      I S C _ s y n c _ s i g n a l s _ r e s e t ( U N I X )
 
4116
 *
 
4117
 **************************************
 
4118
 *
 
4119
 * Functional description
 
4120
 *      Reset all the synchronous signals for a particular thread
 
4121
 * to default.
 
4122
 *
 
4123
 **************************************/
 
4124
 
 
4125
        sigset(SIGILL, SIG_DFL);
 
4126
        sigset(SIGFPE, SIG_DFL);
 
4127
        sigset(SIGBUS, SIG_DFL);
 
4128
        sigset(SIGSEGV, SIG_DFL);
 
4129
}
 
4130
#endif /* UNIX */
 
4131
#endif /* SUPERSERVER */
 
4132
 
 
4133
#ifdef UNIX
 
4134
#ifdef HAVE_MMAP
 
4135
#define UNMAP_FILE
 
4136
void ISC_unmap_file(ISC_STATUS * status_vector, SH_MEM shmem_data, USHORT flag)
 
4137
{
 
4138
/**************************************
 
4139
 *
 
4140
 *      I S C _ u n m a p _ f i l e             ( U N I X - m m a p )
 
4141
 *
 
4142
 **************************************
 
4143
 *
 
4144
 * Functional description
 
4145
 *      Unmap a given file.  Depending upon the flag,
 
4146
 *      get rid of the semaphore and/or truncate the file.
 
4147
 *
 
4148
 **************************************/
 
4149
        union semun arg;
 
4150
 
 
4151
        munmap((char *) shmem_data->sh_mem_address,
 
4152
                   shmem_data->sh_mem_length_mapped);
 
4153
 
 
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);
 
4159
}
 
4160
#endif
 
4161
#endif
 
4162
 
 
4163
 
 
4164
#ifdef UNIX
 
4165
#ifndef HAVE_MMAP
 
4166
#define UNMAP_FILE
 
4167
void ISC_unmap_file(ISC_STATUS* status_vector, SH_MEM shmem_data, USHORT flag)
 
4168
{
 
4169
/**************************************
 
4170
 *
 
4171
 *      I S C _ u n m a p _ f i l e             ( U N I X - s h m a t )
 
4172
 *
 
4173
 **************************************
 
4174
 *
 
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.
 
4178
 *
 
4179
 **************************************/
 
4180
        struct shmid_ds buf;
 
4181
        union semun arg;
 
4182
 
 
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);
 
4188
}
 
4189
#endif
 
4190
#endif
 
4191
 
 
4192
 
 
4193
#ifdef WIN_NT
 
4194
#define UNMAP_FILE
 
4195
void ISC_unmap_file(ISC_STATUS * status_vector,
 
4196
                                        SH_MEM shmem_data,
 
4197
                                        USHORT flag)
 
4198
{
 
4199
/**************************************
 
4200
 *
 
4201
 *      I S C _ u n m a p _ f i l e             ( W I N _ N T )
 
4202
 *
 
4203
 **************************************
 
4204
 *
 
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.
 
4208
 *
 
4209
 **************************************/
 
4210
 
 
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);
 
4218
            
 
4219
        CloseHandle(shmem_data->sh_mem_handle);
 
4220
        UnmapViewOfFile(shmem_data->sh_mem_hdr_address);
 
4221
        CloseHandle(shmem_data->sh_mem_hdr_object);
 
4222
}
 
4223
#endif
 
4224
 
 
4225
 
 
4226
#ifndef UNMAP_FILE
 
4227
void ISC_unmap_file(ISC_STATUS * status_vector,
 
4228
                                        SH_MEM shmem_data,
 
4229
                                        USHORT flag)
 
4230
{
 
4231
/**************************************
 
4232
 *
 
4233
 *      I S C _ u n m a p _ f i l e             ( G E N E R I C )
 
4234
 *
 
4235
 **************************************
 
4236
 *
 
4237
 * Functional description
 
4238
 *      unmap a given file or shared memory.
 
4239
 *
 
4240
 **************************************/
 
4241
 
 
4242
        *status_vector++ = isc_arg_gds;
 
4243
        *status_vector++ = isc_unavailable;
 
4244
        *status_vector++ = isc_arg_end;
 
4245
}
 
4246
#endif
 
4247
 
 
4248
 
 
4249
#if defined(UNIX) && !defined(USE_POSIX_THREADS) && !defined(SOLARIS_MT)
 
4250
static void alarm_handler(void* arg)
 
4251
{
 
4252
/**************************************
 
4253
 *
 
4254
 *      a l a r m _ h a n d l e r       ( U N I X )
 
4255
 *
 
4256
 **************************************
 
4257
 *
 
4258
 * Functional description
 
4259
 *      Handle an alarm clock interrupt.
 
4260
 *
 
4261
 **************************************/
 
4262
}
 
4263
#endif
 
4264
 
 
4265
 
 
4266
static void error(ISC_STATUS* status_vector, TEXT* string, ISC_STATUS status)
 
4267
{
 
4268
/**************************************
 
4269
 *
 
4270
 *      e r r o r
 
4271
 *
 
4272
 **************************************
 
4273
 *
 
4274
 * Functional description
 
4275
 *      We've encountered an error, report it.
 
4276
 *
 
4277
 **************************************/
 
4278
 
 
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;
 
4286
}
 
4287
 
 
4288
 
 
4289
#ifdef VMS
 
4290
static int event_test(WAIT * wait)
 
4291
{
 
4292
/**************************************
 
4293
 *
 
4294
 *      e v e n t _ t e s t
 
4295
 *
 
4296
 **************************************
 
4297
 *
 
4298
 * Functional description
 
4299
 *      Callback routine from thread package for VMS.  Returns
 
4300
 *      TRUE if wait is satified, otherwise FALSE.
 
4301
 *
 
4302
 **************************************/
 
4303
 
 
4304
        return !ISC_event_blocked(wait->wait_count, wait->wait_events,
 
4305
                                                          wait->wait_values);
 
4306
}
 
4307
#endif
 
4308
 
 
4309
 
 
4310
#ifdef UNIX
 
4311
static SLONG find_key(ISC_STATUS * status_vector, TEXT * filename)
 
4312
{
 
4313
/**************************************
 
4314
 *
 
4315
 *      f i n d _ k e y
 
4316
 *
 
4317
 **************************************
 
4318
 *
 
4319
 * Functional description
 
4320
 *      Find the semaphore/shared memory key for a file.
 
4321
 *
 
4322
 **************************************/
 
4323
        int fd;
 
4324
        key_t key;
 
4325
 
 
4326
/* Produce shared memory key for file */
 
4327
 
 
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);
 
4331
                        return 0L;
 
4332
                }
 
4333
                close(fd);
 
4334
                if ((key = ftok(filename, FTOK_KEY)) == -1) {
 
4335
                        error(status_vector, "ftok", errno);
 
4336
                        return 0L;
 
4337
                }
 
4338
        }
 
4339
 
 
4340
        return key;
 
4341
}
 
4342
#endif
 
4343
 
 
4344
 
 
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)
 
4349
{
 
4350
/**************************************
 
4351
 *
 
4352
 *      o p e n _ s e m a p h o r e s           ( U N I X )
 
4353
 *
 
4354
 **************************************
 
4355
 *
 
4356
 * Functional description
 
4357
 *      Open existing block of semaphores.
 
4358
 *
 
4359
 **************************************/
 
4360
        // Open semaphore set
 
4361
        SLONG semid = semget(key, 0, 0);
 
4362
        if (semid == -1) {
 
4363
                error(status_vector, "semget", errno);
 
4364
                return -1;
 
4365
        }
 
4366
        
 
4367
        if (semaphores) {
 
4368
                union semun arg;
 
4369
                semid_ds buf;   
 
4370
                arg.buf = &buf;
 
4371
                // Get number of semaphores in opened set
 
4372
                if (semctl(semid, 0, IPC_STAT, arg) == -1) {
 
4373
                        error(status_vector, "semctl", errno);
 
4374
                        return -1;
 
4375
                }
 
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;
 
4381
                }
 
4382
        }
 
4383
 
 
4384
        return semid;
 
4385
}
 
4386
 
 
4387
static SLONG create_semaphores(
 
4388
                                                         ISC_STATUS * status_vector,
 
4389
                                                         SLONG key, int semaphores)
 
4390
{
 
4391
/**************************************
 
4392
 *
 
4393
 *      c r e a t e _ s e m a p h o r e s               ( U N I X )
 
4394
 *
 
4395
 **************************************
 
4396
 *
 
4397
 * Functional description
 
4398
 *      Create or find a block of semaphores.
 
4399
 *
 
4400
 **************************************/
 
4401
        SLONG semid;
 
4402
        while (true)
 
4403
        {
 
4404
                // Try to open existing semaphore set
 
4405
                semid = semget(key, 0, 0);
 
4406
                if (semid == -1) {
 
4407
                        if (errno != ENOENT) {
 
4408
                                error(status_vector, "semget", errno);
 
4409
                                return -1;
 
4410
                        }
 
4411
                } 
 
4412
                else
 
4413
                {
 
4414
                        union semun arg;
 
4415
                        semid_ds buf;   
 
4416
                        arg.buf = &buf;
 
4417
                        // Get number of semaphores in opened set
 
4418
                        if (semctl(semid, 0, IPC_STAT, arg) == -1) {
 
4419
                                error(status_vector, "semctl", errno);
 
4420
                                return -1;
 
4421
                        }
 
4422
                        if ((int) buf.sem_nsems >= semaphores)
 
4423
                                return semid;
 
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);
 
4427
                                return -1;
 
4428
                        }
 
4429
                }
 
4430
                
 
4431
                // Try to create new semaphore set
 
4432
                semid = semget(key, semaphores, IPC_CREAT | IPC_EXCL | PRIV);
 
4433
                if (semid != -1)
 
4434
                {
 
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);
 
4439
                        struct stat st;
 
4440
                        if (stat(secDb, &st) == 0)
 
4441
                        {
 
4442
                                union semun arg;
 
4443
                                semid_ds ds;
 
4444
                                arg.buf = &ds;
 
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);
 
4449
                        }
 
4450
                        return semid;
 
4451
                }
 
4452
                else
 
4453
                {
 
4454
                        if (errno != EEXIST) {
 
4455
                                error(status_vector, "semget", errno);
 
4456
                                return -1;
 
4457
                        }
 
4458
                }
 
4459
        }
 
4460
}
 
4461
#endif
 
4462
 
 
4463
 
 
4464
#ifdef SUPERSERVER
 
4465
#ifdef UNIX
 
4466
void longjmp_sig_handler(int sig_num)
 
4467
{
 
4468
/**************************************
 
4469
 *
 
4470
 *      l o n g j m p _ s i g _ h a n d l e r
 
4471
 *
 
4472
 **************************************
 
4473
 *
 
4474
 * Functional description
 
4475
 *      The generic signal handler for all signals in a thread.
 
4476
 *
 
4477
 **************************************/
 
4478
 
 
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. */
 
4484
 
 
4485
        thread_db* tdbb = JRD_get_thread_data();
 
4486
 
 
4487
        siglongjmp(tdbb->tdbb_sigsetjmp, sig_num);
 
4488
}
 
4489
#endif /* UNIX */
 
4490
#endif /* SUPERSERVER */
 
4491
 
 
4492
 
 
4493
#ifdef VMS
 
4494
static BOOLEAN mutex_test(MTX mutex)
 
4495
{
 
4496
/**************************************
 
4497
 *
 
4498
 *      m u t e x _ t e s t
 
4499
 *
 
4500
 **************************************
 
4501
 *
 
4502
 * Functional description
 
4503
 *      Callback routine from thread package for VMS.  Returns
 
4504
 *      TRUE if mutex has been granted, otherwise FALSE.
 
4505
 *
 
4506
 **************************************/
 
4507
 
 
4508
        return (mutex->mtx_event_count[0] & 1) ? FALSE : TRUE;
 
4509
}
 
4510
#endif
 
4511
 
 
4512
 
 
4513
#ifdef WIN_NT
 
4514
static void make_object_name(
 
4515
                             TEXT* buffer,
 
4516
                                 size_t bufsize,
 
4517
                             const TEXT* object_name,
 
4518
                             const TEXT* object_type)
 
4519
{
 
4520
/**************************************
 
4521
 *
 
4522
 *      m a k e _ o b j e c t _ n a m e         ( W I N _ N T )
 
4523
 *
 
4524
 **************************************
 
4525
 *
 
4526
 * Functional description
 
4527
 *      Create an object name from a name and type.
 
4528
 *      Also replace the file separator with "_".
 
4529
 *
 
4530
 **************************************/
 
4531
        char hostname[64];
 
4532
        _snprintf(buffer, bufsize, object_name, ISC_get_host(hostname, sizeof(hostname)));
 
4533
        buffer[bufsize - 1] = 0;
 
4534
        
 
4535
        char* p;
 
4536
        char c;
 
4537
        for (p = buffer; c = *p; p++)
 
4538
                if (c == '/' || c == '\\' || c == ':')
 
4539
                        *p = '_';
 
4540
        strcpy(p, object_type);
 
4541
 
 
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
 
4547
        strlwr(buffer);
 
4548
 
 
4549
#ifndef EMBEDDED
 
4550
        fb_utils::prefix_kernel_object_name(buffer, bufsize);
 
4551
#endif
 
4552
}
 
4553
#endif
 
4554
 
 
4555
 
 
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)
 
4559
{
 
4560
/**************************************
 
4561
 *
 
4562
 *      s e m a p h o r e _ w a i t  _ i s c _ s y n c
 
4563
 *
 
4564
 *  (formerly known as: s e m a p h o r e _ w a i t)
 
4565
 *
 
4566
 **************************************
 
4567
 *
 
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.
 
4572
 *
 
4573
 **************************************/
 
4574
#pragma FB_COMPILER_MESSAGE("Warning: B.O. with more than 16 inputs")
 
4575
 
 
4576
        struct sembuf semops[16];
 
4577
        struct sembuf* semptr = semops;
 
4578
        for (int i = 0; i < count; ++semptr, i++) {
 
4579
                semptr->sem_op = 0;
 
4580
                semptr->sem_flg = 0;
 
4581
                semptr->sem_num = *semnums++;
 
4582
        }
 
4583
        int ret = semop(semid, semops, count);
 
4584
 
 
4585
        if (ret == -1 && SYSCALL_INTERRUPTED(errno))
 
4586
                return false;
 
4587
        else
 
4588
                return true;
 
4589
}
 
4590
#endif
 
4591
 
 
4592
 
 
4593