mirror of https://github.com/postgres/postgres
parent
3e48c66136
commit
8df5625966
@ -1,389 +0,0 @@ |
|||||||
/*-------------------------------------------------------------------------
|
|
||||||
* |
|
||||||
* sem.c |
|
||||||
* System V Semaphore Emulation |
|
||||||
* |
|
||||||
* Copyright (c) 1999, repas AEG Automation GmbH |
|
||||||
* |
|
||||||
* 2000-12-1 pmb@mac.com |
|
||||||
* - changed from anonymous to named semaphores for darwin |
|
||||||
* - this required changing sem_info from containig an array of sem_t to an array of sem_t* |
|
||||||
* |
|
||||||
* IDENTIFICATION |
|
||||||
* $Header: /cvsroot/pgsql/src/backend/port/darwin/Attic/sem.c,v 1.5 2001/10/25 05:49:40 momjian Exp $ |
|
||||||
* |
|
||||||
*------------------------------------------------------------------------- |
|
||||||
*/ |
|
||||||
#include "postgres.h" |
|
||||||
|
|
||||||
#include <errno.h> |
|
||||||
#include <semaphore.h> |
|
||||||
#include <string.h> |
|
||||||
#include <sys/types.h> |
|
||||||
#include <unistd.h> |
|
||||||
#include <fcntl.h> |
|
||||||
#include <sys/mman.h> |
|
||||||
|
|
||||||
#include "miscadmin.h" |
|
||||||
#include "storage/ipc.h" |
|
||||||
#include "storage/proc.h" |
|
||||||
#include "port/darwin/sem.h" |
|
||||||
|
|
||||||
#define SEMMAX IPC_NMAXSEM |
|
||||||
#define OPMAX 8 |
|
||||||
|
|
||||||
#define MODE 0700 |
|
||||||
#define SHM_INFO_NAME "SysV_Sem_Info" |
|
||||||
#define SEM_NAME "/pgsql-darwin" |
|
||||||
|
|
||||||
struct pending_ops |
|
||||||
{ |
|
||||||
int op[OPMAX]; /* array of pending operations */ |
|
||||||
int idx; /* index of first free array member */ |
|
||||||
}; |
|
||||||
|
|
||||||
struct sem_set_info |
|
||||||
{ |
|
||||||
key_t key; |
|
||||||
int nsems; |
|
||||||
sem_t *sem[SEMMAX]; /* array of POSIX semaphores */ |
|
||||||
struct sem semV[SEMMAX]; /* array of System V semaphore structures */ |
|
||||||
struct pending_ops pendingOps[SEMMAX]; /* array of pending
|
|
||||||
* operations */ |
|
||||||
}; |
|
||||||
|
|
||||||
struct sem_info |
|
||||||
{ |
|
||||||
sem_t *sem; |
|
||||||
int nsets; |
|
||||||
/* there are actually nsets of these: */ |
|
||||||
struct sem_set_info set[1]; /* VARIABLE LENGTH ARRAY */ |
|
||||||
}; |
|
||||||
|
|
||||||
static struct sem_info *SemInfo = (struct sem_info *) - 1; |
|
||||||
|
|
||||||
|
|
||||||
int |
|
||||||
semctl(int semid, int semnum, int cmd, /* ... */ union semun arg) |
|
||||||
{ |
|
||||||
int r = 0; |
|
||||||
|
|
||||||
sem_wait(SemInfo->sem); |
|
||||||
|
|
||||||
if (semid < 0 || semid >= SemInfo->nsets || |
|
||||||
semnum < 0 || semnum >= SemInfo->set[semid].nsems) |
|
||||||
{ |
|
||||||
sem_post(SemInfo->sem); |
|
||||||
errno = EINVAL; |
|
||||||
return -1; |
|
||||||
} |
|
||||||
|
|
||||||
switch (cmd) |
|
||||||
{ |
|
||||||
case GETNCNT: |
|
||||||
r = SemInfo->set[semid].semV[semnum].semncnt; |
|
||||||
break; |
|
||||||
|
|
||||||
case GETPID: |
|
||||||
r = SemInfo->set[semid].semV[semnum].sempid; |
|
||||||
break; |
|
||||||
|
|
||||||
case GETVAL: |
|
||||||
r = SemInfo->set[semid].semV[semnum].semval; |
|
||||||
break; |
|
||||||
|
|
||||||
case GETALL: |
|
||||||
for (semnum = 0; semnum < SemInfo->set[semid].nsems; semnum++) |
|
||||||
arg.array[semnum] = SemInfo->set[semid].semV[semnum].semval; |
|
||||||
break; |
|
||||||
|
|
||||||
case SETVAL: |
|
||||||
SemInfo->set[semid].semV[semnum].semval = arg.val; |
|
||||||
break; |
|
||||||
|
|
||||||
case SETALL: |
|
||||||
for (semnum = 0; semnum < SemInfo->set[semid].nsems; semnum++) |
|
||||||
SemInfo->set[semid].semV[semnum].semval = arg.array[semnum]; |
|
||||||
break; |
|
||||||
|
|
||||||
case GETZCNT: |
|
||||||
r = SemInfo->set[semid].semV[semnum].semzcnt; |
|
||||||
break; |
|
||||||
|
|
||||||
case IPC_RMID: |
|
||||||
for (semnum = 0; semnum < SemInfo->set[semid].nsems; semnum++) |
|
||||||
{ |
|
||||||
if (sem_close(SemInfo->set[semid].sem[semnum]) == -1) |
|
||||||
r = -1; |
|
||||||
} |
|
||||||
SemInfo->set[semid].key = -1; |
|
||||||
SemInfo->set[semid].nsems = 0; |
|
||||||
break; |
|
||||||
|
|
||||||
default: |
|
||||||
sem_post(SemInfo->sem); |
|
||||||
errno = EINVAL; |
|
||||||
return -1; |
|
||||||
} |
|
||||||
|
|
||||||
sem_post(SemInfo->sem); |
|
||||||
|
|
||||||
return r; |
|
||||||
} |
|
||||||
|
|
||||||
int |
|
||||||
semget(key_t key, int nsems, int semflg) |
|
||||||
{ |
|
||||||
int fd, |
|
||||||
semid, |
|
||||||
semnum, |
|
||||||
nsets; |
|
||||||
int exist = 0; |
|
||||||
Size sem_info_size; |
|
||||||
char semname[64]; |
|
||||||
|
|
||||||
if (nsems < 0 || nsems > SEMMAX) |
|
||||||
{ |
|
||||||
#ifdef DEBUG_IPC |
|
||||||
fprintf(stderr, "darwin semget aborting because nsems out of range. (%d)\n", nsems); |
|
||||||
#endif |
|
||||||
errno = EINVAL; |
|
||||||
return -1; |
|
||||||
} |
|
||||||
|
|
||||||
/* open and map shared memory */ |
|
||||||
if (SemInfo == (struct sem_info *) - 1) |
|
||||||
{ |
|
||||||
#ifdef DEBUG_IPC |
|
||||||
fprintf(stderr, "darwin initializing shared mem for semaphore shim.\n"); |
|
||||||
#endif |
|
||||||
/* test if the shared memory already exists */ |
|
||||||
fd = shm_open(SHM_INFO_NAME, O_RDWR | O_CREAT | O_EXCL, MODE); |
|
||||||
if (fd == -1 && errno == EEXIST) |
|
||||||
{ |
|
||||||
/* exist = 1; */ |
|
||||||
shm_unlink(SHM_INFO_NAME); |
|
||||||
fd = shm_open(SHM_INFO_NAME, O_RDWR | O_CREAT | O_EXCL, MODE); |
|
||||||
} |
|
||||||
if (fd == -1) |
|
||||||
return fd; |
|
||||||
shm_unlink(SHM_INFO_NAME); |
|
||||||
/* The size may only be set once. Ignore errors. */ |
|
||||||
nsets = PROC_SEM_MAP_ENTRIES(MaxBackends); |
|
||||||
sem_info_size = sizeof(struct sem_info) + (nsets - 1) * sizeof(struct sem_set_info); |
|
||||||
ftruncate(fd, sem_info_size); |
|
||||||
SemInfo = mmap(NULL, sem_info_size, |
|
||||||
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); |
|
||||||
if (SemInfo == MAP_FAILED) |
|
||||||
return -1; |
|
||||||
if (!exist) |
|
||||||
{ |
|
||||||
/* initialize shared memory */ |
|
||||||
memset(SemInfo, 0, sem_info_size); |
|
||||||
SemInfo->nsets = nsets; |
|
||||||
for (semid = 0; semid < nsets; semid++) |
|
||||||
SemInfo->set[semid].key = -1; |
|
||||||
/* create semaphore for locking */ |
|
||||||
sprintf(semname, "%s-map", SEM_NAME); |
|
||||||
#ifdef DEBUG_IPC |
|
||||||
fprintf(stderr, "darwin creating sem %s to cover shared mem.\n", semname); |
|
||||||
#endif |
|
||||||
SemInfo->sem = sem_open(semname, O_CREAT, semflg & 0777, 1); |
|
||||||
sem_unlink(semname); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
sem_wait(SemInfo->sem); |
|
||||||
nsets = SemInfo->nsets; |
|
||||||
|
|
||||||
if (key != IPC_PRIVATE) |
|
||||||
{ |
|
||||||
/* search existing element */ |
|
||||||
semid = 0; |
|
||||||
while (semid < nsets && SemInfo->set[semid].key != key) |
|
||||||
semid++; |
|
||||||
if (!(semflg & IPC_CREAT) && semid >= nsets) |
|
||||||
{ |
|
||||||
sem_post(SemInfo->sem); |
|
||||||
errno = ENOENT; |
|
||||||
return -1; |
|
||||||
} |
|
||||||
else if (semid < nsets) |
|
||||||
{ |
|
||||||
if (semflg & IPC_CREAT && semflg & IPC_EXCL) |
|
||||||
{ |
|
||||||
sem_post(SemInfo->sem); |
|
||||||
errno = EEXIST; |
|
||||||
return -1; |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
if (nsems != 0 && SemInfo->set[semid].nsems < nsems) |
|
||||||
{ |
|
||||||
#ifdef DEBUG_IPC |
|
||||||
fprintf(stderr, "darwin semget failed because if (nsems != 0 && SemInfo->set[semid].nsems < nsems) %d %d\n", |
|
||||||
nsems, SemInfo->set[semid].nsems); |
|
||||||
#endif |
|
||||||
sem_post(SemInfo->sem); |
|
||||||
errno = EINVAL; |
|
||||||
return -1; |
|
||||||
} |
|
||||||
sem_post(SemInfo->sem); |
|
||||||
return semid; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/* search first free element */ |
|
||||||
semid = 0; |
|
||||||
while (semid < nsets && SemInfo->set[semid].key != -1) |
|
||||||
semid++; |
|
||||||
if (semid >= nsets) |
|
||||||
{ |
|
||||||
#ifdef DEBUG_IPC |
|
||||||
fprintf(stderr, "darwin semget failed because all keys were -1\n"); |
|
||||||
#endif |
|
||||||
sem_post(SemInfo->sem); |
|
||||||
errno = ENOSPC; |
|
||||||
return -1; |
|
||||||
} |
|
||||||
|
|
||||||
for (semnum = 0; semnum < nsems; semnum++) |
|
||||||
{ |
|
||||||
sprintf(semname, "%s-%d-%d", SEM_NAME, semid, semnum); |
|
||||||
#ifdef DEBUG_IPC |
|
||||||
fprintf(stderr, "darwin creating sem %s to cover set %d num %dm.\n", semname, semid, semnum); |
|
||||||
#endif |
|
||||||
SemInfo->set[semid].sem[semnum] = sem_open(semname, O_CREAT, semflg & 0777, 0); |
|
||||||
sem_unlink(semname); |
|
||||||
|
|
||||||
/* Currently sem_init always returns -1. */ |
|
||||||
#ifdef NOT_USED |
|
||||||
if (sem_init(&SemInfo->set[semid].sem[semnum], 1, 0) == -1) |
|
||||||
{ |
|
||||||
int semnum1; |
|
||||||
|
|
||||||
for (semnum1 = 0; semnum1 < semnum; semnum1++) |
|
||||||
sem_close(SemInfo->set[semid].sem[semnum1]); |
|
||||||
sem_post(SemInfo->sem); |
|
||||||
return -1; |
|
||||||
} |
|
||||||
#endif |
|
||||||
} |
|
||||||
|
|
||||||
SemInfo->set[semid].key = key; |
|
||||||
SemInfo->set[semid].nsems = nsems; |
|
||||||
|
|
||||||
sem_post(SemInfo->sem); |
|
||||||
|
|
||||||
return semid; |
|
||||||
} |
|
||||||
|
|
||||||
int |
|
||||||
semop(int semid, struct sembuf * sops, size_t nsops) |
|
||||||
{ |
|
||||||
int i, |
|
||||||
r = 0, |
|
||||||
r1, |
|
||||||
errno1 = 0, |
|
||||||
op; |
|
||||||
|
|
||||||
sem_wait(SemInfo->sem); |
|
||||||
|
|
||||||
if (semid < 0 || semid >= SemInfo->nsets) |
|
||||||
{ |
|
||||||
sem_post(SemInfo->sem); |
|
||||||
errno = EINVAL; |
|
||||||
return -1; |
|
||||||
} |
|
||||||
for (i = 0; i < nsops; i++) |
|
||||||
{ |
|
||||||
if ( /* sops[i].sem_num < 0 || */ sops[i].sem_num >= SemInfo->set[semid].nsems) |
|
||||||
{ |
|
||||||
sem_post(SemInfo->sem); |
|
||||||
errno = EFBIG; |
|
||||||
return -1; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
for (i = 0; i < nsops; i++) |
|
||||||
{ |
|
||||||
if (sops[i].sem_op < 0) |
|
||||||
{ |
|
||||||
if (SemInfo->set[semid].semV[sops[i].sem_num].semval < -sops[i].sem_op) |
|
||||||
{ |
|
||||||
if (sops[i].sem_flg & IPC_NOWAIT) |
|
||||||
{ |
|
||||||
sem_post(SemInfo->sem); |
|
||||||
errno = EAGAIN; |
|
||||||
return -1; |
|
||||||
} |
|
||||||
SemInfo->set[semid].semV[sops[i].sem_num].semncnt++; |
|
||||||
if (SemInfo->set[semid].pendingOps[sops[i].sem_num].idx >= OPMAX) |
|
||||||
{ |
|
||||||
/* pending operations array overflow */ |
|
||||||
sem_post(SemInfo->sem); |
|
||||||
errno = ERANGE; |
|
||||||
return -1; |
|
||||||
} |
|
||||||
SemInfo->set[semid].pendingOps[sops[i].sem_num].op[SemInfo->set[semid].pendingOps[sops[i].sem_num].idx++] = sops[i].sem_op; |
|
||||||
/* suspend */ |
|
||||||
sem_post(SemInfo->sem); /* avoid deadlock */ |
|
||||||
r1 = sem_wait(SemInfo->set[semid].sem[sops[i].sem_num]); |
|
||||||
sem_wait(SemInfo->sem); |
|
||||||
if (r1) |
|
||||||
{ |
|
||||||
errno1 = errno; |
|
||||||
r = r1; |
|
||||||
/* remove pending operation */ |
|
||||||
SemInfo->set[semid].pendingOps[sops[i].sem_num].op[--SemInfo->set[semid].pendingOps[sops[i].sem_num].idx] = 0; |
|
||||||
} |
|
||||||
else |
|
||||||
SemInfo->set[semid].semV[sops[i].sem_num].semval -= -sops[i].sem_op; |
|
||||||
SemInfo->set[semid].semV[sops[i].sem_num].semncnt--; |
|
||||||
} |
|
||||||
else |
|
||||||
SemInfo->set[semid].semV[sops[i].sem_num].semval -= -sops[i].sem_op; |
|
||||||
} |
|
||||||
else if (sops[i].sem_op > 0) |
|
||||||
{ |
|
||||||
SemInfo->set[semid].semV[sops[i].sem_num].semval += sops[i].sem_op; |
|
||||||
op = sops[i].sem_op; |
|
||||||
while (op > 0 && SemInfo->set[semid].pendingOps[sops[i].sem_num].idx > 0) |
|
||||||
{ /* operations pending */ |
|
||||||
if (SemInfo->set[semid].pendingOps[sops[i].sem_num].op[SemInfo->set[semid].pendingOps[sops[i].sem_num].idx - 1] + op >= 0) |
|
||||||
{ |
|
||||||
/* unsuspend processes */ |
|
||||||
if (sem_post(SemInfo->set[semid].sem[sops[i].sem_num])) |
|
||||||
{ |
|
||||||
errno1 = errno; |
|
||||||
r = -1; |
|
||||||
} |
|
||||||
/* adjust pending operations */ |
|
||||||
op += SemInfo->set[semid].pendingOps[sops[i].sem_num].op[--SemInfo->set[semid].pendingOps[sops[i].sem_num].idx]; |
|
||||||
SemInfo->set[semid].pendingOps[sops[i].sem_num].op[SemInfo->set[semid].pendingOps[sops[i].sem_num].idx] = 0; |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
/* adjust pending operations */ |
|
||||||
SemInfo->set[semid].pendingOps[sops[i].sem_num].op[SemInfo->set[semid].pendingOps[sops[i].sem_num].idx - 1] += op; |
|
||||||
op = 0; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
else |
|
||||||
/* sops[i].sem_op == 0 */ |
|
||||||
{ |
|
||||||
/* not supported */ |
|
||||||
sem_post(SemInfo->sem); |
|
||||||
errno = ENOSYS; |
|
||||||
return -1; |
|
||||||
} |
|
||||||
SemInfo->set[semid].semV[sops[i].sem_num].sempid = getpid(); |
|
||||||
} |
|
||||||
|
|
||||||
sem_post(SemInfo->sem); |
|
||||||
|
|
||||||
errno = errno1; |
|
||||||
return r; |
|
||||||
} |
|
Loading…
Reference in new issue