]> granicus.if.org Git - postgresql/blob - src/backend/port/win32_sema.c
pgindent run for release 9.3
[postgresql] / src / backend / port / win32_sema.c
1 /*-------------------------------------------------------------------------
2  *
3  * win32_sema.c
4  *        Microsoft Windows Win32 Semaphores Emulation
5  *
6  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
7  *
8  * IDENTIFICATION
9  *        src/backend/port/win32_sema.c
10  *
11  *-------------------------------------------------------------------------
12  */
13
14 #include "postgres.h"
15
16 #include "miscadmin.h"
17 #include "storage/ipc.h"
18 #include "storage/pg_sema.h"
19
20 static HANDLE *mySemSet;                /* IDs of sema sets acquired so far */
21 static int      numSems;                        /* number of sema sets acquired so far */
22 static int      maxSems;                        /* allocated size of mySemaSet array */
23
24 static void ReleaseSemaphores(int code, Datum arg);
25
26 /*
27  * PGReserveSemaphores --- initialize semaphore support
28  *
29  * In the Win32 implementation, we acquire semaphores on-demand; the
30  * maxSemas parameter is just used to size the array that keeps track of
31  * acquired semas for subsequent releasing.  We use anonymous semaphores
32  * so the semaphores are automatically freed when the last referencing
33  * process exits.
34  */
35 void
36 PGReserveSemaphores(int maxSemas, int port)
37 {
38         mySemSet = (HANDLE *) malloc(maxSemas * sizeof(HANDLE));
39         if (mySemSet == NULL)
40                 elog(PANIC, "out of memory");
41         numSems = 0;
42         maxSems = maxSemas;
43
44         on_shmem_exit(ReleaseSemaphores, 0);
45 }
46
47 /*
48  * Release semaphores at shutdown or shmem reinitialization
49  *
50  * (called as an on_shmem_exit callback, hence funny argument list)
51  */
52 static void
53 ReleaseSemaphores(int code, Datum arg)
54 {
55         int                     i;
56
57         for (i = 0; i < numSems; i++)
58                 CloseHandle(mySemSet[i]);
59         free(mySemSet);
60 }
61
62 /*
63  * PGSemaphoreCreate
64  *
65  * Initialize a PGSemaphore structure to represent a sema with count 1
66  */
67 void
68 PGSemaphoreCreate(PGSemaphore sema)
69 {
70         HANDLE          cur_handle;
71         SECURITY_ATTRIBUTES sec_attrs;
72
73         /* Can't do this in a backend, because static state is postmaster's */
74         Assert(!IsUnderPostmaster);
75
76         if (numSems >= maxSems)
77                 elog(PANIC, "too many semaphores created");
78
79         ZeroMemory(&sec_attrs, sizeof(sec_attrs));
80         sec_attrs.nLength = sizeof(sec_attrs);
81         sec_attrs.lpSecurityDescriptor = NULL;
82         sec_attrs.bInheritHandle = TRUE;
83
84         /* We don't need a named semaphore */
85         cur_handle = CreateSemaphore(&sec_attrs, 1, 32767, NULL);
86         if (cur_handle)
87         {
88                 /* Successfully done */
89                 *sema = cur_handle;
90                 mySemSet[numSems++] = cur_handle;
91         }
92         else
93                 ereport(PANIC,
94                                 (errmsg("could not create semaphore: error code %lu", GetLastError())));
95 }
96
97 /*
98  * PGSemaphoreReset
99  *
100  * Reset a previously-initialized PGSemaphore to have count 0
101  */
102 void
103 PGSemaphoreReset(PGSemaphore sema)
104 {
105         /*
106          * There's no direct API for this in Win32, so we have to ratchet the
107          * semaphore down to 0 with repeated trylock's.
108          */
109         while (PGSemaphoreTryLock(sema));
110 }
111
112 /*
113  * PGSemaphoreLock
114  *
115  * Lock a semaphore (decrement count), blocking if count would be < 0.
116  * Serve the interrupt if interruptOK is true.
117  */
118 void
119 PGSemaphoreLock(PGSemaphore sema, bool interruptOK)
120 {
121         DWORD           ret;
122         HANDLE          wh[2];
123
124         /*
125          * Note: pgwin32_signal_event should be first to ensure that it will be
126          * reported when multiple events are set.  We want to guarantee that
127          * pending signals are serviced.
128          */
129         wh[0] = pgwin32_signal_event;
130         wh[1] = *sema;
131
132         /*
133          * As in other implementations of PGSemaphoreLock, we need to check for
134          * cancel/die interrupts each time through the loop.  But here, there is
135          * no hidden magic about whether the syscall will internally service a
136          * signal --- we do that ourselves.
137          */
138         do
139         {
140                 ImmediateInterruptOK = interruptOK;
141                 CHECK_FOR_INTERRUPTS();
142
143                 ret = WaitForMultipleObjectsEx(2, wh, FALSE, INFINITE, TRUE);
144
145                 if (ret == WAIT_OBJECT_0)
146                 {
147                         /* Signal event is set - we have a signal to deliver */
148                         pgwin32_dispatch_queued_signals();
149                         errno = EINTR;
150                 }
151                 else if (ret == WAIT_OBJECT_0 + 1)
152                 {
153                         /* We got it! */
154                         errno = 0;
155                 }
156                 else
157                         /* Otherwise we are in trouble */
158                         errno = EIDRM;
159
160                 ImmediateInterruptOK = false;
161         } while (errno == EINTR);
162
163         if (errno != 0)
164                 ereport(FATAL,
165                 (errmsg("could not lock semaphore: error code %lu", GetLastError())));
166 }
167
168 /*
169  * PGSemaphoreUnlock
170  *
171  * Unlock a semaphore (increment count)
172  */
173 void
174 PGSemaphoreUnlock(PGSemaphore sema)
175 {
176         if (!ReleaseSemaphore(*sema, 1, NULL))
177                 ereport(FATAL,
178                                 (errmsg("could not unlock semaphore: error code %lu", GetLastError())));
179 }
180
181 /*
182  * PGSemaphoreTryLock
183  *
184  * Lock a semaphore only if able to do so without blocking
185  */
186 bool
187 PGSemaphoreTryLock(PGSemaphore sema)
188 {
189         DWORD           ret;
190
191         ret = WaitForSingleObject(*sema, 0);
192
193         if (ret == WAIT_OBJECT_0)
194         {
195                 /* We got it! */
196                 return true;
197         }
198         else if (ret == WAIT_TIMEOUT)
199         {
200                 /* Can't get it */
201                 errno = EAGAIN;
202                 return false;
203         }
204
205         /* Otherwise we are in trouble */
206         ereport(FATAL,
207         (errmsg("could not try-lock semaphore: error code %lu", GetLastError())));
208
209         /* keep compiler quiet */
210         return false;
211 }