~ubuntu-branches/debian/stretch/cfitsio/stretch

« back to all changes in this revision

Viewing changes to drvrsmem.c

  • Committer: Bazaar Package Importer
  • Author(s): Gopal Narayanan
  • Date: 2002-02-26 11:27:29 UTC
  • Revision ID: james.westby@ubuntu.com-20020226112729-3q2o993rhh81ipp4
Tags: upstream-2.401
ImportĀ upstreamĀ versionĀ 2.401

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*              S H A R E D   M E M O R Y   D R I V E R
 
2
                =======================================
 
3
 
 
4
                  by Jerzy.Borkowski@obs.unige.ch
 
5
 
 
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
 
9
            in url parser.
 
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
 
13
*/
 
14
 
 
15
#ifdef HAVE_SHMEM_SERVICES
 
16
#include "fitsio2.h"                         /* drvrsmem.h is included by it */
 
17
 
 
18
#include <stdio.h>
 
19
#include <stdlib.h>
 
20
#include <string.h>
 
21
#include <errno.h>
 
22
#include <sys/types.h>
 
23
#include <sys/stat.h>
 
24
#include <fcntl.h>
 
25
#include <unistd.h>
 
26
 
 
27
 
 
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 */
 
38
 
 
39
                /* static support routines prototypes */
 
40
 
 
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 */
 
45
 
 
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 !!! */
 
56
 
 
57
                /* support routines - initialization */
 
58
 
 
59
 
 
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;
 
69
 
 
70
   return(SHARED_OK);
 
71
 }
 
72
 
 
73
static  int shared_destroy_entry(int idx)       /* unconditionally destroy sema & shseg and clear entry */
 
74
 { int r, r2;
 
75
   union semun filler;
 
76
 
 
77
   if ((idx < 0) || (idx >= shared_maxseg)) return(SHARED_BADARG);
 
78
   r2 = r = SHARED_OK;
 
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);
 
85
 }
 
86
 
 
87
void    shared_cleanup(void)                    /* this must (should) be called during exit/abort */
 
88
 { int          i, j, r, oktodelete, filelocked, segmentspresent;
 
89
   flock_t      flk;
 
90
   struct shmid_ds  ds;
 
91
 
 
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 ... */
 
98
 
 
99
          r = shared_destroy_entry(i);          /* destroy unconditionally sema & segment */
 
100
          if (shared_debug) 
 
101
            { if (SHARED_OK == r) printf(" [%d]", i);
 
102
              else printf(" [error on %d !!!!]", i);
 
103
 
 
104
            }
 
105
        }
 
106
       free((void *)shared_lt);                 /* free local table */
 
107
       shared_lt = NULL;
 
108
     }
 
109
   if (NULL != shared_gt)                       /* detach global index table */
 
110
     { oktodelete = 0;
 
111
       filelocked = 0;
 
112
       if (shared_debug) printf(" detaching globalsharedtable");
 
113
       if (SHARED_INVALID != shared_fd)
 
114
 
 
115
       flk.l_type = F_WRLCK;                    /* lock whole lock file */
 
116
       flk.l_whence = 0;
 
117
       flk.l_start = 0;
 
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 */
 
125
                  break;
 
126
                }
 
127
            }
 
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 */
 
131
               }
 
132
         }
 
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;
 
137
         }
 
138
       shared_gt = NULL;
 
139
       if (filelocked)                          /* if we locked, we need to unlock */
 
140
         { flk.l_type = F_UNLCK;
 
141
           flk.l_whence = 0;
 
142
           flk.l_start = 0;
 
143
           flk.l_len = shared_maxseg;
 
144
           fcntl(shared_fd, F_SETLK, &flk);
 
145
         }
 
146
     }
 
147
   shared_gt_h = SHARED_INVALID;
 
148
 
 
149
   if (SHARED_INVALID != shared_fd)             /* close lock file */
 
150
     { if (shared_debug) printf(" closing lockfile");
 
151
       close(shared_fd);
 
152
       shared_fd = SHARED_INVALID;
 
153
     }
 
154
 
 
155
   
 
156
   shared_kbase = 0;
 
157
   shared_maxseg = 0;
 
158
   shared_range = 0;
 
159
   shared_init_called = 0;
 
160
 
 
161
   if (shared_debug) printf(" <<done>>\n");
 
162
   return;
 
163
 }
 
164
 
 
165
 
 
166
int     shared_init(int debug_msgs)             /* initialize shared memory stuff, you have to call this routine once */
 
167
 { int i;
 
168
   char buf[1000], *p;
 
169
   mode_t oldumask;
 
170
 
 
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 */
 
173
   
 
174
   if (shared_debug) printf("shared_init:");
 
175
 
 
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);
 
180
 
 
181
   shared_maxseg = 0;
 
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);
 
185
   
 
186
   shared_range = 3 * shared_maxseg;
 
187
 
 
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);
 
191
       oldumask = umask(0);
 
192
 
 
193
       shared_fd = open(buf, O_TRUNC | O_EXCL | O_CREAT | O_RDWR, shared_create_mode);
 
194
       umask(oldumask);
 
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");
 
199
 
 
200
         }
 
201
       else
 
202
         { if (shared_debug) printf("master");
 
203
         }
 
204
     }
 
205
 
 
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");
 
215
         }
 
216
       else
 
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");
 
221
         }
 
222
     }
 
223
 
 
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 */
 
232
        }
 
233
       if (shared_debug) printf("ok");
 
234
     }
 
235
 
 
236
   atexit(shared_cleanup);                      /* we want shared_cleanup to be called at exit or abort */
 
237
 
 
238
   if (shared_debug) printf(" <<done>>\n");
 
239
   return(SHARED_OK);
 
240
 }
 
241
 
 
242
 
 
243
int     shared_recover(int id)                  /* try to recover dormant segments after applic crash */
 
244
 { int i, r, r2;
 
245
 
 
246
   if (NULL == shared_gt) return(SHARED_NOTINIT);       /* not initialized */
 
247
   if (NULL == shared_lt) return(SHARED_NOTINIT);       /* not initialized */
 
248
   r = SHARED_OK;
 
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);
 
258
          if (shared_debug)
 
259
            { printf("%s", r ? "error couldn't clear handle" : "handle cleared");
 
260
            }
 
261
        }
 
262
      shared_demux(i, SHARED_RDWRITE);
 
263
    }
 
264
   return(r);                                           /* table full */
 
265
 }
 
266
 
 
267
                /* API routines - mutexes and locking */
 
268
 
 
269
static  int shared_mux(int idx, int mode)       /* obtain exclusive access to specified segment */
 
270
 { flock_t flk;
 
271
 
 
272
   int r;
 
273
 
 
274
   if (0 == shared_init_called)                 /* delayed initialization */
 
275
     { if (SHARED_OK != (r = shared_init(0))) return(r);
 
276
 
 
277
     }
 
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);
 
281
   flk.l_whence = 0;
 
282
   flk.l_start = idx;
 
283
   flk.l_len = 1;
 
284
   if (shared_debug) printf(" [mux (%d): ", idx);
 
285
   if (-1 == fcntl(shared_fd, ((mode & SHARED_NOWAIT) ? F_SETLK : F_SETLKW), &flk))
 
286
     { switch (errno)
 
287
        { case EAGAIN: ;
 
288
 
 
289
          case EACCES: if (shared_debug) printf("again]");
 
290
                       return(SHARED_AGAIN);
 
291
          default:     if (shared_debug) printf("err]");
 
292
                       return(SHARED_IPCERR);
 
293
        }
 
294
     }
 
295
   if (shared_debug) printf("ok]");
 
296
   return(SHARED_OK);
 
297
 }
 
298
 
 
299
 
 
300
 
 
301
static  int shared_demux(int idx, int mode)     /* free exclusive access to specified segment */
 
302
 { flock_t flk;
 
303
 
 
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;
 
307
   flk.l_whence = 0;
 
308
   flk.l_start = idx;
 
309
   flk.l_len = 1;
 
310
   if (shared_debug) printf(" [demux (%d): ", idx);
 
311
   if (-1 == fcntl(shared_fd, F_SETLKW, &flk))
 
312
     { switch (errno)
 
313
        { case EAGAIN: ;
 
314
          case EACCES: if (shared_debug) printf("again]");
 
315
                       return(SHARED_AGAIN);
 
316
          default:     if (shared_debug) printf("err]");
 
317
                       return(SHARED_IPCERR);
 
318
        }
 
319
 
 
320
     }
 
321
   if (shared_debug) printf("mode=%d ok]", mode);
 
322
   return(SHARED_OK);
 
323
 }
 
324
 
 
325
 
 
326
 
 
327
static int shared_process_count(int sem)                /* valid only for time of invocation */
 
328
 { union semun su;
 
329
 
 
330
   su.val = 0;                                          /* to force compiler not to give warning messages */
 
331
   return(semctl(sem, 0, GETVAL, su));                  /* su is unused here */
 
332
 }
 
333
 
 
334
 
 
335
static int shared_delta_process(int sem, int delta)     /* change number of processes hanging on segment */
 
336
 { struct sembuf sb;
 
337
 
 
338
   if (SHARED_INVALID == sem) return(SHARED_BADARG);    /* semaphore not attached */
 
339
   sb.sem_num = 0;
 
340
   sb.sem_op = delta;
 
341
   sb.sem_flg = SEM_UNDO;
 
342
   return((-1 == semop(sem, &sb, 1)) ? SHARED_IPCERR : SHARED_OK);
 
343
 }
 
344
 
 
345
 
 
346
static int shared_attach_process(int sem)
 
347
 { if (shared_debug) printf(" [attach process]");
 
348
   return(shared_delta_process(sem, 1));
 
349
 }
 
350
 
 
351
 
 
352
static int shared_detach_process(int sem)
 
353
 { if (shared_debug) printf(" [detach process]");
 
354
   return(shared_delta_process(sem, -1));
 
355
 }
 
356
 
 
357
                /* API routines - hashing and searching */
 
358
 
 
359
 
 
360
static int shared_get_free_entry(int newhandle)         /* get newhandle, or -1, entry is set rw locked */
 
361
 {
 
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 */
 
372
 }
 
373
 
 
374
 
 
375
static int shared_get_hash(long size, int idx)  /* return hash value for malloc */
 
376
 { static int counter = 0;
 
377
   int hash;
 
378
 
 
379
   hash = (counter + size * idx) % shared_range;
 
380
   counter = (counter + 1) % shared_range;
 
381
   return(hash);
 
382
 }
 
383
 
 
384
 
 
385
static  long shared_adjust_size(long size)              /* size must be >= 0 !!! */
 
386
 { return(((size + sizeof(BLKHEAD) + SHARED_GRANUL - 1) / SHARED_GRANUL) * SHARED_GRANUL); }
 
387
 
 
388
 
 
389
                /* API routines - core : malloc/realloc/free/attach/detach/lock/unlock */
 
390
 
 
391
int     shared_malloc(long size, int mode, int newhandle)               /* return idx or SHARED_INVALID */
 
392
 { int h, i, r, idx, key;
 
393
   union semun filler;
 
394
   BLKHEAD *bp;
 
395
   
 
396
   if (0 == shared_init_called)                 /* delayed initialization */
 
397
     { if (SHARED_OK != (r = shared_init(0))) return(r);
 
398
     }
 
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);
 
403
   for (i = 0; ; i++)
 
404
    { if (i >= shared_range)                            /* table full, signal error & exit */
 
405
        { shared_demux(idx, SHARED_RDWRITE);
 
406
          return(SHARED_INVALID);
 
407
        }
 
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);
 
417
          continue;
 
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 */
 
423
        }
 
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 */
 
430
        }
 
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;
 
438
        }
 
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;
 
449
 
 
450
      break;
 
451
    }
 
452
   shared_demux(idx, SHARED_RDWRITE);                   /* hope this will not fail */
 
453
   return(idx);
 
454
 }
 
455
 
 
456
 
 
457
int     shared_attach(int idx)
 
458
 { int r, r2;
 
459
 
 
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);
 
463
       return(r);
 
464
     }
 
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);
 
470
     }
 
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;
 
475
     }
 
476
   shared_lt[idx].seekpos = 0L;                         /* r/w pointer positioned at beg of block */
 
477
   r2 = shared_demux(idx, SHARED_RDWRITE);
 
478
   return(r ? r : r2);
 
479
 }
 
480
 
 
481
 
 
482
 
 
483
static int      shared_check_locked_index(int idx)      /* verify that given idx is valid */ 
 
484
 { int r;
 
485
 
 
486
   if (0 == shared_init_called)                         /* delayed initialization */
 
487
     { if (SHARED_OK != (r = shared_init(0))) return(r);
 
488
 
 
489
     }
 
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);
 
496
   return(SHARED_OK);
 
497
 }
 
498
 
 
499
 
 
500
 
 
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 */
 
503
   BLKHEAD *bp;
 
504
 
 
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);
 
512
 
 
513
     }
 
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);
 
517
     }
 
518
   shared_lt[idx].p = bp;                               /* store pointer to shmem data */
 
519
   return(SHARED_OK);
 
520
 }
 
521
 
 
522
 
 
523
static  int     shared_validate(int idx, int mode)      /* use intrnally inside crit.sect !!! */
 
524
 { int r;
 
525
 
 
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); 
 
530
         return(r);
 
531
       }
 
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);
 
534
       return(r);
 
535
     }
 
536
   return(SHARED_OK);
 
537
 }
 
538
 
 
539
 
 
540
SHARED_P shared_realloc(int idx, long newsize)  /* realloc shared memory segment */
 
541
 { int h, key, i, r;
 
542
   BLKHEAD *bp;
 
543
   long transfersize;
 
544
 
 
545
   r = SHARED_OK;
 
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;
 
552
 
 
553
       return((SHARED_P)((shared_lt[idx].p) + 1));
 
554
     }
 
555
   for (i = 0; ; i++)
 
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);
 
563
          continue;
 
564
        }
 
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;
 
575
      break;
 
576
    }
 
577
   return((SHARED_P)(bp + 1));
 
578
 }
 
579
 
 
580
 
 
581
int     shared_free(int idx)                    /* detach segment, if last process & !PERSIST, destroy segment */
 
582
 { int cnt, r, r2;
 
583
 
 
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);
 
587
       return(r);
 
588
     }
 
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);
 
594
     }
 
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);
 
600
     }
 
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);
 
603
   return(r ? r : r2);
 
604
 }
 
605
 
 
606
 
 
607
SHARED_P shared_lock(int idx, int mode)         /* lock given segment for exclusive access */
 
608
 { int r;
 
609
 
 
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); 
 
614
         return(NULL);
 
615
       }
 
616
   if (NULL == shared_lt[idx].p)                /* stupid pointer ?? */
 
617
     if (SHARED_OK != (r = shared_map(idx)))
 
618
       { shared_demux(idx, mode); 
 
619
         return(NULL);
 
620
       }
 
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);
 
623
       return(NULL);
 
624
     }
 
625
   if (mode & SHARED_RDWRITE)
 
626
     { shared_lt[idx].lkcnt = -1;
 
627
 
 
628
       shared_gt[idx].nprocdebug++;
 
629
     }
 
630
 
 
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));
 
634
 }
 
635
 
 
636
 
 
637
int     shared_unlock(int idx)                  /* unlock given segment, assumes seg is locked !! */
 
638
 { int r, r2, mode;
 
639
 
 
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;
 
644
     }
 
645
   else
 
646
     { shared_lt[idx].lkcnt = 0;                /* unlock write lock */
 
647
       shared_gt[idx].nprocdebug--;
 
648
       mode = SHARED_RDWRITE;
 
649
     }
 
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 */
 
653
     }
 
654
   r2 = shared_demux(idx, mode);                /* unlock segment, rest is only parameter checking */
 
655
   return(r ? r : r2);
 
656
 }
 
657
 
 
658
                /* API routines - support and info routines */
 
659
 
 
660
 
 
661
int     shared_attr(int idx)                    /* get the attributes of the shared memory segment */
 
662
 { int r;
 
663
 
 
664
   if (shared_check_locked_index(idx)) return(SHARED_INVALID);
 
665
   r = shared_gt[idx].attr;
 
666
   return(r);
 
667
 }
 
668
 
 
669
 
 
670
int     shared_set_attr(int idx, int newattr)   /* get the attributes of the shared memory segment */
 
671
 { int r;
 
672
 
 
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;
 
677
   return(r);
 
678
 
 
679
 }
 
680
 
 
681
 
 
682
int     shared_set_debug(int mode)              /* set/reset debug mode */
 
683
 { int r = shared_debug;
 
684
 
 
685
   shared_debug = mode;
 
686
   return(r);
 
687
 }
 
688
 
 
689
 
 
690
int     shared_set_createmode(int mode)          /* set/reset debug mode */
 
691
 { int r = shared_create_mode;
 
692
 
 
693
   shared_create_mode = mode;
 
694
   return(r);
 
695
 }
 
696
 
 
697
 
 
698
 
 
699
 
 
700
int     shared_list(int id)
 
701
 { int i, r;
 
702
 
 
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:");
 
706
   r = SHARED_OK;
 
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 */
 
713
 
 
714
       { case SHARED_AGAIN:
 
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");
 
719
                printf("\n");
 
720
                break;
 
721
         case SHARED_OK:
 
722
                printf(" %3d %08lx %4d  %8d", i, (unsigned long int)shared_gt[i].key,
 
723
 
 
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");
 
727
                printf("\n");
 
728
                shared_demux(i, SHARED_RDONLY);
 
729
                break;
 
730
         default:
 
731
                continue;
 
732
       }
 
733
    }
 
734
   if (shared_debug) printf(" done\n");
 
735
   return(r);                                           /* table full */
 
736
 }
 
737
 
 
738
 
 
739
int     shared_uncond_delete(int id)
 
740
 { int i, r;
 
741
 
 
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:");
 
745
   r = SHARED_OK;
 
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");
 
750
          continue;
 
751
        }
 
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");
 
755
          continue;
 
756
        }
 
757
      if (shared_set_attr(i, SHARED_RESIZE) >= SHARED_ERRBASE)
 
758
        { printf(" cannot clear PERSIST attribute");
 
759
        }
 
760
      if (shared_free(i))
 
761
        { printf(" delete failed\n");
 
762
        }
 
763
      else
 
764
        { printf(" deleted\n");
 
765
        }
 
766
    }
 
767
   if (shared_debug) printf(" done\n");
 
768
   return(r);                                           /* table full */
 
769
 }
 
770
 
 
771
 
 
772
/************************* CFITSIO DRIVER FUNCTIONS ***************************/
 
773
 
 
774
int     smem_init(void)
 
775
 { return(0);
 
776
 }
 
777
 
 
778
int     smem_shutdown(void)
 
779
 
 
780
 { if (shared_init_called) shared_cleanup();
 
781
   return(0);
 
782
 }
 
783
 
 
784
int     smem_setoptions(int option)
 
785
 { option = 0;
 
786
   return(0);
 
787
 }
 
788
 
 
789
 
 
790
int     smem_getoptions(int *options)
 
791
 { if (NULL == options) return(SHARED_NULPTR);
 
792
   *options = 0;
 
793
   return(0);
 
794
 }
 
795
 
 
796
int     smem_getversion(int *version)
 
797
 { if (NULL == version) return(SHARED_NULPTR);
 
798
   *version = 10;
 
799
   return(0);
 
800
 }
 
801
 
 
802
 
 
803
int     smem_open(char *filename, int rwmode, int *driverhandle)
 
804
 { int h, nitems, r;
 
805
   DAL_SHM_SEGHEAD *sp;
 
806
 
 
807
 
 
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);
 
812
 
 
813
   if (SHARED_OK != (r = shared_attach(h))) return(r);
 
814
 
 
815
   if (NULL == (sp = (DAL_SHM_SEGHEAD *)shared_lock(h,
 
816
                ((READWRITE == rwmode) ? SHARED_RDWRITE : SHARED_RDONLY))))
 
817
     {  shared_free(h);
 
818
        return(SHARED_BADARG);
 
819
     }
 
820
 
 
821
   if ((h != sp->h) || (DAL_SHM_SEGHEAD_ID != sp->ID))
 
822
     { shared_unlock(h);
 
823
       shared_free(h);
 
824
 
 
825
       return(SHARED_BADARG);
 
826
     }
 
827
 
 
828
   *driverhandle = h;
 
829
   return(0);
 
830
 }
 
831
 
 
832
 
 
833
int     smem_create(char *filename, int *driverhandle)
 
834
 { DAL_SHM_SEGHEAD *sp;
 
835
   int h, sz, nitems;
 
836
 
 
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);
 
841
 
 
842
   if (SHARED_INVALID == (h = shared_malloc(sz = 2880 + sizeof(DAL_SHM_SEGHEAD), 
 
843
                        SHARED_RESIZE | SHARED_PERSIST, h)))
 
844
     return(SHARED_NOMEM);
 
845
 
 
846
   if (NULL == (sp = (DAL_SHM_SEGHEAD *)shared_lock(h, SHARED_RDWRITE)))
 
847
     { shared_free(h);
 
848
       return(SHARED_BADARG);
 
849
     }
 
850
 
 
851
   sp->ID = DAL_SHM_SEGHEAD_ID;
 
852
   sp->h = h;
 
853
   sp->size = sz;
 
854
   sp->nodeidx = -1;
 
855
 
 
856
   *driverhandle = h;
 
857
   
 
858
   return(0);
 
859
 }
 
860
 
 
861
 
 
862
int     smem_close(int driverhandle)
 
863
 { int r;
 
864
 
 
865
   if (SHARED_OK != (r = shared_unlock(driverhandle))) return(r);
 
866
   return(shared_free(driverhandle));
 
867
 }
 
868
 
 
869
int     smem_remove(char *filename)
 
870
 { int nitems, h, r;
 
871
 
 
872
   if (NULL == filename) return(SHARED_NULPTR);
 
873
   nitems = sscanf(filename, "h%d", &h);
 
874
   if (1 != nitems) return(SHARED_BADARG);
 
875
 
 
876
   if (0 == shared_check_locked_index(h))       /* are we locked ? */
 
877
 
 
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);
 
881
         }
 
882
 
 
883
     }
 
884
   else                                         /* not locked */
 
885
     { if (SHARED_OK != (r = smem_open(filename, READWRITE, &h)))
 
886
         return(r);                             /* so open in RW mode */
 
887
     }
 
888
 
 
889
   shared_set_attr(h, SHARED_RESIZE);           /* delete PERSIST attribute */
 
890
   return(smem_close(h));                       /* detach segment (this will delete it) */
 
891
 }
 
892
 
 
893
int     smem_size(int driverhandle, OFF_T *size)
 
894
 {
 
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));
 
898
   return(0);
 
899
 }
 
900
 
 
901
int     smem_flush(int driverhandle)
 
902
 {
 
903
   if (shared_check_locked_index(driverhandle)) return(SHARED_INVALID);
 
904
   return(0);
 
905
 }
 
906
 
 
907
int     smem_seek(int driverhandle, OFF_T offset)
 
908
 {
 
909
   if (offset < 0) return(SHARED_BADARG);
 
910
   if (shared_check_locked_index(driverhandle)) return(SHARED_INVALID);
 
911
   shared_lt[driverhandle].seekpos = offset;
 
912
   return(0);
 
913
 }
 
914
 
 
915
int     smem_read(int driverhandle, void *buffer, long nbytes)
 
916
 {
 
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 */
 
922
 
 
923
   memcpy(buffer,
 
924
          ((char *)(((DAL_SHM_SEGHEAD *)(shared_lt[driverhandle].p + 1)) + 1)) +
 
925
                shared_lt[driverhandle].seekpos,
 
926
          nbytes);
 
927
 
 
928
   shared_lt[driverhandle].seekpos += nbytes;
 
929
   return(0);
 
930
 }
 
931
 
 
932
int     smem_write(int driverhandle, void *buffer, long nbytes)
 
933
 {
 
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 ? */
 
937
 
 
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);
 
943
     }
 
944
 
 
945
   memcpy(((char *)(((DAL_SHM_SEGHEAD *)(shared_lt[driverhandle].p + 1)) + 1)) +
 
946
                shared_lt[driverhandle].seekpos,
 
947
          buffer,
 
948
          nbytes);
 
949
 
 
950
   shared_lt[driverhandle].seekpos += nbytes;
 
951
   return(0);
 
952
 }
 
953
#endif