mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-10-04 04:46:52 +02:00
Add shared memory and semaphore routines for Win32.
Also update copyright to be ours, with approval from Jan.
This commit is contained in:
parent
d670bf378c
commit
1a67e4869c
239
src/backend/port/win32/sem.c
Normal file
239
src/backend/port/win32/sem.c
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* sem.c
|
||||||
|
* Microsoft Windows Win32 Semaphores Emulation
|
||||||
|
*
|
||||||
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "postgres.h"
|
||||||
|
#include "storage/shmem.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int m_numSems;
|
||||||
|
off_t m_semaphoreHandles; // offset from beginning of header
|
||||||
|
off_t m_semaphoreCounts; // offset from beginning of header
|
||||||
|
} win32_sem_set_hdr;
|
||||||
|
|
||||||
|
/* Control of a semaphore pool. The pool is an area in which we stored all
|
||||||
|
** the semIds of the pool. The first long is the number of semaphore
|
||||||
|
** allocated in the pool followed by semaphore handles
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
semctl(int semId, int semNum, int flag, union semun semun)
|
||||||
|
{
|
||||||
|
win32_sem_set_hdr* the_set = (win32_sem_set_hdr*)MAKE_PTR(semId);
|
||||||
|
|
||||||
|
/* semNum might be 0 */
|
||||||
|
/* semun.array contains the sem initial values */
|
||||||
|
int* sem_counts = (int*)((off_t)the_set + the_set->m_semaphoreCounts);
|
||||||
|
|
||||||
|
/* Fix the count of all sem of the pool to semun.array */
|
||||||
|
if (flag == SETALL)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct sembuf sops;
|
||||||
|
sops.sem_flg = IPC_NOWAIT;
|
||||||
|
|
||||||
|
for (i = 0; i < the_set->m_numSems; ++i) {
|
||||||
|
if (semun.array[i] == sem_counts[i])
|
||||||
|
continue; /* Nothing to do */
|
||||||
|
|
||||||
|
if (semun.array[i] < sem_counts[i])
|
||||||
|
sops.sem_op = -1;
|
||||||
|
else
|
||||||
|
sops.sem_op = 1;
|
||||||
|
|
||||||
|
sops.sem_num = i;
|
||||||
|
|
||||||
|
/* Quickly lock/unlock the semaphore (if we can) */
|
||||||
|
if (semop(semId, &sops, 1) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix the count of one semaphore to semun.val */
|
||||||
|
else if (flag == SETVAL)
|
||||||
|
{
|
||||||
|
if (semun.val != sem_counts[semNum]) {
|
||||||
|
struct sembuf sops;
|
||||||
|
sops.sem_flg = IPC_NOWAIT;
|
||||||
|
sops.sem_num = semNum;
|
||||||
|
|
||||||
|
if (semun.val < sem_counts[semNum])
|
||||||
|
sops.sem_op = -1;
|
||||||
|
else
|
||||||
|
sops.sem_op = 1;
|
||||||
|
|
||||||
|
/* Quickly lock/unlock the semaphore (if we can) */
|
||||||
|
if (semop(semId, &sops, 1) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Delete the pool */
|
||||||
|
else if (flag == IPC_RMID)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
HANDLE* sem_handles = (HANDLE*)((off_t)the_set + the_set->m_semaphoreHandles);
|
||||||
|
|
||||||
|
/* Loop over all semaphore to delete them */
|
||||||
|
for (i = 0; i < the_set->m_numSems; ++i)
|
||||||
|
CloseHandle(sem_handles[i]);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the current semaphore count */
|
||||||
|
else if (flag == GETNCNT)
|
||||||
|
{
|
||||||
|
return the_set->m_numSems;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the current semaphore count of the first semaphore in the pool */
|
||||||
|
else if (flag == GETVAL)
|
||||||
|
{
|
||||||
|
return sem_counts[semNum];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Other commands not yet supported */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find a pool id based on IPC key */
|
||||||
|
int
|
||||||
|
semget(int semKey, int semNum, int flags)
|
||||||
|
{
|
||||||
|
char semname[32];
|
||||||
|
char cur_num[20];
|
||||||
|
DWORD last_error;
|
||||||
|
char* num_part;
|
||||||
|
bool ans = true;
|
||||||
|
SECURITY_ATTRIBUTES sec_attrs;
|
||||||
|
HANDLE cur_handle;
|
||||||
|
bool found = false;
|
||||||
|
Size sem_set_size = sizeof(win32_sem_set_hdr) + semNum * (sizeof(HANDLE) + sizeof(int));
|
||||||
|
HANDLE* sem_handles = NULL;
|
||||||
|
int* sem_counts = NULL;
|
||||||
|
|
||||||
|
sec_attrs.nLength = sizeof(sec_attrs);
|
||||||
|
sec_attrs.lpSecurityDescriptor = NULL;
|
||||||
|
sec_attrs.bInheritHandle = TRUE;
|
||||||
|
|
||||||
|
sprintf(semname, "PG_SEMSET.%d.", semKey);
|
||||||
|
num_part = semname + strlen(semname);
|
||||||
|
|
||||||
|
strcpy(num_part, _itoa(_getpid() * -1, cur_num, 10)); /* For shared memory, include the pid */
|
||||||
|
win32_sem_set_hdr* new_set = (win32_sem_set_hdr*)ShmemInitStruct(semname, sem_set_size, &found);
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
/* This should *never* happen */
|
||||||
|
errno = EEXIST;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_set->m_numSems = semNum;
|
||||||
|
new_set->m_semaphoreHandles = sizeof(win32_sem_set_hdr); // array starts after header
|
||||||
|
new_set->m_semaphoreCounts = new_set->m_semaphoreHandles + (sizeof(HANDLE) * semNum);
|
||||||
|
|
||||||
|
sem_handles = (HANDLE*)((off_t)new_set + new_set->m_semaphoreHandles);
|
||||||
|
sem_counts = (int*)((off_t)new_set + new_set->m_semaphoreCounts);
|
||||||
|
|
||||||
|
for (int i=0; i<semNum && ans; ++i) {
|
||||||
|
strcpy(num_part, _itoa(i, cur_num, 10));
|
||||||
|
|
||||||
|
if (flags & IPC_CREAT)
|
||||||
|
cur_handle = CreateSemaphore(&sec_attrs, 0, 1, semname);
|
||||||
|
else
|
||||||
|
cur_handle = OpenSemaphore(SEMAPHORE_ALL_ACCESS, TRUE, semname);
|
||||||
|
|
||||||
|
sem_handles[i] = cur_handle;
|
||||||
|
|
||||||
|
last_error = GetLastError();
|
||||||
|
if (!cur_handle)
|
||||||
|
{
|
||||||
|
errno = EACCES;
|
||||||
|
ans = false;
|
||||||
|
}
|
||||||
|
else if (last_error == ERROR_ALREADY_EXISTS && (flags & (IPC_CREAT | IPC_EXCL)))
|
||||||
|
{
|
||||||
|
errno = EEXIST;
|
||||||
|
ans = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ans) {
|
||||||
|
return MAKE_OFFSET(new_set);
|
||||||
|
} else {
|
||||||
|
// Blow away what we've got right now...
|
||||||
|
for (int i=0; i<semNum; ++i) {
|
||||||
|
if (sem_handles[i])
|
||||||
|
CloseHandle(sem_handles[i]);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Acquire or release in the semaphore pool */
|
||||||
|
int
|
||||||
|
semop(int semId, struct sembuf * sops, int nsops)
|
||||||
|
{
|
||||||
|
win32_sem_set_hdr* the_set = (win32_sem_set_hdr*)MAKE_PTR(semId);
|
||||||
|
HANDLE* sem_handles = (HANDLE*)((off_t)the_set + the_set->m_semaphoreHandles);
|
||||||
|
int* sem_counts = (int*)((off_t)the_set + the_set->m_semaphoreCounts);
|
||||||
|
HANDLE cur_handle;
|
||||||
|
|
||||||
|
if (nsops != 1) {
|
||||||
|
/* Not supported (we return on 1st success, and don't cancel earlier ops) */
|
||||||
|
errno = E2BIG;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_handle = sem_handles[sops[0].sem_num];
|
||||||
|
|
||||||
|
if (sops[0].sem_op == -1)
|
||||||
|
{
|
||||||
|
DWORD ret;
|
||||||
|
if (sops[0].sem_flg & IPC_NOWAIT)
|
||||||
|
ret = WaitForSingleObject(cur_handle, 0);
|
||||||
|
else
|
||||||
|
ret = WaitForSingleObject(cur_handle, INFINITE);
|
||||||
|
|
||||||
|
if (ret == WAIT_OBJECT_0) {
|
||||||
|
/* We got it! */
|
||||||
|
sem_counts[sops[0].sem_num]--;
|
||||||
|
return 0;
|
||||||
|
} else if (ret == WAIT_TIMEOUT)
|
||||||
|
/* Couldn't get it */
|
||||||
|
errno = EAGAIN;
|
||||||
|
else
|
||||||
|
errno = EIDRM;
|
||||||
|
}
|
||||||
|
else if (sops[0].sem_op > 0) {
|
||||||
|
/* Don't want the lock anymore */
|
||||||
|
sem_counts[sops[0].sem_num]++;
|
||||||
|
ReleaseSemaphore(cur_handle, sops[0].sem_op, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* Not supported */
|
||||||
|
errno = ERANGE;
|
||||||
|
|
||||||
|
/* If we get down here, then something is wrong */
|
||||||
|
return -1;
|
||||||
|
}
|
120
src/backend/port/win32/shm.c
Normal file
120
src/backend/port/win32/shm.c
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* shm.c
|
||||||
|
* Microsoft Windows Win32 Shared Memory Emulation
|
||||||
|
*
|
||||||
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "postgres.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
static DWORD s_segsize = 0;
|
||||||
|
|
||||||
|
/* Detach from a shared mem area based on its address */
|
||||||
|
int
|
||||||
|
shmdt(const void *shmaddr)
|
||||||
|
{
|
||||||
|
if (UnmapViewOfFile(shmaddr))
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attach to an existing area */
|
||||||
|
void *
|
||||||
|
shmat(int memId, void* shmaddr, int flag)
|
||||||
|
{
|
||||||
|
/* KEW_TODO -- shmat needs to count # attached to shared mem */
|
||||||
|
void *lpmem = MapViewOfFileEx((HANDLE)memId,
|
||||||
|
FILE_MAP_WRITE | FILE_MAP_READ,
|
||||||
|
0, 0, /* (DWORD)pshmdsc->segsize */ s_segsize, shmaddr);
|
||||||
|
|
||||||
|
if (lpmem == NULL) {
|
||||||
|
lpmem = (void *)-1;
|
||||||
|
errno = GetLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
return lpmem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Control a shared mem area */
|
||||||
|
int
|
||||||
|
shmctl(int shmid, int flag, struct shmid_ds * dummy)
|
||||||
|
{
|
||||||
|
if (flag == IPC_RMID)
|
||||||
|
{
|
||||||
|
/* Delete the area */
|
||||||
|
CloseHandle((HANDLE)shmid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (flag == IPC_STAT)
|
||||||
|
{
|
||||||
|
/* Can only test for if exists */
|
||||||
|
int hmap = shmget(shmid, 0, 0);
|
||||||
|
if (hmap < 0) {
|
||||||
|
/* Shared memory does not exist */
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Shared memory does exist and must be in use */
|
||||||
|
shmctl(hmap, IPC_RMID, NULL); /* Release our hold on it */
|
||||||
|
errno = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get an area based on the IPC key */
|
||||||
|
int
|
||||||
|
shmget(int memKey, int size, int flag)
|
||||||
|
{
|
||||||
|
HANDLE hmap;
|
||||||
|
char szShareMem[32];
|
||||||
|
DWORD dwRet;
|
||||||
|
|
||||||
|
s_segsize = size;
|
||||||
|
sprintf(szShareMem, "sharemem.%d", memKey);
|
||||||
|
|
||||||
|
if (flag & IPC_CREAT) {
|
||||||
|
hmap = CreateFileMapping((HANDLE)0xFFFFFFFF, /* Use the swap file */
|
||||||
|
NULL,
|
||||||
|
PAGE_READWRITE, /* Memory is Read/Write */
|
||||||
|
0L, /* Size Upper 32 Bits */
|
||||||
|
(DWORD)s_segsize, /* Size Lower 32 bits*/
|
||||||
|
szShareMem);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
hmap = OpenFileMapping(FILE_MAP_ALL_ACCESS,
|
||||||
|
FALSE,
|
||||||
|
szShareMem);
|
||||||
|
if (!hmap) {
|
||||||
|
errno = ENOENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dwRet = GetLastError();
|
||||||
|
if (dwRet == ERROR_ALREADY_EXISTS && hmap && (flag & (IPC_CREAT | IPC_EXCL))) {
|
||||||
|
/* Caller wanted to create the segment -- error if already exists */
|
||||||
|
CloseHandle(hmap);
|
||||||
|
errno = EEXIST;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (!hmap)
|
||||||
|
{
|
||||||
|
/* Unable to get shared memory */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)hmap;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user