1
/*-------------------------------------------------------------------------
4
* System V Semaphore Emulation
6
* Copyright (c) 1999, repas AEG Automation GmbH
10
* $PostgreSQL: pgsql/src/backend/port/qnx4/sem.c,v 1.12 2003-11-29 19:51:54 pgsql Exp $
12
*-------------------------------------------------------------------------
18
#include <semaphore.h>
26
#include "miscadmin.h"
27
#include "storage/ipc.h"
28
#include "storage/proc.h"
31
#define SEMMAX (PROC_NSEMS_PER_SET+1)
35
#define SHM_INFO_NAME "PgSysV_Sem_Info"
40
int op[OPMAX]; /* array of pending operations */
41
int idx; /* index of first free array member */
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
58
/* there are actually nsets of these: */
59
struct sem_set_info set[1]; /* VARIABLE LENGTH ARRAY */
62
static struct sem_info *SemInfo = (struct sem_info *) - 1;
64
/* ----------------------------------------------------------------
65
* semclean - remove the shared memory file on exit
66
* only called by the process which created the shm file
67
* ----------------------------------------------------------------
73
remove("/dev/shmem/" SHM_INFO_NAME);
77
semctl(int semid, int semnum, int cmd, /* ... */ union semun arg)
81
sem_wait(&SemInfo->sem);
83
if (semid < 0 || semid >= SemInfo->nsets ||
84
semnum < 0 || semnum >= SemInfo->set[semid].nsems)
86
sem_post(&SemInfo->sem);
94
r = SemInfo->set[semid].semV[semnum].semncnt;
98
r = SemInfo->set[semid].semV[semnum].sempid;
102
r = SemInfo->set[semid].semV[semnum].semval;
106
for (semnum = 0; semnum < SemInfo->set[semid].nsems; semnum++)
107
arg.array[semnum] = SemInfo->set[semid].semV[semnum].semval;
111
SemInfo->set[semid].semV[semnum].semval = arg.val;
115
for (semnum = 0; semnum < SemInfo->set[semid].nsems; semnum++)
116
SemInfo->set[semid].semV[semnum].semval = arg.array[semnum];
120
r = SemInfo->set[semid].semV[semnum].semzcnt;
124
for (semnum = 0; semnum < SemInfo->set[semid].nsems; semnum++)
126
if (sem_destroy(&SemInfo->set[semid].sem[semnum]) == -1)
129
SemInfo->set[semid].key = -1;
130
SemInfo->set[semid].nsems = 0;
134
sem_post(&SemInfo->sem);
139
sem_post(&SemInfo->sem);
145
semget(key_t key, int nsems, int semflg)
155
if (nsems < 0 || nsems > SEMMAX)
161
/* open and map shared memory */
162
if (SemInfo == (struct sem_info *) - 1)
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)
169
fd = shm_open(SHM_INFO_NAME, O_RDWR | O_CREAT, MODE);
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 */
184
* size is rounded by proc to the next __PAGESIZE
186
if (statbuf.st_size !=
187
(((sem_info_size / __PAGESIZE) + 1) * __PAGESIZE))
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,
200
SemInfo = mmap(NULL, sem_info_size,
201
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
202
if (SemInfo == MAP_FAILED)
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);
217
sem_wait(&SemInfo->sem);
218
nsets = SemInfo->nsets;
220
if (key != IPC_PRIVATE)
222
/* search existing element */
224
while (semid < nsets && SemInfo->set[semid].key != key)
226
if (!(semflg & IPC_CREAT) && semid >= nsets)
228
sem_post(&SemInfo->sem);
232
else if (semid < nsets)
234
if (semflg & IPC_CREAT && semflg & IPC_EXCL)
236
sem_post(&SemInfo->sem);
242
if (nsems != 0 && SemInfo->set[semid].nsems < nsems)
244
sem_post(&SemInfo->sem);
248
sem_post(&SemInfo->sem);
254
/* search first free element */
256
while (semid < nsets && SemInfo->set[semid].key != -1)
260
sem_post(&SemInfo->sem);
265
for (semnum = 0; semnum < nsems; semnum++)
267
sem_init(&SemInfo->set[semid].sem[semnum], 1, 0);
268
/* Currently sem_init always returns -1. */
270
if (sem_init(&SemInfo->set[semid].sem[semnum], 1, 0) == -1)
274
for (semnum1 = 0; semnum1 < semnum; semnum1++)
275
sem_destroy(&SemInfo->set[semid].sem[semnum1]);
276
sem_post(&SemInfo->sem);
282
SemInfo->set[semid].key = key;
283
SemInfo->set[semid].nsems = nsems;
285
sem_post(&SemInfo->sem);
291
semop(int semid, struct sembuf * sops, size_t nsops)
299
sem_wait(&SemInfo->sem);
301
if (semid < 0 || semid >= SemInfo->nsets)
303
sem_post(&SemInfo->sem);
307
for (i = 0; i < nsops; i++)
309
if ( /* sops[i].sem_num < 0 || */ sops[i].sem_num >= SemInfo->set[semid].nsems)
311
sem_post(&SemInfo->sem);
317
for (i = 0; i < nsops; i++)
319
if (sops[i].sem_op < 0)
321
if (SemInfo->set[semid].semV[sops[i].sem_num].semval < -sops[i].sem_op)
323
if (sops[i].sem_flg & IPC_NOWAIT)
325
sem_post(&SemInfo->sem);
329
SemInfo->set[semid].semV[sops[i].sem_num].semncnt++;
330
if (SemInfo->set[semid].pendingOps[sops[i].sem_num].idx >= OPMAX)
332
/* pending operations array overflow */
333
sem_post(&SemInfo->sem);
337
SemInfo->set[semid].pendingOps[sops[i].sem_num].op[SemInfo->set[semid].pendingOps[sops[i].sem_num].idx++] = sops[i].sem_op;
339
sem_post(&SemInfo->sem); /* avoid deadlock */
340
r1 = sem_wait(&SemInfo->set[semid].sem[sops[i].sem_num]);
341
sem_wait(&SemInfo->sem);
346
/* remove pending operation */
347
SemInfo->set[semid].pendingOps[sops[i].sem_num].op[--SemInfo->set[semid].pendingOps[sops[i].sem_num].idx] = 0;
350
SemInfo->set[semid].semV[sops[i].sem_num].semval -= -sops[i].sem_op;
351
SemInfo->set[semid].semV[sops[i].sem_num].semncnt--;
354
SemInfo->set[semid].semV[sops[i].sem_num].semval -= -sops[i].sem_op;
356
else if (sops[i].sem_op > 0)
358
SemInfo->set[semid].semV[sops[i].sem_num].semval += 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)
364
/* unsuspend processes */
365
if (sem_post(&SemInfo->set[semid].sem[sops[i].sem_num]))
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;
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;
383
/* sops[i].sem_op == 0 */
386
sem_post(&SemInfo->sem);
390
SemInfo->set[semid].semV[sops[i].sem_num].sempid = getpid();
393
sem_post(&SemInfo->sem);