~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/port/qnx4/sem.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * sem.c
 
4
 *        System V Semaphore Emulation
 
5
 *
 
6
 * Copyright (c) 1999, repas AEG Automation GmbH
 
7
 *
 
8
 *
 
9
 * IDENTIFICATION
 
10
 *        $PostgreSQL: pgsql/src/backend/port/qnx4/sem.c,v 1.12 2003-11-29 19:51:54 pgsql Exp $
 
11
 *
 
12
 *-------------------------------------------------------------------------
 
13
 */
 
14
 
 
15
#include "postgres.h"
 
16
 
 
17
#include <errno.h>
 
18
#include <semaphore.h>
 
19
#include <unistd.h>
 
20
#include <fcntl.h>
 
21
#include <sys/mman.h>
 
22
#include <sys/sem.h>
 
23
#include <sys/mman.h>
 
24
#include <sys/stat.h>
 
25
 
 
26
#include "miscadmin.h"
 
27
#include "storage/ipc.h"
 
28
#include "storage/proc.h"
 
29
 
 
30
 
 
31
#define SEMMAX  (PROC_NSEMS_PER_SET+1)
 
32
#define OPMAX   8
 
33
 
 
34
#define MODE    0700
 
35
#define SHM_INFO_NAME   "PgSysV_Sem_Info"
 
36
 
 
37
 
 
38
struct pending_ops
 
39
{
 
40
        int                     op[OPMAX];              /* array of pending operations */
 
41
        int                     idx;                    /* index of first free array member */
 
42
};
 
43
 
 
44
struct sem_set_info
 
45
{
 
46
        key_t           key;
 
47
        int                     nsems;
 
48
        sem_t           sem[SEMMAX];    /* array of POSIX semaphores */
 
49
        struct sem      semV[SEMMAX];   /* array of System V semaphore structures */
 
50
        struct pending_ops pendingOps[SEMMAX];          /* array of pending
 
51
                                                                                                 * operations */
 
52
};
 
53
 
 
54
struct sem_info
 
55
{
 
56
        sem_t           sem;
 
57
        int                     nsets;
 
58
        /* there are actually nsets of these: */
 
59
        struct sem_set_info set[1]; /* VARIABLE LENGTH ARRAY */
 
60
};
 
61
 
 
62
static struct sem_info *SemInfo = (struct sem_info *) - 1;
 
63
 
 
64
/* ----------------------------------------------------------------
 
65
 * semclean - remove the shared memory file on exit
 
66
 *                        only called by the process which created the shm file
 
67
 * ----------------------------------------------------------------
 
68
 */
 
69
 
 
70
static void
 
71
semclean(void)
 
72
{
 
73
        remove("/dev/shmem/" SHM_INFO_NAME);
 
74
}
 
75
 
 
76
int
 
77
semctl(int semid, int semnum, int cmd, /* ... */ union semun arg)
 
78
{
 
79
        int                     r = 0;
 
80
 
 
81
        sem_wait(&SemInfo->sem);
 
82
 
 
83
        if (semid < 0 || semid >= SemInfo->nsets ||
 
84
                semnum < 0 || semnum >= SemInfo->set[semid].nsems)
 
85
        {
 
86
                sem_post(&SemInfo->sem);
 
87
                errno = EINVAL;
 
88
                return -1;
 
89
        }
 
90
 
 
91
        switch (cmd)
 
92
        {
 
93
                case GETNCNT:
 
94
                        r = SemInfo->set[semid].semV[semnum].semncnt;
 
95
                        break;
 
96
 
 
97
                case GETPID:
 
98
                        r = SemInfo->set[semid].semV[semnum].sempid;
 
99
                        break;
 
100
 
 
101
                case GETVAL:
 
102
                        r = SemInfo->set[semid].semV[semnum].semval;
 
103
                        break;
 
104
 
 
105
                case GETALL:
 
106
                        for (semnum = 0; semnum < SemInfo->set[semid].nsems; semnum++)
 
107
                                arg.array[semnum] = SemInfo->set[semid].semV[semnum].semval;
 
108
                        break;
 
109
 
 
110
                case SETVAL:
 
111
                        SemInfo->set[semid].semV[semnum].semval = arg.val;
 
112
                        break;
 
113
 
 
114
                case SETALL:
 
115
                        for (semnum = 0; semnum < SemInfo->set[semid].nsems; semnum++)
 
116
                                SemInfo->set[semid].semV[semnum].semval = arg.array[semnum];
 
117
                        break;
 
118
 
 
119
                case GETZCNT:
 
120
                        r = SemInfo->set[semid].semV[semnum].semzcnt;
 
121
                        break;
 
122
 
 
123
                case IPC_RMID:
 
124
                        for (semnum = 0; semnum < SemInfo->set[semid].nsems; semnum++)
 
125
                        {
 
126
                                if (sem_destroy(&SemInfo->set[semid].sem[semnum]) == -1)
 
127
                                        r = -1;
 
128
                        }
 
129
                        SemInfo->set[semid].key = -1;
 
130
                        SemInfo->set[semid].nsems = 0;
 
131
                        break;
 
132
 
 
133
                default:
 
134
                        sem_post(&SemInfo->sem);
 
135
                        errno = EINVAL;
 
136
                        return -1;
 
137
        }
 
138
 
 
139
        sem_post(&SemInfo->sem);
 
140
 
 
141
        return r;
 
142
}
 
143
 
 
144
int
 
145
semget(key_t key, int nsems, int semflg)
 
146
{
 
147
        int                     fd,
 
148
                                semid,
 
149
                                semnum,
 
150
                                nsets;
 
151
        int                     exist = 0;
 
152
        Size            sem_info_size;
 
153
        struct stat statbuf;
 
154
 
 
155
        if (nsems < 0 || nsems > SEMMAX)
 
156
        {
 
157
                errno = EINVAL;
 
158
                return -1;
 
159
        }
 
160
 
 
161
        /* open and map shared memory */
 
162
        if (SemInfo == (struct sem_info *) - 1)
 
163
        {
 
164
                /* test if the shared memory already exists */
 
165
                fd = shm_open(SHM_INFO_NAME, O_RDWR | O_CREAT | O_EXCL, MODE);
 
166
                if (fd == -1 && errno == EEXIST)
 
167
                {
 
168
                        exist = 1;
 
169
                        fd = shm_open(SHM_INFO_NAME, O_RDWR | O_CREAT, MODE);
 
170
                }
 
171
                if (fd == -1)
 
172
                        return fd;
 
173
                /* The size may only be set once. Ignore errors. */
 
174
                nsets = PROC_SEM_MAP_ENTRIES(MaxBackends);
 
175
                sem_info_size = sizeof(struct sem_info) + (nsets - 1) * sizeof(struct sem_set_info);
 
176
                ltrunc(fd, sem_info_size, SEEK_SET);
 
177
                if (fstat(fd, &statbuf))        /* would be strange : the only doc'ed */
 
178
                {                                               /* error is EBADF */
 
179
                        close(fd);
 
180
                        return -1;
 
181
                }
 
182
 
 
183
                /*
 
184
                 * size is rounded by proc to the next __PAGESIZE
 
185
                 */
 
186
                if (statbuf.st_size !=
 
187
                        (((sem_info_size / __PAGESIZE) + 1) * __PAGESIZE))
 
188
                {
 
189
                        fprintf(stderr,
 
190
                                        "Found a pre-existing shared memory block for the semaphore memory\n"
 
191
                                        "of a different size (%ld instead %ld). Make sure that all executables\n"
 
192
                                        "are from the same release or remove the file \"/dev/shmem/%s\"\n"
 
193
                                        "left by a previous version.\n",
 
194
                                        (long) statbuf.st_size,
 
195
                                        (long) sem_info_size,
 
196
                                        SHM_INFO_NAME);
 
197
                        errno = EACCES;
 
198
                        return -1;
 
199
                }
 
200
                SemInfo = mmap(NULL, sem_info_size,
 
201
                                           PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
 
202
                if (SemInfo == MAP_FAILED)
 
203
                        return -1;
 
204
                if (!exist)
 
205
                {
 
206
                        /* initialize shared memory */
 
207
                        memset(SemInfo, 0, sem_info_size);
 
208
                        SemInfo->nsets = nsets;
 
209
                        for (semid = 0; semid < nsets; semid++)
 
210
                                SemInfo->set[semid].key = -1;
 
211
                        /* create semaphore for locking */
 
212
                        sem_init(&SemInfo->sem, 1, 1);
 
213
                        on_proc_exit(semclean, 0);
 
214
                }
 
215
        }
 
216
 
 
217
        sem_wait(&SemInfo->sem);
 
218
        nsets = SemInfo->nsets;
 
219
 
 
220
        if (key != IPC_PRIVATE)
 
221
        {
 
222
                /* search existing element */
 
223
                semid = 0;
 
224
                while (semid < nsets && SemInfo->set[semid].key != key)
 
225
                        semid++;
 
226
                if (!(semflg & IPC_CREAT) && semid >= nsets)
 
227
                {
 
228
                        sem_post(&SemInfo->sem);
 
229
                        errno = ENOENT;
 
230
                        return -1;
 
231
                }
 
232
                else if (semid < nsets)
 
233
                {
 
234
                        if (semflg & IPC_CREAT && semflg & IPC_EXCL)
 
235
                        {
 
236
                                sem_post(&SemInfo->sem);
 
237
                                errno = EEXIST;
 
238
                                return -1;
 
239
                        }
 
240
                        else
 
241
                        {
 
242
                                if (nsems != 0 && SemInfo->set[semid].nsems < nsems)
 
243
                                {
 
244
                                        sem_post(&SemInfo->sem);
 
245
                                        errno = EINVAL;
 
246
                                        return -1;
 
247
                                }
 
248
                                sem_post(&SemInfo->sem);
 
249
                                return semid;
 
250
                        }
 
251
                }
 
252
        }
 
253
 
 
254
        /* search first free element */
 
255
        semid = 0;
 
256
        while (semid < nsets && SemInfo->set[semid].key != -1)
 
257
                semid++;
 
258
        if (semid >= nsets)
 
259
        {
 
260
                sem_post(&SemInfo->sem);
 
261
                errno = ENOSPC;
 
262
                return -1;
 
263
        }
 
264
 
 
265
        for (semnum = 0; semnum < nsems; semnum++)
 
266
        {
 
267
                sem_init(&SemInfo->set[semid].sem[semnum], 1, 0);
 
268
/* Currently sem_init always returns -1. */
 
269
#ifdef NOT_USED
 
270
                if (sem_init(&SemInfo->set[semid].sem[semnum], 1, 0) == -1)
 
271
                {
 
272
                        int                     semnum1;
 
273
 
 
274
                        for (semnum1 = 0; semnum1 < semnum; semnum1++)
 
275
                                sem_destroy(&SemInfo->set[semid].sem[semnum1]);
 
276
                        sem_post(&SemInfo->sem);
 
277
                        return -1;
 
278
                }
 
279
#endif
 
280
        }
 
281
 
 
282
        SemInfo->set[semid].key = key;
 
283
        SemInfo->set[semid].nsems = nsems;
 
284
 
 
285
        sem_post(&SemInfo->sem);
 
286
 
 
287
        return semid;
 
288
}
 
289
 
 
290
int
 
291
semop(int semid, struct sembuf * sops, size_t nsops)
 
292
{
 
293
        int                     i,
 
294
                                r = 0,
 
295
                                r1,
 
296
                                errno1 = 0,
 
297
                                op;
 
298
 
 
299
        sem_wait(&SemInfo->sem);
 
300
 
 
301
        if (semid < 0 || semid >= SemInfo->nsets)
 
302
        {
 
303
                sem_post(&SemInfo->sem);
 
304
                errno = EINVAL;
 
305
                return -1;
 
306
        }
 
307
        for (i = 0; i < nsops; i++)
 
308
        {
 
309
                if ( /* sops[i].sem_num < 0 || */ sops[i].sem_num >= SemInfo->set[semid].nsems)
 
310
                {
 
311
                        sem_post(&SemInfo->sem);
 
312
                        errno = EFBIG;
 
313
                        return -1;
 
314
                }
 
315
        }
 
316
 
 
317
        for (i = 0; i < nsops; i++)
 
318
        {
 
319
                if (sops[i].sem_op < 0)
 
320
                {
 
321
                        if (SemInfo->set[semid].semV[sops[i].sem_num].semval < -sops[i].sem_op)
 
322
                        {
 
323
                                if (sops[i].sem_flg & IPC_NOWAIT)
 
324
                                {
 
325
                                        sem_post(&SemInfo->sem);
 
326
                                        errno = EAGAIN;
 
327
                                        return -1;
 
328
                                }
 
329
                                SemInfo->set[semid].semV[sops[i].sem_num].semncnt++;
 
330
                                if (SemInfo->set[semid].pendingOps[sops[i].sem_num].idx >= OPMAX)
 
331
                                {
 
332
                                        /* pending operations array overflow */
 
333
                                        sem_post(&SemInfo->sem);
 
334
                                        errno = ERANGE;
 
335
                                        return -1;
 
336
                                }
 
337
                                SemInfo->set[semid].pendingOps[sops[i].sem_num].op[SemInfo->set[semid].pendingOps[sops[i].sem_num].idx++] = sops[i].sem_op;
 
338
                                /* suspend */
 
339
                                sem_post(&SemInfo->sem);                /* avoid deadlock */
 
340
                                r1 = sem_wait(&SemInfo->set[semid].sem[sops[i].sem_num]);
 
341
                                sem_wait(&SemInfo->sem);
 
342
                                if (r1)
 
343
                                {
 
344
                                        errno1 = errno;
 
345
                                        r = r1;
 
346
                                        /* remove pending operation */
 
347
                                        SemInfo->set[semid].pendingOps[sops[i].sem_num].op[--SemInfo->set[semid].pendingOps[sops[i].sem_num].idx] = 0;
 
348
                                }
 
349
                                else
 
350
                                        SemInfo->set[semid].semV[sops[i].sem_num].semval -= -sops[i].sem_op;
 
351
                                SemInfo->set[semid].semV[sops[i].sem_num].semncnt--;
 
352
                        }
 
353
                        else
 
354
                                SemInfo->set[semid].semV[sops[i].sem_num].semval -= -sops[i].sem_op;
 
355
                }
 
356
                else if (sops[i].sem_op > 0)
 
357
                {
 
358
                        SemInfo->set[semid].semV[sops[i].sem_num].semval += sops[i].sem_op;
 
359
                        op = sops[i].sem_op;
 
360
                        while (op > 0 && SemInfo->set[semid].pendingOps[sops[i].sem_num].idx > 0)
 
361
                        {                                       /* operations pending */
 
362
                                if (SemInfo->set[semid].pendingOps[sops[i].sem_num].op[SemInfo->set[semid].pendingOps[sops[i].sem_num].idx - 1] + op >= 0)
 
363
                                {
 
364
                                        /* unsuspend processes */
 
365
                                        if (sem_post(&SemInfo->set[semid].sem[sops[i].sem_num]))
 
366
                                        {
 
367
                                                errno1 = errno;
 
368
                                                r = -1;
 
369
                                        }
 
370
                                        /* adjust pending operations */
 
371
                                        op += SemInfo->set[semid].pendingOps[sops[i].sem_num].op[--SemInfo->set[semid].pendingOps[sops[i].sem_num].idx];
 
372
                                        SemInfo->set[semid].pendingOps[sops[i].sem_num].op[SemInfo->set[semid].pendingOps[sops[i].sem_num].idx] = 0;
 
373
                                }
 
374
                                else
 
375
                                {
 
376
                                        /* adjust pending operations */
 
377
                                        SemInfo->set[semid].pendingOps[sops[i].sem_num].op[SemInfo->set[semid].pendingOps[sops[i].sem_num].idx - 1] += op;
 
378
                                        op = 0;
 
379
                                }
 
380
                        }
 
381
                }
 
382
                else
 
383
                        /* sops[i].sem_op == 0 */
 
384
                {
 
385
                        /* not supported */
 
386
                        sem_post(&SemInfo->sem);
 
387
                        errno = ENOSYS;
 
388
                        return -1;
 
389
                }
 
390
                SemInfo->set[semid].semV[sops[i].sem_num].sempid = getpid();
 
391
        }
 
392
 
 
393
        sem_post(&SemInfo->sem);
 
394
 
 
395
        errno = errno1;
 
396
        return r;
 
397
}