From 908f317b73c784b7101463d08d6415ef7fd5cb6c Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Sat, 29 Apr 2006 16:34:41 +0000 Subject: [PATCH] Add Win32 semaphore implementation, rather than mimicking SysV semaphores. Qingqing Zhou --- configure.in | 23 +++-- src/backend/port/win32_sema.c | 195 ++++++++++++++++++++++++++++++++++++++++++ src/include/storage/pg_sema.h | 7 +- 3 files changed, 215 insertions(+), 10 deletions(-) create mode 100644 src/backend/port/win32_sema.c diff --git a/configure.in b/configure.in index f35cdd6b7e..83a2906259 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,5 @@ dnl Process this file with autoconf to produce a configure script. -dnl $PostgreSQL: pgsql/configure.in,v 1.462 2006/04/29 00:51:41 momjian Exp $ +dnl $PostgreSQL: pgsql/configure.in,v 1.463 2006/04/29 16:34:41 momjian Exp $ dnl dnl Developers, please strive to achieve this order: dnl @@ -1269,17 +1269,22 @@ AC_FUNC_MEMCMP # Select semaphore implementation type. -if test x"$USE_NAMED_POSIX_SEMAPHORES" = x"1" ; then - AC_DEFINE(USE_NAMED_POSIX_SEMAPHORES, 1, [Define to select named POSIX semaphores.]) - SEMA_IMPLEMENTATION="src/backend/port/posix_sema.c" -else - if test x"$USE_UNNAMED_POSIX_SEMAPHORES" = x"1" ; then - AC_DEFINE(USE_UNNAMED_POSIX_SEMAPHORES, 1, [Define to select unnamed POSIX semaphores.]) +if test "$PORTNAME" != "win32"; then + if test x"$USE_NAMED_POSIX_SEMAPHORES" = x"1" ; then + AC_DEFINE(USE_NAMED_POSIX_SEMAPHORES, 1, [Define to select named POSIX semaphores.]) SEMA_IMPLEMENTATION="src/backend/port/posix_sema.c" else - AC_DEFINE(USE_SYSV_SEMAPHORES, 1, [Define to select SysV-style semaphores.]) - SEMA_IMPLEMENTATION="src/backend/port/sysv_sema.c" + if test x"$USE_UNNAMED_POSIX_SEMAPHORES" = x"1" ; then + AC_DEFINE(USE_UNNAMED_POSIX_SEMAPHORES, 1, [Define to select unnamed POSIX semaphores.]) + SEMA_IMPLEMENTATION="src/backend/port/posix_sema.c" + else + AC_DEFINE(USE_SYSV_SEMAPHORES, 1, [Define to select SysV-style semaphores.]) + SEMA_IMPLEMENTATION="src/backend/port/sysv_sema.c" + fi fi +else + AC_DEFINE(USE_WIN32_SEMAPHORES, 1, [Define to select Win32-style semaphores.]) + SEMA_IMPLEMENTATION="src/backend/port/win32_sema.c" fi diff --git a/src/backend/port/win32_sema.c b/src/backend/port/win32_sema.c new file mode 100644 index 0000000000..bf8ee839f2 --- /dev/null +++ b/src/backend/port/win32_sema.c @@ -0,0 +1,195 @@ +/*------------------------------------------------------------------------- + * + * win32_sema.c + * Microsoft Windows Win32 Semaphores Emulation + * + * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/port/win32_sema.c,v 1.1 2006/04/29 16:34:41 momjian Exp $ + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "miscadmin.h" +#include "storage/ipc.h" +#include "storage/pg_sema.h" + +static HANDLE *mySemSet; /* IDs of sema sets acquired so far */ +static int numSems; /* number of sema sets acquired so far */ +static int maxSems; /* allocated size of mySemaSet array */ + +static void ReleaseSemaphores(int code, Datum arg); + +/* + * PGReserveSemaphores --- initialize semaphore support + * + * In the Win32 implementation, we acquire semaphores on-demand; the + * maxSemas parameter is just used to size the array that keeps track of + * acquired semas for subsequent releasing. We use anonymous semaphores + * so the semaphores are automatically freed when the last referencing + * process exits. + */ +void PGReserveSemaphores(int maxSemas, int port) +{ + mySemSet = (HANDLE *)malloc(maxSemas * sizeof(HANDLE)); + if (mySemSet == NULL) + elog(PANIC, "out of memory"); + numSems = 0; + maxSems = maxSemas; + + on_shmem_exit(ReleaseSemaphores, 0); +} + +/* + * Release semaphores at shutdown or shmem reinitialization + * + * (called as an on_shmem_exit callback, hence funny argument list) + */ +static void +ReleaseSemaphores(int code, Datum arg) +{ + int i; + + for (i = 0; i < numSems; i++) + CloseHandle(mySemSet[i]); + free(mySemSet); +} + +/* + * PGSemaphoreCreate + * + * Initialize a PGSemaphore structure to represent a sema with count 1 + */ +void PGSemaphoreCreate(PGSemaphore sema) +{ + HANDLE cur_handle; + SECURITY_ATTRIBUTES sec_attrs; + + /* Can't do this in a backend, because static state is postmaster's */ + Assert(!IsUnderPostmaster); + + if (numSems >= maxSems) + elog(PANIC, "too many semaphores created"); + + ZeroMemory(&sec_attrs, sizeof(sec_attrs)); + sec_attrs.nLength = sizeof(sec_attrs); + sec_attrs.lpSecurityDescriptor = NULL; + sec_attrs.bInheritHandle = TRUE; + + /* We don't need a named semaphore */ + cur_handle = CreateSemaphore(&sec_attrs, 1, 1, NULL); + if (cur_handle) + { + /* Successfully done */ + *sema = cur_handle; + mySemSet[numSems++] = cur_handle; + } + else + ereport(PANIC, + (errmsg("could not create semaphore: error code %d", (int)GetLastError()))); +} + +/* + * PGSemaphoreReset + * + * Reset a previously-initialized PGSemaphore to have count 0 + */ +void PGSemaphoreReset(PGSemaphore sema) +{ + /* + * There's no direct API for this in Win32, so we have to ratchet the + * semaphore down to 0 with repeated trylock's. + */ + while (PGSemaphoreTryLock(sema)); +} + +/* + * PGSemaphoreLock + * + * Lock a semaphore (decrement count), blocking if count would be < 0. + * Serve the interrupt if interruptOK is true. + */ +void PGSemaphoreLock(PGSemaphore sema, bool interruptOK) +{ + DWORD ret; + HANDLE wh[2]; + + wh[0] = *sema; + wh[1] = pgwin32_signal_event; + + do + { + ImmediateInterruptOK = interruptOK; + CHECK_FOR_INTERRUPTS(); + + errno = 0; + ret = WaitForMultipleObjectsEx(2, wh, FALSE, INFINITE, TRUE); + + if (ret == WAIT_OBJECT_0) + { + /* We got it! */ + return; + } + else if (ret == WAIT_OBJECT_0 + 1) + { + /* Signal event is set - we have a signal to deliver */ + pgwin32_dispatch_queued_signals(); + errno = EINTR; + } + else + /* Otherwise we are in trouble */ + errno = EIDRM; + + ImmediateInterruptOK = false; + } while (errno == EINTR); + + if (errno != 0) + ereport(FATAL, + (errmsg("could not lock semaphore: error code %d", (int) GetLastError()))); +} + +/* + * PGSemaphoreUnlock + * + * Unlock a semaphore (increment count) + */ +void PGSemaphoreUnlock(PGSemaphore sema) +{ + if (!ReleaseSemaphore(*sema, 1, NULL)) + ereport(FATAL, + (errmsg("could not unlock semaphore: error code %d", (int) GetLastError()))); +} + +/* + * PGSemaphoreTryLock + * + * Lock a semaphore only if able to do so without blocking + */ +bool PGSemaphoreTryLock(PGSemaphore sema) +{ + DWORD ret; + + ret = WaitForSingleObject(*sema, 0); + + if (ret == WAIT_OBJECT_0) + { + /* We got it! */ + return true; + } + else if (ret == WAIT_TIMEOUT) + { + /* Can't get it */ + errno = EAGAIN; + return false; + } + + /* Otherwise we are in trouble */ + ereport(FATAL, + (errmsg("could not try-lock semaphore: error code %d", (int) GetLastError()))); + + /* keep compiler quiet */ + return false; +} diff --git a/src/include/storage/pg_sema.h b/src/include/storage/pg_sema.h index bacbd7d3f0..65a482468d 100644 --- a/src/include/storage/pg_sema.h +++ b/src/include/storage/pg_sema.h @@ -13,7 +13,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/storage/pg_sema.h,v 1.8 2006/03/05 15:58:59 momjian Exp $ + * $PostgreSQL: pgsql/src/include/storage/pg_sema.h,v 1.9 2006/04/29 16:34:41 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -54,6 +54,11 @@ typedef struct PGSemaphoreData } PGSemaphoreData; #endif +#ifdef USE_WIN32_SEMAPHORES + +typedef HANDLE PGSemaphoreData; +#endif + typedef PGSemaphoreData *PGSemaphore; -- 2.11.0