diff --git a/src/backend/port/win32/sem.c b/src/backend/port/win32/sem.c new file mode 100644 index 0000000000..33a29651ef --- /dev/null +++ b/src/backend/port/win32/sem.c @@ -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 + +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; im_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; +} diff --git a/src/backend/port/win32/shm.c b/src/backend/port/win32/shm.c new file mode 100644 index 0000000000..20aaf1f6a4 --- /dev/null +++ b/src/backend/port/win32/shm.c @@ -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 +#include + +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; +}