Header And Logo

PostgreSQL
| The world's most advanced open source database.

win32_sema.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * win32_sema.c
00004  *    Microsoft Windows Win32 Semaphores Emulation
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  *
00008  * IDENTIFICATION
00009  *    src/backend/port/win32_sema.c
00010  *
00011  *-------------------------------------------------------------------------
00012  */
00013 
00014 #include "postgres.h"
00015 
00016 #include "miscadmin.h"
00017 #include "storage/ipc.h"
00018 #include "storage/pg_sema.h"
00019 
00020 static HANDLE *mySemSet;        /* IDs of sema sets acquired so far */
00021 static int  numSems;            /* number of sema sets acquired so far */
00022 static int  maxSems;            /* allocated size of mySemaSet array */
00023 
00024 static void ReleaseSemaphores(int code, Datum arg);
00025 
00026 /*
00027  * PGReserveSemaphores --- initialize semaphore support
00028  *
00029  * In the Win32 implementation, we acquire semaphores on-demand; the
00030  * maxSemas parameter is just used to size the array that keeps track of
00031  * acquired semas for subsequent releasing.  We use anonymous semaphores
00032  * so the semaphores are automatically freed when the last referencing
00033  * process exits.
00034  */
00035 void
00036 PGReserveSemaphores(int maxSemas, int port)
00037 {
00038     mySemSet = (HANDLE *) malloc(maxSemas * sizeof(HANDLE));
00039     if (mySemSet == NULL)
00040         elog(PANIC, "out of memory");
00041     numSems = 0;
00042     maxSems = maxSemas;
00043 
00044     on_shmem_exit(ReleaseSemaphores, 0);
00045 }
00046 
00047 /*
00048  * Release semaphores at shutdown or shmem reinitialization
00049  *
00050  * (called as an on_shmem_exit callback, hence funny argument list)
00051  */
00052 static void
00053 ReleaseSemaphores(int code, Datum arg)
00054 {
00055     int         i;
00056 
00057     for (i = 0; i < numSems; i++)
00058         CloseHandle(mySemSet[i]);
00059     free(mySemSet);
00060 }
00061 
00062 /*
00063  * PGSemaphoreCreate
00064  *
00065  * Initialize a PGSemaphore structure to represent a sema with count 1
00066  */
00067 void
00068 PGSemaphoreCreate(PGSemaphore sema)
00069 {
00070     HANDLE      cur_handle;
00071     SECURITY_ATTRIBUTES sec_attrs;
00072 
00073     /* Can't do this in a backend, because static state is postmaster's */
00074     Assert(!IsUnderPostmaster);
00075 
00076     if (numSems >= maxSems)
00077         elog(PANIC, "too many semaphores created");
00078 
00079     ZeroMemory(&sec_attrs, sizeof(sec_attrs));
00080     sec_attrs.nLength = sizeof(sec_attrs);
00081     sec_attrs.lpSecurityDescriptor = NULL;
00082     sec_attrs.bInheritHandle = TRUE;
00083 
00084     /* We don't need a named semaphore */
00085     cur_handle = CreateSemaphore(&sec_attrs, 1, 32767, NULL);
00086     if (cur_handle)
00087     {
00088         /* Successfully done */
00089         *sema = cur_handle;
00090         mySemSet[numSems++] = cur_handle;
00091     }
00092     else
00093         ereport(PANIC,
00094                 (errmsg("could not create semaphore: error code %lu", GetLastError())));
00095 }
00096 
00097 /*
00098  * PGSemaphoreReset
00099  *
00100  * Reset a previously-initialized PGSemaphore to have count 0
00101  */
00102 void
00103 PGSemaphoreReset(PGSemaphore sema)
00104 {
00105     /*
00106      * There's no direct API for this in Win32, so we have to ratchet the
00107      * semaphore down to 0 with repeated trylock's.
00108      */
00109     while (PGSemaphoreTryLock(sema));
00110 }
00111 
00112 /*
00113  * PGSemaphoreLock
00114  *
00115  * Lock a semaphore (decrement count), blocking if count would be < 0.
00116  * Serve the interrupt if interruptOK is true.
00117  */
00118 void
00119 PGSemaphoreLock(PGSemaphore sema, bool interruptOK)
00120 {
00121     DWORD       ret;
00122     HANDLE      wh[2];
00123 
00124     /*
00125      * Note: pgwin32_signal_event should be first to ensure that it will be
00126      * reported when multiple events are set.  We want to guarantee that
00127      * pending signals are serviced.
00128      */
00129     wh[0] = pgwin32_signal_event;
00130     wh[1] = *sema;
00131 
00132     /*
00133      * As in other implementations of PGSemaphoreLock, we need to check for
00134      * cancel/die interrupts each time through the loop.  But here, there is
00135      * no hidden magic about whether the syscall will internally service a
00136      * signal --- we do that ourselves.
00137      */
00138     do
00139     {
00140         ImmediateInterruptOK = interruptOK;
00141         CHECK_FOR_INTERRUPTS();
00142 
00143         ret = WaitForMultipleObjectsEx(2, wh, FALSE, INFINITE, TRUE);
00144 
00145         if (ret == WAIT_OBJECT_0)
00146         {
00147             /* Signal event is set - we have a signal to deliver */
00148             pgwin32_dispatch_queued_signals();
00149             errno = EINTR;
00150         }
00151         else if (ret == WAIT_OBJECT_0 + 1)
00152         {
00153             /* We got it! */
00154             errno = 0;
00155         }
00156         else
00157             /* Otherwise we are in trouble */
00158             errno = EIDRM;
00159 
00160         ImmediateInterruptOK = false;
00161     } while (errno == EINTR);
00162 
00163     if (errno != 0)
00164         ereport(FATAL,
00165         (errmsg("could not lock semaphore: error code %lu", GetLastError())));
00166 }
00167 
00168 /*
00169  * PGSemaphoreUnlock
00170  *
00171  * Unlock a semaphore (increment count)
00172  */
00173 void
00174 PGSemaphoreUnlock(PGSemaphore sema)
00175 {
00176     if (!ReleaseSemaphore(*sema, 1, NULL))
00177         ereport(FATAL,
00178                 (errmsg("could not unlock semaphore: error code %lu", GetLastError())));
00179 }
00180 
00181 /*
00182  * PGSemaphoreTryLock
00183  *
00184  * Lock a semaphore only if able to do so without blocking
00185  */
00186 bool
00187 PGSemaphoreTryLock(PGSemaphore sema)
00188 {
00189     DWORD       ret;
00190 
00191     ret = WaitForSingleObject(*sema, 0);
00192 
00193     if (ret == WAIT_OBJECT_0)
00194     {
00195         /* We got it! */
00196         return true;
00197     }
00198     else if (ret == WAIT_TIMEOUT)
00199     {
00200         /* Can't get it */
00201         errno = EAGAIN;
00202         return false;
00203     }
00204 
00205     /* Otherwise we are in trouble */
00206     ereport(FATAL,
00207     (errmsg("could not try-lock semaphore: error code %lu", GetLastError())));
00208 
00209     /* keep compiler quiet */
00210     return false;
00211 }