Skip to content

Commit 1a67e48

Browse files
committed
Add shared memory and semaphore routines for Win32.
Also update copyright to be ours, with approval from Jan.
1 parent d670bf3 commit 1a67e48

File tree

2 files changed

+359
-0
lines changed

2 files changed

+359
-0
lines changed

src/backend/port/win32/sem.c

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

src/backend/port/win32/shm.c

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* shm.c
4+
* Microsoft Windows Win32 Shared Memory Emulation
5+
*
6+
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7+
*
8+
*-------------------------------------------------------------------------
9+
*/
10+
11+
#include "postgres.h"
12+
#include "windows.h"
13+
14+
#include <stdio.h>
15+
#include <errno.h>
16+
17+
static DWORD s_segsize = 0;
18+
19+
/* Detach from a shared mem area based on its address */
20+
int
21+
shmdt(const void *shmaddr)
22+
{
23+
if (UnmapViewOfFile(shmaddr))
24+
return 0;
25+
else
26+
return -1;
27+
}
28+
29+
/* Attach to an existing area */
30+
void *
31+
shmat(int memId, void* shmaddr, int flag)
32+
{
33+
/* KEW_TODO -- shmat needs to count # attached to shared mem */
34+
void *lpmem = MapViewOfFileEx((HANDLE)memId,
35+
FILE_MAP_WRITE | FILE_MAP_READ,
36+
0, 0, /* (DWORD)pshmdsc->segsize */ s_segsize, shmaddr);
37+
38+
if (lpmem == NULL) {
39+
lpmem = (void *)-1;
40+
errno = GetLastError();
41+
}
42+
43+
return lpmem;
44+
}
45+
46+
/* Control a shared mem area */
47+
int
48+
shmctl(int shmid, int flag, struct shmid_ds * dummy)
49+
{
50+
if (flag == IPC_RMID)
51+
{
52+
/* Delete the area */
53+
CloseHandle((HANDLE)shmid);
54+
return 0;
55+
}
56+
if (flag == IPC_STAT)
57+
{
58+
/* Can only test for if exists */
59+
int hmap = shmget(shmid, 0, 0);
60+
if (hmap < 0) {
61+
/* Shared memory does not exist */
62+
errno = EINVAL;
63+
return -1;
64+
}
65+
else {
66+
/* Shared memory does exist and must be in use */
67+
shmctl(hmap, IPC_RMID, NULL); /* Release our hold on it */
68+
errno = 0;
69+
return 0;
70+
}
71+
}
72+
73+
errno = EINVAL;
74+
return -1;
75+
}
76+
77+
/* Get an area based on the IPC key */
78+
int
79+
shmget(int memKey, int size, int flag)
80+
{
81+
HANDLE hmap;
82+
char szShareMem[32];
83+
DWORD dwRet;
84+
85+
s_segsize = size;
86+
sprintf(szShareMem, "sharemem.%d", memKey);
87+
88+
if (flag & IPC_CREAT) {
89+
hmap = CreateFileMapping((HANDLE)0xFFFFFFFF, /* Use the swap file */
90+
NULL,
91+
PAGE_READWRITE, /* Memory is Read/Write */
92+
0L, /* Size Upper 32 Bits */
93+
(DWORD)s_segsize, /* Size Lower 32 bits*/
94+
szShareMem);
95+
}
96+
else {
97+
hmap = OpenFileMapping(FILE_MAP_ALL_ACCESS,
98+
FALSE,
99+
szShareMem);
100+
if (!hmap) {
101+
errno = ENOENT;
102+
return -1;
103+
}
104+
}
105+
106+
dwRet = GetLastError();
107+
if (dwRet == ERROR_ALREADY_EXISTS && hmap && (flag & (IPC_CREAT | IPC_EXCL))) {
108+
/* Caller wanted to create the segment -- error if already exists */
109+
CloseHandle(hmap);
110+
errno = EEXIST;
111+
return -1;
112+
}
113+
else if (!hmap)
114+
{
115+
/* Unable to get shared memory */
116+
return -1;
117+
}
118+
119+
return (int)hmap;
120+
}

0 commit comments

Comments
 (0)