1
/* S H A R E D M E M O R Y D R I V E R
2
=======================================
4
by Jerzy.Borkowski@obs.unige.ch
6
09-Mar-98 : initial version 1.0 released
7
23-Mar-98 : shared_malloc now accepts new handle as an argument
8
23-Mar-98 : shmem://0, shmem://1, etc changed to shmem://h0, etc due to bug
10
10-Apr-98 : code cleanup
11
13-May-99 : delayed initialization added, global table deleted on exit when
12
no shmem segments remain, and last process terminates
15
#ifdef HAVE_SHMEM_SERVICES
16
#include "fitsio2.h" /* drvrsmem.h is included by it */
22
#include <sys/types.h>
28
static int shared_kbase = 0; /* base for shared memory handles */
29
static int shared_maxseg = 0; /* max number of shared memory blocks */
30
static int shared_range = 0; /* max number of tried entries */
31
static int shared_fd = SHARED_INVALID; /* handle of global access lock file */
32
static int shared_gt_h = SHARED_INVALID; /* handle of global table segment */
33
static SHARED_LTAB *shared_lt = NULL; /* local table pointer */
34
static SHARED_GTAB *shared_gt = NULL; /* global table pointer */
35
static int shared_create_mode = 0666; /* permission flags for created objects */
36
static int shared_debug = 1; /* simple debugging tool, set to 0 to disable messages */
37
static int shared_init_called = 0; /* flag whether shared_init() has been called, used for delayed init */
39
/* static support routines prototypes */
41
static int shared_clear_entry(int idx); /* unconditionally clear entry */
42
static int shared_destroy_entry(int idx); /* unconditionally destroy sema & shseg and clear entry */
43
static int shared_mux(int idx, int mode); /* obtain exclusive access to specified segment */
44
static int shared_demux(int idx, int mode); /* free exclusive access to specified segment */
46
static int shared_process_count(int sem); /* valid only for time of invocation */
47
static int shared_delta_process(int sem, int delta); /* change number of processes hanging on segment */
48
static int shared_attach_process(int sem);
49
static int shared_detach_process(int sem);
50
static int shared_get_free_entry(int newhandle); /* get free entry in shared_key, or -1, entry is set rw locked */
51
static int shared_get_hash(long size, int idx);/* return hash value for malloc */
52
static long shared_adjust_size(long size); /* size must be >= 0 !!! */
53
static int shared_check_locked_index(int idx); /* verify that given idx is valid */
54
static int shared_map(int idx); /* map all tables for given idx, check for validity */
55
static int shared_validate(int idx, int mode); /* use intrnally inside crit.sect !!! */
57
/* support routines - initialization */
60
static int shared_clear_entry(int idx) /* unconditionally clear entry */
61
{ if ((idx < 0) || (idx >= shared_maxseg)) return(SHARED_BADARG);
62
shared_gt[idx].key = SHARED_INVALID; /* clear entries in global table */
63
shared_gt[idx].handle = SHARED_INVALID;
64
shared_gt[idx].sem = SHARED_INVALID;
65
shared_gt[idx].semkey = SHARED_INVALID;
66
shared_gt[idx].nprocdebug = 0;
67
shared_gt[idx].size = 0;
68
shared_gt[idx].attr = 0;
73
static int shared_destroy_entry(int idx) /* unconditionally destroy sema & shseg and clear entry */
77
if ((idx < 0) || (idx >= shared_maxseg)) return(SHARED_BADARG);
79
filler.val = 0; /* this is to make cc happy (warning otherwise) */
80
if (SHARED_INVALID != shared_gt[idx].sem) r = semctl(shared_gt[idx].sem, 0, IPC_RMID, filler); /* destroy semaphore */
81
if (SHARED_INVALID != shared_gt[idx].handle) r2 = shmctl(shared_gt[idx].handle, IPC_RMID, 0); /* destroy shared memory segment */
82
if (SHARED_OK == r) r = r2; /* accumulate error code in r, free r2 */
83
r2 = shared_clear_entry(idx);
84
return((SHARED_OK == r) ? r2 : r);
87
void shared_cleanup(void) /* this must (should) be called during exit/abort */
88
{ int i, j, r, oktodelete, filelocked, segmentspresent;
92
if (shared_debug) printf("shared_cleanup:");
93
if (NULL != shared_lt)
94
{ if (shared_debug) printf(" deleting segments:");
95
for (i=0; i<shared_maxseg; i++)
96
{ if (0 == shared_lt[i].tcnt) continue; /* we're not using this segment, skip this ... */
97
if (-1 != shared_lt[i].lkcnt) continue; /* seg not R/W locked by us, skip this ... */
99
r = shared_destroy_entry(i); /* destroy unconditionally sema & segment */
101
{ if (SHARED_OK == r) printf(" [%d]", i);
102
else printf(" [error on %d !!!!]", i);
106
free((void *)shared_lt); /* free local table */
109
if (NULL != shared_gt) /* detach global index table */
112
if (shared_debug) printf(" detaching globalsharedtable");
113
if (SHARED_INVALID != shared_fd)
115
flk.l_type = F_WRLCK; /* lock whole lock file */
118
flk.l_len = shared_maxseg;
119
if (-1 != fcntl(shared_fd, F_SETLK, &flk))
120
{ filelocked = 1; /* success, scan global table, to see if there are any segs */
121
segmentspresent = 0; /* assume, there are no segs in the system */
122
for (j=0; j<shared_maxseg; j++)
123
{ if (SHARED_INVALID != shared_gt[j].key)
124
{ segmentspresent = 1; /* yes, there is at least one */
128
if (0 == segmentspresent) /* if there are no segs ... */
129
if (0 == shmctl(shared_gt_h, IPC_STAT, &ds)) /* get number of processes attached to table */
130
{ if (ds.shm_nattch <= 1) oktodelete = 1; /* if only one (we), then it is safe (but see text 4 lines later) to unlink */
133
shmdt((char *)shared_gt); /* detach global table */
134
if (oktodelete) /* delete global table from system, if no shm seg present */
135
{ shmctl(shared_gt_h, IPC_RMID, 0); /* there is a race condition here - time window between shmdt and shmctl */
136
shared_gt_h = SHARED_INVALID;
139
if (filelocked) /* if we locked, we need to unlock */
140
{ flk.l_type = F_UNLCK;
143
flk.l_len = shared_maxseg;
144
fcntl(shared_fd, F_SETLK, &flk);
147
shared_gt_h = SHARED_INVALID;
149
if (SHARED_INVALID != shared_fd) /* close lock file */
150
{ if (shared_debug) printf(" closing lockfile");
152
shared_fd = SHARED_INVALID;
159
shared_init_called = 0;
161
if (shared_debug) printf(" <<done>>\n");
166
int shared_init(int debug_msgs) /* initialize shared memory stuff, you have to call this routine once */
171
shared_init_called = 1; /* tell everybody no need to call us for the 2nd time */
172
shared_debug = debug_msgs; /* set required debug mode */
174
if (shared_debug) printf("shared_init:");
176
shared_kbase = 0; /* adapt to current env. settings */
177
if (NULL != (p = getenv(SHARED_ENV_KEYBASE))) shared_kbase = atoi(p);
178
if (0 == shared_kbase) shared_kbase = SHARED_KEYBASE;
179
if (shared_debug) printf(" keybase=%d", shared_kbase);
182
if (NULL != (p = getenv(SHARED_ENV_MAXSEG))) shared_maxseg = atoi(p);
183
if (0 == shared_maxseg) shared_maxseg = SHARED_MAXSEG;
184
if (shared_debug) printf(" maxseg=%d", shared_maxseg);
186
shared_range = 3 * shared_maxseg;
188
if (SHARED_INVALID == shared_fd) /* create rw locking file (this file is never deleted) */
189
{ if (shared_debug) printf(" lockfileinit=");
190
sprintf(buf, "%s.%d.%d", SHARED_FDNAME, shared_kbase, shared_maxseg);
193
shared_fd = open(buf, O_TRUNC | O_EXCL | O_CREAT | O_RDWR, shared_create_mode);
195
if (SHARED_INVALID == shared_fd) /* or just open rw locking file, in case it already exists */
196
{ shared_fd = open(buf, O_TRUNC | O_RDWR, shared_create_mode);
197
if (SHARED_INVALID == shared_fd) return(SHARED_NOFILE);
198
if (shared_debug) printf("slave");
202
{ if (shared_debug) printf("master");
206
if (SHARED_INVALID == shared_gt_h) /* global table not attached, try to create it in shared memory */
207
{ if (shared_debug) printf(" globalsharedtableinit=");
208
shared_gt_h = shmget(shared_kbase, shared_maxseg * sizeof(SHARED_GTAB), IPC_CREAT | IPC_EXCL | shared_create_mode); /* try open as a master */
209
if (SHARED_INVALID == shared_gt_h) /* if failed, try to open as a slave */
210
{ shared_gt_h = shmget(shared_kbase, shared_maxseg * sizeof(SHARED_GTAB), shared_create_mode);
211
if (SHARED_INVALID == shared_gt_h) return(SHARED_IPCERR); /* means deleted ID residing in system, shared mem unusable ... */
212
shared_gt = (SHARED_GTAB *)shmat(shared_gt_h, 0, 0); /* attach segment */
213
if (((SHARED_GTAB *)SHARED_INVALID) == shared_gt) return(SHARED_IPCERR);
214
if (shared_debug) printf("slave");
217
{ shared_gt = (SHARED_GTAB *)shmat(shared_gt_h, 0, 0); /* attach segment */
218
if (((SHARED_GTAB *)SHARED_INVALID) == shared_gt) return(SHARED_IPCERR);
219
for (i=0; i<shared_maxseg; i++) shared_clear_entry(i); /* since we are master, init data */
220
if (shared_debug) printf("master");
224
if (NULL == shared_lt) /* initialize local table */
225
{ if (shared_debug) printf(" localtableinit=");
226
if (NULL == (shared_lt = (SHARED_LTAB *)malloc(shared_maxseg * sizeof(SHARED_LTAB)))) return(SHARED_NOMEM);
227
for (i=0; i<shared_maxseg; i++)
228
{ shared_lt[i].p = NULL; /* not mapped */
229
shared_lt[i].tcnt = 0; /* unused (or zero threads using this seg) */
230
shared_lt[i].lkcnt = 0; /* segment is unlocked */
231
shared_lt[i].seekpos = 0L; /* r/w pointer at the beginning of file */
233
if (shared_debug) printf("ok");
236
atexit(shared_cleanup); /* we want shared_cleanup to be called at exit or abort */
238
if (shared_debug) printf(" <<done>>\n");
243
int shared_recover(int id) /* try to recover dormant segments after applic crash */
246
if (NULL == shared_gt) return(SHARED_NOTINIT); /* not initialized */
247
if (NULL == shared_lt) return(SHARED_NOTINIT); /* not initialized */
249
for (i=0; i<shared_maxseg; i++)
250
{ if (-1 != id) if (i != id) continue;
251
if (shared_lt[i].tcnt) continue; /* somebody (we) is using it */
252
if (SHARED_INVALID == shared_gt[i].key) continue; /* unused slot */
253
if (shared_mux(i, SHARED_NOWAIT | SHARED_RDWRITE)) continue; /* acquire exclusive access to segment, but do not wait */
254
r2 = shared_process_count(shared_gt[i].sem);
255
if ((shared_gt[i].nprocdebug > r2) || (0 == r2))
256
{ if (shared_debug) printf("Bogus handle=%d nproc=%d sema=%d:", i, shared_gt[i].nprocdebug, r2);
257
r = shared_destroy_entry(i);
259
{ printf("%s", r ? "error couldn't clear handle" : "handle cleared");
262
shared_demux(i, SHARED_RDWRITE);
264
return(r); /* table full */
267
/* API routines - mutexes and locking */
269
static int shared_mux(int idx, int mode) /* obtain exclusive access to specified segment */
274
if (0 == shared_init_called) /* delayed initialization */
275
{ if (SHARED_OK != (r = shared_init(0))) return(r);
278
if (SHARED_INVALID == shared_fd) return(SHARED_NOTINIT);
279
if ((idx < 0) || (idx >= shared_maxseg)) return(SHARED_BADARG);
280
flk.l_type = ((mode & SHARED_RDWRITE) ? F_WRLCK : F_RDLCK);
284
if (shared_debug) printf(" [mux (%d): ", idx);
285
if (-1 == fcntl(shared_fd, ((mode & SHARED_NOWAIT) ? F_SETLK : F_SETLKW), &flk))
289
case EACCES: if (shared_debug) printf("again]");
290
return(SHARED_AGAIN);
291
default: if (shared_debug) printf("err]");
292
return(SHARED_IPCERR);
295
if (shared_debug) printf("ok]");
301
static int shared_demux(int idx, int mode) /* free exclusive access to specified segment */
304
if (SHARED_INVALID == shared_fd) return(SHARED_NOTINIT);
305
if ((idx < 0) || (idx >= shared_maxseg)) return(SHARED_BADARG);
306
flk.l_type = F_UNLCK;
310
if (shared_debug) printf(" [demux (%d): ", idx);
311
if (-1 == fcntl(shared_fd, F_SETLKW, &flk))
314
case EACCES: if (shared_debug) printf("again]");
315
return(SHARED_AGAIN);
316
default: if (shared_debug) printf("err]");
317
return(SHARED_IPCERR);
321
if (shared_debug) printf("mode=%d ok]", mode);
327
static int shared_process_count(int sem) /* valid only for time of invocation */
330
su.val = 0; /* to force compiler not to give warning messages */
331
return(semctl(sem, 0, GETVAL, su)); /* su is unused here */
335
static int shared_delta_process(int sem, int delta) /* change number of processes hanging on segment */
338
if (SHARED_INVALID == sem) return(SHARED_BADARG); /* semaphore not attached */
341
sb.sem_flg = SEM_UNDO;
342
return((-1 == semop(sem, &sb, 1)) ? SHARED_IPCERR : SHARED_OK);
346
static int shared_attach_process(int sem)
347
{ if (shared_debug) printf(" [attach process]");
348
return(shared_delta_process(sem, 1));
352
static int shared_detach_process(int sem)
353
{ if (shared_debug) printf(" [detach process]");
354
return(shared_delta_process(sem, -1));
357
/* API routines - hashing and searching */
360
static int shared_get_free_entry(int newhandle) /* get newhandle, or -1, entry is set rw locked */
362
if (NULL == shared_gt) return(-1); /* not initialized */
363
if (NULL == shared_lt) return(-1); /* not initialized */
364
if (newhandle < 0) return(-1);
365
if (newhandle >= shared_maxseg) return(-1);
366
if (shared_lt[newhandle].tcnt) return(-1); /* somebody (we) is using it */
367
if (shared_mux(newhandle, SHARED_NOWAIT | SHARED_RDWRITE)) return(-1); /* used by others */
368
if (SHARED_INVALID == shared_gt[newhandle].key) return(newhandle); /* we have found free slot, lock it and return index */
369
shared_demux(newhandle, SHARED_RDWRITE);
370
if (shared_debug) printf("[free_entry - ERROR - entry unusable]");
371
return(-1); /* table full */
375
static int shared_get_hash(long size, int idx) /* return hash value for malloc */
376
{ static int counter = 0;
379
hash = (counter + size * idx) % shared_range;
380
counter = (counter + 1) % shared_range;
385
static long shared_adjust_size(long size) /* size must be >= 0 !!! */
386
{ return(((size + sizeof(BLKHEAD) + SHARED_GRANUL - 1) / SHARED_GRANUL) * SHARED_GRANUL); }
389
/* API routines - core : malloc/realloc/free/attach/detach/lock/unlock */
391
int shared_malloc(long size, int mode, int newhandle) /* return idx or SHARED_INVALID */
392
{ int h, i, r, idx, key;
396
if (0 == shared_init_called) /* delayed initialization */
397
{ if (SHARED_OK != (r = shared_init(0))) return(r);
399
if (shared_debug) printf("malloc (size = %ld, mode = %d):", size, mode);
400
if (size < 0) return(SHARED_INVALID);
401
if (-1 == (idx = shared_get_free_entry(newhandle))) return(SHARED_INVALID);
402
if (shared_debug) printf(" idx=%d", idx);
404
{ if (i >= shared_range) /* table full, signal error & exit */
405
{ shared_demux(idx, SHARED_RDWRITE);
406
return(SHARED_INVALID);
408
key = shared_kbase + ((i + shared_get_hash(size, idx)) % shared_range);
409
if (shared_debug) printf(" key=%d", key);
410
h = shmget(key, shared_adjust_size(size), IPC_CREAT | IPC_EXCL | shared_create_mode);
411
if (shared_debug) printf(" handle=%d", h);
412
if (SHARED_INVALID == h) continue; /* segment already accupied */
413
bp = (BLKHEAD *)shmat(h, 0, 0); /* try attach */
414
if (shared_debug) printf(" p=%p", bp);
415
if (((BLKHEAD *)SHARED_INVALID) == bp) /* cannot attach, delete segment, try with another key */
416
{ shmctl(h, IPC_RMID, 0);
418
} /* now create semaphor counting number of processes attached */
419
if (SHARED_INVALID == (shared_gt[idx].sem = semget(key, 1, IPC_CREAT | IPC_EXCL | shared_create_mode)))
420
{ shmdt((void *)bp); /* cannot create segment, delete everything */
421
shmctl(h, IPC_RMID, 0);
422
continue; /* try with another key */
424
if (shared_debug) printf(" sem=%d", shared_gt[idx].sem);
425
if (shared_attach_process(shared_gt[idx].sem)) /* try attach process */
426
{ semctl(shared_gt[idx].sem, 0, IPC_RMID, filler); /* destroy semaphore */
427
shmdt((char *)bp); /* detach shared mem segment */
428
shmctl(h, IPC_RMID, 0); /* destroy shared mem segment */
429
continue; /* try with another key */
431
bp->s.tflag = BLOCK_SHARED; /* fill in data in segment's header (this is really not necessary) */
432
bp->s.ID[0] = SHARED_ID_0;
433
bp->s.ID[1] = SHARED_ID_1;
434
bp->s.handle = idx; /* used in yorick */
435
if (mode & SHARED_RESIZE)
436
{ if (shmdt((char *)bp)) r = SHARED_IPCERR; /* if segment is resizable, then detach segment */
437
shared_lt[idx].p = NULL;
439
else { shared_lt[idx].p = bp; }
440
shared_lt[idx].tcnt = 1; /* one thread using segment */
441
shared_lt[idx].lkcnt = 0; /* no locks at the moment */
442
shared_lt[idx].seekpos = 0L; /* r/w pointer positioned at beg of block */
443
shared_gt[idx].handle = h; /* fill in data in global table */
444
shared_gt[idx].size = size;
445
shared_gt[idx].attr = mode;
446
shared_gt[idx].semkey = key;
447
shared_gt[idx].key = key;
448
shared_gt[idx].nprocdebug = 0;
452
shared_demux(idx, SHARED_RDWRITE); /* hope this will not fail */
457
int shared_attach(int idx)
460
if (SHARED_OK != (r = shared_mux(idx, SHARED_RDWRITE | SHARED_WAIT))) return(r);
461
if (SHARED_OK != (r = shared_map(idx)))
462
{ shared_demux(idx, SHARED_RDWRITE);
465
if (shared_attach_process(shared_gt[idx].sem)) /* try attach process */
466
{ shmdt((char *)(shared_lt[idx].p)); /* cannot attach process, detach everything */
467
shared_lt[idx].p = NULL;
468
shared_demux(idx, SHARED_RDWRITE);
469
return(SHARED_BADARG);
471
shared_lt[idx].tcnt++; /* one more thread is using segment */
472
if (shared_gt[idx].attr & SHARED_RESIZE) /* if resizeable, detach and return special pointer */
473
{ if (shmdt((char *)(shared_lt[idx].p))) r = SHARED_IPCERR; /* if segment is resizable, then detach segment */
474
shared_lt[idx].p = NULL;
476
shared_lt[idx].seekpos = 0L; /* r/w pointer positioned at beg of block */
477
r2 = shared_demux(idx, SHARED_RDWRITE);
483
static int shared_check_locked_index(int idx) /* verify that given idx is valid */
486
if (0 == shared_init_called) /* delayed initialization */
487
{ if (SHARED_OK != (r = shared_init(0))) return(r);
490
if ((idx < 0) || (idx >= shared_maxseg)) return(SHARED_BADARG);
491
if (NULL == shared_lt[idx].p) return(SHARED_BADARG); /* NULL pointer, not attached ?? */
492
if (0 == shared_lt[idx].lkcnt) return(SHARED_BADARG); /* not locked ?? */
493
if ((SHARED_ID_0 != (shared_lt[idx].p)->s.ID[0]) || (SHARED_ID_1 != (shared_lt[idx].p)->s.ID[1]) ||
494
(BLOCK_SHARED != (shared_lt[idx].p)->s.tflag)) /* invalid data in segment */
495
return(SHARED_BADARG);
501
static int shared_map(int idx) /* map all tables for given idx, check for validity */
502
{ int h; /* have to obtain excl. access before calling shared_map */
505
if ((idx < 0) || (idx >= shared_maxseg)) return(SHARED_BADARG);
506
if (SHARED_INVALID == shared_gt[idx].key) return(SHARED_BADARG);
507
if (SHARED_INVALID == (h = shmget(shared_gt[idx].key, 1, shared_create_mode))) return(SHARED_BADARG);
508
if (((BLKHEAD *)SHARED_INVALID) == (bp = (BLKHEAD *)shmat(h, 0, 0))) return(SHARED_BADARG);
509
if ((SHARED_ID_0 != bp->s.ID[0]) || (SHARED_ID_1 != bp->s.ID[1]) || (BLOCK_SHARED != bp->s.tflag) || (h != shared_gt[idx].handle))
510
{ shmdt((char *)bp); /* invalid segment, detach everything */
511
return(SHARED_BADARG);
514
if (shared_gt[idx].sem != semget(shared_gt[idx].semkey, 1, shared_create_mode)) /* check if sema is still there */
515
{ shmdt((char *)bp); /* cannot attach semaphore, detach everything */
516
return(SHARED_BADARG);
518
shared_lt[idx].p = bp; /* store pointer to shmem data */
523
static int shared_validate(int idx, int mode) /* use intrnally inside crit.sect !!! */
526
if (SHARED_OK != (r = shared_mux(idx, mode))) return(r); /* idx checked by shared_mux */
527
if (NULL == shared_lt[idx].p)
528
if (SHARED_OK != (r = shared_map(idx)))
529
{ shared_demux(idx, mode);
532
if ((SHARED_ID_0 != (shared_lt[idx].p)->s.ID[0]) || (SHARED_ID_1 != (shared_lt[idx].p)->s.ID[1]) || (BLOCK_SHARED != (shared_lt[idx].p)->s.tflag))
533
{ shared_demux(idx, mode);
540
SHARED_P shared_realloc(int idx, long newsize) /* realloc shared memory segment */
546
if (newsize < 0) return(NULL);
547
if (shared_check_locked_index(idx)) return(NULL);
548
if (0 == (shared_gt[idx].attr & SHARED_RESIZE)) return(NULL);
549
if (-1 != shared_lt[idx].lkcnt) return(NULL); /* check for RW lock */
550
if (shared_adjust_size(shared_gt[idx].size) == shared_adjust_size(newsize))
551
{ shared_gt[idx].size = newsize;
553
return((SHARED_P)((shared_lt[idx].p) + 1));
556
{ if (i >= shared_range) return(NULL); /* table full, signal error & exit */
557
key = shared_kbase + ((i + shared_get_hash(newsize, idx)) % shared_range);
558
h = shmget(key, shared_adjust_size(newsize), IPC_CREAT | IPC_EXCL | shared_create_mode);
559
if (SHARED_INVALID == h) continue; /* segment already accupied */
560
bp = (BLKHEAD *)shmat(h, 0, 0); /* try attach */
561
if (((BLKHEAD *)SHARED_INVALID) == bp) /* cannot attach, delete segment, try with another key */
562
{ shmctl(h, IPC_RMID, 0);
565
*bp = *(shared_lt[idx].p); /* copy header, then data */
566
transfersize = ((newsize < shared_gt[idx].size) ? newsize : shared_gt[idx].size);
567
if (transfersize > 0)
568
memcpy((void *)(bp + 1), (void *)((shared_lt[idx].p) + 1), transfersize);
569
if (shmdt((char *)(shared_lt[idx].p))) r = SHARED_IPCERR; /* try to detach old segment */
570
if (shmctl(shared_gt[idx].handle, IPC_RMID, 0)) if (SHARED_OK == r) r = SHARED_IPCERR; /* destroy old shared memory segment */
571
shared_gt[idx].size = newsize; /* signal new size */
572
shared_gt[idx].handle = h; /* signal new handle */
573
shared_gt[idx].key = key; /* signal new key */
574
shared_lt[idx].p = bp;
577
return((SHARED_P)(bp + 1));
581
int shared_free(int idx) /* detach segment, if last process & !PERSIST, destroy segment */
584
if (SHARED_OK != (r = shared_validate(idx, SHARED_RDWRITE | SHARED_WAIT))) return(r);
585
if (SHARED_OK != (r = shared_detach_process(shared_gt[idx].sem))) /* update number of processes using segment */
586
{ shared_demux(idx, SHARED_RDWRITE);
589
shared_lt[idx].tcnt--; /* update number of threads using segment */
590
if (shared_lt[idx].tcnt > 0) return(shared_demux(idx, SHARED_RDWRITE)); /* if more threads are using segment we are done */
591
if (shmdt((char *)(shared_lt[idx].p))) /* if, we are the last thread, try to detach segment */
592
{ shared_demux(idx, SHARED_RDWRITE);
593
return(SHARED_IPCERR);
595
shared_lt[idx].p = NULL; /* clear entry in local table */
596
shared_lt[idx].seekpos = 0L; /* r/w pointer positioned at beg of block */
597
if (-1 == (cnt = shared_process_count(shared_gt[idx].sem))) /* get number of processes hanging on segment */
598
{ shared_demux(idx, SHARED_RDWRITE);
599
return(SHARED_IPCERR);
601
if ((0 == cnt) && (0 == (shared_gt[idx].attr & SHARED_PERSIST))) r = shared_destroy_entry(idx); /* no procs on seg, destroy it */
602
r2 = shared_demux(idx, SHARED_RDWRITE);
607
SHARED_P shared_lock(int idx, int mode) /* lock given segment for exclusive access */
610
if (shared_mux(idx, mode)) return(NULL); /* idx checked by shared_mux */
611
if (0 != shared_lt[idx].lkcnt) /* are we already locked ?? */
612
if (SHARED_OK != (r = shared_map(idx)))
613
{ shared_demux(idx, mode);
616
if (NULL == shared_lt[idx].p) /* stupid pointer ?? */
617
if (SHARED_OK != (r = shared_map(idx)))
618
{ shared_demux(idx, mode);
621
if ((SHARED_ID_0 != (shared_lt[idx].p)->s.ID[0]) || (SHARED_ID_1 != (shared_lt[idx].p)->s.ID[1]) || (BLOCK_SHARED != (shared_lt[idx].p)->s.tflag))
622
{ shared_demux(idx, mode);
625
if (mode & SHARED_RDWRITE)
626
{ shared_lt[idx].lkcnt = -1;
628
shared_gt[idx].nprocdebug++;
631
else shared_lt[idx].lkcnt++;
632
shared_lt[idx].seekpos = 0L; /* r/w pointer positioned at beg of block */
633
return((SHARED_P)((shared_lt[idx].p) + 1));
637
int shared_unlock(int idx) /* unlock given segment, assumes seg is locked !! */
640
if (SHARED_OK != (r = shared_check_locked_index(idx))) return(r);
641
if (shared_lt[idx].lkcnt > 0)
642
{ shared_lt[idx].lkcnt--; /* unlock read lock */
643
mode = SHARED_RDONLY;
646
{ shared_lt[idx].lkcnt = 0; /* unlock write lock */
647
shared_gt[idx].nprocdebug--;
648
mode = SHARED_RDWRITE;
650
if (0 == shared_lt[idx].lkcnt) if (shared_gt[idx].attr & SHARED_RESIZE)
651
{ if (shmdt((char *)(shared_lt[idx].p))) r = SHARED_IPCERR; /* segment is resizable, then detach segment */
652
shared_lt[idx].p = NULL; /* signal detachment in local table */
654
r2 = shared_demux(idx, mode); /* unlock segment, rest is only parameter checking */
658
/* API routines - support and info routines */
661
int shared_attr(int idx) /* get the attributes of the shared memory segment */
664
if (shared_check_locked_index(idx)) return(SHARED_INVALID);
665
r = shared_gt[idx].attr;
670
int shared_set_attr(int idx, int newattr) /* get the attributes of the shared memory segment */
673
if (shared_check_locked_index(idx)) return(SHARED_INVALID);
674
if (-1 != shared_lt[idx].lkcnt) return(SHARED_INVALID); /* ADDED - check for RW lock */
675
r = shared_gt[idx].attr;
676
shared_gt[idx].attr = newattr;
682
int shared_set_debug(int mode) /* set/reset debug mode */
683
{ int r = shared_debug;
690
int shared_set_createmode(int mode) /* set/reset debug mode */
691
{ int r = shared_create_mode;
693
shared_create_mode = mode;
700
int shared_list(int id)
703
if (NULL == shared_gt) return(SHARED_NOTINIT); /* not initialized */
704
if (NULL == shared_lt) return(SHARED_NOTINIT); /* not initialized */
705
if (shared_debug) printf("shared_list:");
707
printf(" Idx Key Nproc Size Flags\n");
708
printf("==============================================\n");
709
for (i=0; i<shared_maxseg; i++)
710
{ if (-1 != id) if (i != id) continue;
711
if (SHARED_INVALID == shared_gt[i].key) continue; /* unused slot */
712
switch (shared_mux(i, SHARED_NOWAIT | SHARED_RDONLY)) /* acquire exclusive access to segment, but do not wait */
715
printf("!%3d %08lx %4d %8d", i, (unsigned long int)shared_gt[i].key,
716
shared_gt[i].nprocdebug, shared_gt[i].size);
717
if (SHARED_RESIZE & shared_gt[i].attr) printf(" RESIZABLE");
718
if (SHARED_PERSIST & shared_gt[i].attr) printf(" PERSIST");
722
printf(" %3d %08lx %4d %8d", i, (unsigned long int)shared_gt[i].key,
724
shared_gt[i].nprocdebug, shared_gt[i].size);
725
if (SHARED_RESIZE & shared_gt[i].attr) printf(" RESIZABLE");
726
if (SHARED_PERSIST & shared_gt[i].attr) printf(" PERSIST");
728
shared_demux(i, SHARED_RDONLY);
734
if (shared_debug) printf(" done\n");
735
return(r); /* table full */
739
int shared_uncond_delete(int id)
742
if (NULL == shared_gt) return(SHARED_NOTINIT); /* not initialized */
743
if (NULL == shared_lt) return(SHARED_NOTINIT); /* not initialized */
744
if (shared_debug) printf("shared_uncond_delete:");
746
for (i=0; i<shared_maxseg; i++)
747
{ if (-1 != id) if (i != id) continue;
748
if (shared_attach(i))
749
{ if (-1 != id) printf("no such handle\n");
752
printf("handle %d:", i);
753
if (NULL == shared_lock(i, SHARED_RDWRITE | SHARED_NOWAIT))
754
{ printf(" cannot lock in RW mode, not deleted\n");
757
if (shared_set_attr(i, SHARED_RESIZE) >= SHARED_ERRBASE)
758
{ printf(" cannot clear PERSIST attribute");
761
{ printf(" delete failed\n");
764
{ printf(" deleted\n");
767
if (shared_debug) printf(" done\n");
768
return(r); /* table full */
772
/************************* CFITSIO DRIVER FUNCTIONS ***************************/
778
int smem_shutdown(void)
780
{ if (shared_init_called) shared_cleanup();
784
int smem_setoptions(int option)
790
int smem_getoptions(int *options)
791
{ if (NULL == options) return(SHARED_NULPTR);
796
int smem_getversion(int *version)
797
{ if (NULL == version) return(SHARED_NULPTR);
803
int smem_open(char *filename, int rwmode, int *driverhandle)
808
if (NULL == filename) return(SHARED_NULPTR);
809
if (NULL == driverhandle) return(SHARED_NULPTR);
810
nitems = sscanf(filename, "h%d", &h);
811
if (1 != nitems) return(SHARED_BADARG);
813
if (SHARED_OK != (r = shared_attach(h))) return(r);
815
if (NULL == (sp = (DAL_SHM_SEGHEAD *)shared_lock(h,
816
((READWRITE == rwmode) ? SHARED_RDWRITE : SHARED_RDONLY))))
818
return(SHARED_BADARG);
821
if ((h != sp->h) || (DAL_SHM_SEGHEAD_ID != sp->ID))
825
return(SHARED_BADARG);
833
int smem_create(char *filename, int *driverhandle)
834
{ DAL_SHM_SEGHEAD *sp;
837
if (NULL == filename) return(SHARED_NULPTR); /* currently ignored */
838
if (NULL == driverhandle) return(SHARED_NULPTR);
839
nitems = sscanf(filename, "h%d", &h);
840
if (1 != nitems) return(SHARED_BADARG);
842
if (SHARED_INVALID == (h = shared_malloc(sz = 2880 + sizeof(DAL_SHM_SEGHEAD),
843
SHARED_RESIZE | SHARED_PERSIST, h)))
844
return(SHARED_NOMEM);
846
if (NULL == (sp = (DAL_SHM_SEGHEAD *)shared_lock(h, SHARED_RDWRITE)))
848
return(SHARED_BADARG);
851
sp->ID = DAL_SHM_SEGHEAD_ID;
862
int smem_close(int driverhandle)
865
if (SHARED_OK != (r = shared_unlock(driverhandle))) return(r);
866
return(shared_free(driverhandle));
869
int smem_remove(char *filename)
872
if (NULL == filename) return(SHARED_NULPTR);
873
nitems = sscanf(filename, "h%d", &h);
874
if (1 != nitems) return(SHARED_BADARG);
876
if (0 == shared_check_locked_index(h)) /* are we locked ? */
878
{ if (-1 != shared_lt[h].lkcnt) /* are we locked RO ? */
879
{ if (SHARED_OK != (r = shared_unlock(h))) return(r); /* yes, so relock in RW */
880
if (NULL == shared_lock(h, SHARED_RDWRITE)) return(SHARED_BADARG);
884
else /* not locked */
885
{ if (SHARED_OK != (r = smem_open(filename, READWRITE, &h)))
886
return(r); /* so open in RW mode */
889
shared_set_attr(h, SHARED_RESIZE); /* delete PERSIST attribute */
890
return(smem_close(h)); /* detach segment (this will delete it) */
893
int smem_size(int driverhandle, OFF_T *size)
895
if (NULL == size) return(SHARED_NULPTR);
896
if (shared_check_locked_index(driverhandle)) return(SHARED_INVALID);
897
*size = (OFF_T) (shared_gt[driverhandle].size - sizeof(DAL_SHM_SEGHEAD));
901
int smem_flush(int driverhandle)
903
if (shared_check_locked_index(driverhandle)) return(SHARED_INVALID);
907
int smem_seek(int driverhandle, OFF_T offset)
909
if (offset < 0) return(SHARED_BADARG);
910
if (shared_check_locked_index(driverhandle)) return(SHARED_INVALID);
911
shared_lt[driverhandle].seekpos = offset;
915
int smem_read(int driverhandle, void *buffer, long nbytes)
917
if (NULL == buffer) return(SHARED_NULPTR);
918
if (shared_check_locked_index(driverhandle)) return(SHARED_INVALID);
919
if (nbytes < 0) return(SHARED_BADARG);
920
if ((shared_lt[driverhandle].seekpos + nbytes) > shared_gt[driverhandle].size)
921
return(SHARED_BADARG); /* read beyond EOF */
924
((char *)(((DAL_SHM_SEGHEAD *)(shared_lt[driverhandle].p + 1)) + 1)) +
925
shared_lt[driverhandle].seekpos,
928
shared_lt[driverhandle].seekpos += nbytes;
932
int smem_write(int driverhandle, void *buffer, long nbytes)
934
if (NULL == buffer) return(SHARED_NULPTR);
935
if (shared_check_locked_index(driverhandle)) return(SHARED_INVALID);
936
if (-1 != shared_lt[driverhandle].lkcnt) return(SHARED_INVALID); /* are we locked RW ? */
938
if (nbytes < 0) return(SHARED_BADARG);
939
if ((unsigned long)(shared_lt[driverhandle].seekpos + nbytes) > (unsigned long)(shared_gt[driverhandle].size - sizeof(DAL_SHM_SEGHEAD)))
940
{ /* need to realloc shmem */
941
if (NULL == shared_realloc(driverhandle, shared_lt[driverhandle].seekpos + nbytes + sizeof(DAL_SHM_SEGHEAD)))
942
return(SHARED_NOMEM);
945
memcpy(((char *)(((DAL_SHM_SEGHEAD *)(shared_lt[driverhandle].p + 1)) + 1)) +
946
shared_lt[driverhandle].seekpos,
950
shared_lt[driverhandle].seekpos += nbytes;