OSDN Git Service

Add CVS ID tags to port/win32/files.
[pg-rex/syncrep.git] / src / backend / port / win32 / sema.c
1 /*-------------------------------------------------------------------------
2  *
3  * sema.c
4  *        Microsoft Windows Win32 Semaphores Emulation
5  *
6  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
7  *
8  * IDENTIFICATION
9  *        $PostgreSQL: pgsql/src/backend/port/win32/sema.c,v 1.5 2004/02/12 20:37:34 momjian Exp $
10  *
11  *-------------------------------------------------------------------------
12  */
13
14 #include "postgres.h"
15 #include "storage/shmem.h"
16
17 #include <errno.h>
18
19 typedef struct
20 {
21         int                     m_numSems;
22         off_t           m_semaphoreHandles;
23         /* offset from beginning of header */
24         off_t           m_semaphoreCounts;
25         /* offset from beginning of header */
26 }       win32_sem_set_hdr;
27
28 /* Control of a semaphore pool. The pool is an area in which we stored all
29 ** the semIds of the pool. The first long is the number of semaphore
30 ** allocated in the pool followed by semaphore handles
31 */
32
33 int
34 semctl(int semId, int semNum, int flag, union semun semun)
35 {
36         win32_sem_set_hdr *the_set = (win32_sem_set_hdr *) MAKE_PTR(semId);
37
38         /* semNum might be 0 */
39         /* semun.array contains the sem initial values */
40         int                *sem_counts = (int *) ((off_t) the_set + the_set->m_semaphoreCounts);
41
42         /* Fix the count of all sem of the pool to semun.array */
43         if (flag == SETALL)
44         {
45                 int                     i;
46                 struct sembuf sops;
47
48                 sops.sem_flg = IPC_NOWAIT;
49
50                 for (i = 0; i < the_set->m_numSems; ++i)
51                 {
52                         if (semun.array[i] == sem_counts[i])
53                                 continue;               /* Nothing to do */
54
55                         if (semun.array[i] < sem_counts[i])
56                                 sops.sem_op = -1;
57                         else
58                                 sops.sem_op = 1;
59
60                         sops.sem_num = i;
61
62                         /* Quickly lock/unlock the semaphore (if we can) */
63                         if (semop(semId, &sops, 1) < 0)
64                                 return -1;
65                 }
66                 return 1;
67         }
68
69         /* Fix the count of one semaphore to semun.val */
70         else if (flag == SETVAL)
71         {
72                 if (semun.val != sem_counts[semNum])
73                 {
74                         struct sembuf sops;
75
76                         sops.sem_flg = IPC_NOWAIT;
77                         sops.sem_num = semNum;
78
79                         if (semun.val < sem_counts[semNum])
80                                 sops.sem_op = -1;
81                         else
82                                 sops.sem_op = 1;
83
84                         /* Quickly lock/unlock the semaphore (if we can) */
85                         if (semop(semId, &sops, 1) < 0)
86                                 return -1;
87                 }
88
89                 return 1;
90         }
91
92         /* Delete the pool */
93         else if (flag == IPC_RMID)
94         {
95                 int                     i;
96                 HANDLE     *sem_handles = (HANDLE *) ((off_t) the_set + the_set->m_semaphoreHandles);
97
98                 /* Loop over all semaphore to delete them */
99                 for (i = 0; i < the_set->m_numSems; ++i)
100                         CloseHandle(sem_handles[i]);
101
102                 return 1;
103         }
104
105         /* Get the current semaphore count */
106         else if (flag == GETNCNT)
107                 return the_set->m_numSems;
108
109         /* Get the current semaphore count of the first semaphore in the pool */
110         else if (flag == GETVAL)
111                 return sem_counts[semNum];
112
113         /* Other commands not yet supported */
114         else
115         {
116                 errno = EINVAL;
117                 return -1;
118         }
119 }
120
121 /* Find a pool id based on IPC key */
122 int
123 semget(int semKey, int semNum, int flags)
124 {
125         char            semname[32];
126         char            cur_num[20];
127         DWORD           last_error;
128         char       *num_part;
129         bool            ans = true;
130         SECURITY_ATTRIBUTES sec_attrs;
131         HANDLE          cur_handle;
132         bool            found = false;
133         Size            sem_set_size = sizeof(win32_sem_set_hdr) + semNum * (sizeof(HANDLE) + sizeof(int));
134         HANDLE     *sem_handles = NULL;
135         int                *sem_counts = NULL;
136         int                     i;
137
138         sec_attrs.nLength = sizeof(sec_attrs);
139         sec_attrs.lpSecurityDescriptor = NULL;
140         sec_attrs.bInheritHandle = TRUE;
141
142         sprintf(semname, "PG_SEMSET.%d.", semKey);
143         num_part = semname + strlen(semname);
144
145         strcpy(num_part, _itoa(_getpid() * -1, cur_num, 10));           /* For shared memory,
146                                                                                                                                  * include the pid */
147         win32_sem_set_hdr *new_set = (win32_sem_set_hdr *) ShmemInitStruct(semname, sem_set_size, &found);
148
149         if (found)
150         {
151                 /* This should *never* happen */
152                 errno = EEXIST;
153                 return -1;
154         }
155
156         new_set->m_numSems = semNum;
157         new_set->m_semaphoreHandles = sizeof(win32_sem_set_hdr);
158         /* array starts after header */
159         new_set->m_semaphoreCounts = new_set->m_semaphoreHandles + (sizeof(HANDLE) * semNum);
160
161         sem_handles = (HANDLE *) ((off_t) new_set + new_set->m_semaphoreHandles);
162         sem_counts = (int *) ((off_t) new_set + new_set->m_semaphoreCounts);
163
164         for (i = 0; i < semNum && ans; ++i)
165         {
166                 strcpy(num_part, _itoa(i, cur_num, 10));
167
168                 if (flags & IPC_CREAT)
169                         cur_handle = CreateSemaphore(&sec_attrs, 0, 1, semname);
170                 else
171                         cur_handle = OpenSemaphore(SEMAPHORE_ALL_ACCESS, TRUE, semname);
172
173                 sem_handles[i] = cur_handle;
174
175                 last_error = GetLastError();
176                 if (!cur_handle)
177                 {
178                         errno = EACCES;
179                         ans = false;
180                 }
181                 else if (last_error == ERROR_ALREADY_EXISTS && (flags & (IPC_CREAT | IPC_EXCL)))
182                 {
183                         errno = EEXIST;
184                         ans = false;
185                 }
186         }
187
188         if (ans)
189                 return MAKE_OFFSET(new_set);
190         else
191         {
192                 int                     i;
193
194                 /* Blow away what we've got right now... */
195                 for (i = 0; i < semNum; ++i)
196                 {
197                         if (sem_handles[i])
198                                 CloseHandle(sem_handles[i]);
199                         else
200                                 break;
201                 }
202
203                 return -1;
204         }
205 }
206
207 /* Acquire or release in the semaphore pool */
208 int
209 semop(int semId, struct sembuf * sops, int nsops)
210 {
211         win32_sem_set_hdr *the_set = (win32_sem_set_hdr *) MAKE_PTR(semId);
212         HANDLE     *sem_handles = (HANDLE *) ((off_t) the_set + the_set->m_semaphoreHandles);
213         int                *sem_counts = (int *) ((off_t) the_set + the_set->m_semaphoreCounts);
214         HANDLE          cur_handle;
215
216         if (nsops != 1)
217         {
218                 /*
219                  * Not supported (we return on 1st success, and don't cancel
220                  * earlier ops)
221                  */
222                 errno = E2BIG;
223                 return -1;
224         }
225
226         cur_handle = sem_handles[sops[0].sem_num];
227
228         if (sops[0].sem_op == -1)
229         {
230                 DWORD           ret;
231
232                 if (sops[0].sem_flg & IPC_NOWAIT)
233                         ret = WaitForSingleObject(cur_handle, 0);
234                 else
235                         ret = WaitForSingleObject(cur_handle, INFINITE);
236
237                 if (ret == WAIT_OBJECT_0)
238                 {
239                         /* We got it! */
240                         sem_counts[sops[0].sem_num]--;
241                         return 0;
242                 }
243                 else if (ret == WAIT_TIMEOUT)
244                         /* Couldn't get it */
245                         errno = EAGAIN;
246                 else
247                         errno = EIDRM;
248         }
249         else if (sops[0].sem_op > 0)
250         {
251                 /* Don't want the lock anymore */
252                 sem_counts[sops[0].sem_num]++;
253                 ReleaseSemaphore(cur_handle, sops[0].sem_op, NULL);
254                 return 0;
255         }
256         else
257                 /* Not supported */
258                 errno = ERANGE;
259
260         /* If we get down here, then something is wrong */
261         return -1;
262 }