From 908f317b73c784b7101463d08d6415ef7fd5cb6c Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
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 f35cdd6b7e5..83a29062593 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 00000000000..bf8ee839f25
--- /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 bacbd7d3f0c..65a482468d3 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;
 
 
-- 
GitLab