aboutsummaryrefslogtreecommitdiff
path: root/src/backend/port/win32/nt.c
blob: b5940051045fb56f96c1a35d3a07562bc45e4578 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
#include <windows.h>
#include <time.h>
#include "postgres.h"
#include "storage/ipc.h"

/* The name of the Postgres 95 ipc file mapping object */
#define IPC_NAME	"PG95_IPC"

/* The name of the Postgres 95 ipc file mapping object semaphore */
#define IPC_SEM_NAME	"PG95_IPC_SEM"

/* The maximum length of a shared memory object name */
#define IPC_MAX_SHMEM_NAME	32

/* The maximum number of emulated Unix shared memory segments */
#define IPC_NMAXSHM	10

/* The Maximum number of elements in a semaphore set. Note that this
** is just a guess.
*/
#define IPC_NMAXSEMGRP	7

/* The various states of a semaphore */
#define SIGNALED	1
#define UNSIGNALED 	0
#define UNUSED		-1

/* The security attribute structure necessary for handles to be inhereted */
SECURITY_ATTRIBUTES sec_attrib = { sizeof (LPSECURITY_ATTRIBUTES),
	NULL, TRUE};

/*
Postgres95 uses semaphores and shared memory. Both are provided by
Unix and NT, although NT uses a different method for referencing
them. Rather than changing the function calls used by Postgres95
to use NT system services, we've written code to emulate the Unix
system calls. We deliberately don't do a complete emulation of the
Unix calls, partly because it doesn't appear possible, but also
because only a few options of the Unix calls are actually used by
Postgres95.

The most noticable difference between the way Unix and NT use semaphores
is that the central entity on Unix is a semaphore set consisting of
potientially many actual semaphores whereas on NT a semaphore handle
represents just one actual semaphore. Furthermore, a Unix semaphore set
is identified by one semaphore id no matter how many elements there
are in the set. Given a Unix semaphore id, the Unix API provides a way
to index into the set to reference a specific semaphore.

You might think that since both a semaphore id and a semaphore handle
is just an integer there won't be any changes necessary to the Postgres95
code to deal with NT semaphores. If it weren't for the existence of
multi-semaphore semaphore sets this would be true.

To handle semaphore sets a fixed-size table, whose size is partially
based on the sum of the maximum number of semaphores times the maximum
number of semaphores per semaphore set, is created and kept in shared
memory that is visable to every backend started by the Postmaster.

Each semaphore set entry consists of an arbitrary key value, which serves
to identify the semaphore set, and IPC_NMAXSEMGRP array elements to
store the NT semaphore handles representing the NT semaphore used for
the semaphore set. Semaphore IDs are just indices into this table.
In order to distinguish occupied entries in this table -1 is always
considered an invalid semaphore ID.

This table is also used to store information about shared memory
segments. Fortunately, there is a one-to-one mapping between Unix
shared memory IDs and NT shared memory handles so the code to emulate
Unix shared memory is simple.
*/

/* We need one of these for each emulated semaphore set */
struct Pg_sem
{
	key_t	Pg_sem_key;
	HANDLE	Pg_sem_handle[IPC_NMAXSEMGRP];
	int	Pg_sem_nsems;
};

/* We need one of these for each emulated shared memory segment */
struct Pg_shm
{
	key_t	Pg_shm_key;
	HANDLE  Pg_shm_handle;
};

/* This structure is what's stored in shared memory. Note that
** since both the shared memory and semaphore data is in the same
** table, and the table is protected by a single NT semaphore, there's
** a chance that semaphore manipulation could be slowed down by
** shared memory manipulation, and vice versa. But, since both are
** allocated primarily when the Postmaster starts up, which isn't time
** critical, I don't think this will prove to be a problem.
*/

static struct Pg_shared
{
	int Pg_next_sem;
	int Pg_next_shm;
	struct Pg_sem Pg_sem[IPC_NMAXSEM];
	struct Pg_shm Pg_shm[IPC_NMAXSHM];
} *Pg_shared_ptr;

/* The semaphore that protects the shared memory table */
HANDLE Pg_shared_hnd;

/*
** Perform a semaphore operation. We're passed a semaphore set id,
** a pointer to an array of sembuf structures, and the number
** of elements in the array. Each element in the sembuf structure
** describes a specific semaphore within the semaphore set and the
** operation to perform on it.
*/

int
semop(int semid, struct sembuf *sops, u_int nsops)
{
	u_int i;
	int result;
	HANDLE hndl;

	/* Go through all the sops structures */
	for (i = 0; i < nsops; i++)
	{
		struct sembuf *sptr;
		int semval;
		int av_sem_op;

		sptr = &sops[i];
		/*
		printf("performing %d in sem # %d\n", sptr->sem_op, sptr->sem_num);
		*/

		/*
		** Postgres95 uses -255 to represent a lock request
		** and 255 to show a lock release. Changing these values
		** to -1 and 1 make it easier to keep track of the state
		** of the semaphore.
		*/
		if (sptr->sem_op == -255)
			sptr->sem_op = -1;
		else if (sptr->sem_op == 255)
			sptr->sem_op = 1;
		else
			printf("invalid sem_op %d\n", sptr->sem_op);

		_get_ipc_sem();
		hndl = Pg_shared_ptr->Pg_sem[semid].Pg_sem_handle[sptr->sem_num];
		_rel_ipc_sem();
		semval = _get_sem_val(hndl);

		if (sptr->sem_op == 0)
		{
			if (semval == UNSIGNALED)
				return(semval);
			else
			{
				if (sptr->sem_flg & IPC_NOWAIT)
					return(SIGNALED);
				else
					result = WaitForSingleObject(hndl, 5000);
			}
		}

		av_sem_op = abs(sptr->sem_op);

		/* If a lock is being attempted */
		if (sptr->sem_op < 0)
		{
			if (semval >= av_sem_op)
			{
				semval -= av_sem_op;
				if (semval <= UNSIGNALED)
					result = WaitForSingleObject(hndl, 5000);
			}
			else
			{
				if (sptr->sem_flg & IPC_NOWAIT)
					return(SIGNALED);
				else
					result = WaitForSingleObject(hndl, 5000);
			}
		}

		/* If a lock is being released */
		if (sptr->sem_op > 0)
		{
			semval += av_sem_op;
			if (semval > 0)
				ReleaseSemaphore(hndl, 1, NULL);
		}
	}
}

int
semget(key_t key, int nsems, int semflg)
{
	int id, new_sem, ret_val;

	/* If nmsems is 0 then assume that we're just checking whether
	** the semaphore identified by key exists. Assume that
	** if key is IPC_PRIVATE that this should always fail.
	*/
	if (nsems == 0)
	{
		if (key == IPC_PRIVATE)
			ret_val = -1;
		else
		{
			_get_ipc_sem();
			id = _get_sem_id(key);
			_rel_ipc_sem();
			ret_val = id;
		}
		return(ret_val);
	}

	/* See if there's already a semaphore with the key.
	** If not, record the key, allocate enough space for the
	** handles of the semaphores, and then create the semaphores.
	*/
	_get_ipc_sem();
	id = _get_sem_id(key);
	if (id == UNUSED)
	{
		register int i;
		struct Pg_sem *pg_ptr;

		new_sem = Pg_shared_ptr->Pg_next_sem++;

		pg_ptr = &(Pg_shared_ptr->Pg_sem[new_sem]);
		pg_ptr->Pg_sem_key = key;
		pg_ptr->Pg_sem_nsems = nsems;

		for (i = 0; i < nsems; i++)
			pg_ptr->Pg_sem_handle[i] = CreateSemaphore(&sec_attrib, 1, 255, NULL);
		ret_val = new_sem;
	}
	else
		ret_val = id;
	_rel_ipc_sem();
	return(ret_val);
}

/* These next two functions could be written as one function, although
** doing so would require some additional logic.
*/

/* Given a semaphore key, return the corresponding id.
** This function assumes that the shared memory table is being
** protected by the shared memory table semaphore.
*/
_get_sem_id(key_t key)
{
	register int i;

	/* Go through the shared memory table looking for a semaphore
	** whose key matches what we're looking for
	*/
	for (i = 0; i < Pg_shared_ptr->Pg_next_sem; i++)
		if (Pg_shared_ptr->Pg_sem[i].Pg_sem_key == key)
			return(i);

	/* Return UNUSED if we didn't find a match */
	return(UNUSED);
}

/* Given a shared memory key, return the corresponding id
** This function assumes that the shared memory table is being
** protected by the shared memory table semaphore.
*/
_get_shm_id(key_t key)
{
	register int i;

	/* Go through the shared memory table looking for a semaphore
	** whose key matches what we're looking for
	*/
	for (i = 0; i < Pg_shared_ptr->Pg_next_shm; i++)
		if (Pg_shared_ptr->Pg_shm[i].Pg_shm_key == key)
			return(i);

	/* Return UNUSED if we didn't find a match */
	return(UNUSED);
}

int
semctl(int semid, int semnum, int cmd, void *y)
{
	int old_val;
	HANDLE hndl;

	switch (cmd)
	{
	case SETALL:
	case SETVAL:
		/* We can't change the value of a semaphore under
		** NT except by releasing it or waiting for it.
		*/
		return(0);

	case GETVAL:
		_get_ipc_sem();
		hndl = Pg_shared_ptr->Pg_sem[semid].Pg_sem_handle[semnum];
		_rel_ipc_sem();
		old_val = _get_sem_val(hndl);
		return(old_val);
	}
}

/* Get the current value of the semaphore whose handle is passed in hnd
** This function does NOT assume that the shared memory table is being
** protected by the shared memory table semaphore.
*/

int
_get_sem_val(HANDLE hnd)
{
	DWORD waitresult;

	/* Try to get the semaphore */
	waitresult = WaitForSingleObject(hnd, 0L);

	/* Check what the value of the semaphore was */
	switch(waitresult)
	{
	/* The semaphore was signaled so we just got it.
	** Since we don't really want to keep it, since we just
	** wanted to test its value, go ahead and release it.
	*/
	case WAIT_OBJECT_0:
		ReleaseSemaphore(hnd, 1, NULL);
		return(SIGNALED);

	/* The semaphore was non-signaled meaning someone else had it. */
	case WAIT_TIMEOUT:
		return(UNSIGNALED);
	}
}

int
shmget(key_t key, uint32 size, int flags)
{
	HANDLE hnd;
	char name[IPC_MAX_SHMEM_NAME];
	int id;

	/* Get the handle for the key, if any. */
	_get_ipc_sem();
	id = _get_shm_id(key);
	_rel_ipc_sem();

	/* If we're really going to create a new mapping */
	if (flags != 0)
	{
		/* if the key is already being used return an error */
		if (id != UNUSED)
			return(-1);

		/* convert the key to a character string */
		sprintf(name, "%d", key);
	
		hnd = CreateFileMapping((HANDLE)0xffffffff,
			&sec_attrib, PAGE_READWRITE,
			0, size, name);
	
		if (hnd == NULL)
			return(-1);
		else
		{
			int new_ipc;
			struct Pg_shm *pg_ptr;

			_get_ipc_sem();
			new_ipc = Pg_shared_ptr->Pg_next_shm++;

			pg_ptr = &(Pg_shared_ptr->Pg_shm[new_ipc]);
			pg_ptr->Pg_shm_key = key;
			pg_ptr->Pg_shm_handle = hnd;
			_rel_ipc_sem();
			return(new_ipc);
		}
	}

	/* flags is 0 so we just want the id for the existing mapping */
	else
		return(id);
}

shmdt(char *shmaddr)
{
	UnmapViewOfFile(shmaddr);
}

int
shmctl(IpcMemoryId shmid, int cmd, struct shmid_ds *buf)
{
	int x = 0;

	if (cmd == IPC_RMID)
	{
		_get_ipc_sem();
		CloseHandle(Pg_shared_ptr->Pg_shm[shmid].Pg_shm_handle);
		_rel_ipc_sem();
		return(0);
	}
	x = x / x;
}

/* Attach to the already created shared memory segment */
LPVOID *
shmat(int shmid, void *shmaddr, int shmflg)
{
	LPVOID *ret_addr;

	_get_ipc_sem();
	ret_addr = MapViewOfFile(Pg_shared_ptr->Pg_shm[shmid].Pg_shm_handle,
		FILE_MAP_ALL_ACCESS, 0, 0, 0);
	_rel_ipc_sem();
	if (ret_addr == NULL)
	{
		int jon;

		jon = GetLastError();
	}
	return(ret_addr);
}

/* This is the function that is called when the postmaster starts up.
** It is here that the shared memory table is created. Also, create
** the semaphore that will be used to protect the shared memory table.
** TODO - do something with the return value.
*/
_nt_init()
{
	HANDLE hnd;
	int size = sizeof (struct Pg_shared);

	/* Create the file mapping for the shared memory to be
	** used to store the ipc table.
	*/
	hnd = CreateFileMapping((HANDLE)0xffffffff,
		&sec_attrib, PAGE_READWRITE,
		0, size, IPC_NAME);

	if (hnd == NULL)
	{
		size = GetLastError();
		return(-1);
	}

	Pg_shared_hnd = CreateSemaphore(&sec_attrib, 1, 255, IPC_SEM_NAME);
	if (Pg_shared_hnd == NULL)
	{
		size = GetLastError();
		return(-1);
	}
}

/* This function gets called by every backend at startup time. Its
** main duty is to put the address of the shared memory table pointed
** to by Pg_shared_ptr. There's no need to get the IPC_SEM_NAME semaphore
** because this function is called before we start manipulating the
** shared memory table.
*/
void
_nt_attach()
{
	HANDLE hnd;

	/* Get a handle to the shared memory table */
	hnd = OpenFileMapping(FILE_MAP_ALL_ACCESS,
		FALSE, IPC_NAME);

	/* Map the ipc shared memory table into the address space
	** of this process at an address returned by MapViewOfFile
	*/
	Pg_shared_ptr = (struct Pg_shared *) MapViewOfFile(hnd,
		FILE_MAP_ALL_ACCESS, 0, 0, 0);

	if (Pg_shared_ptr == NULL)
	{
		hnd = GetLastError();
		return(-1);
	}
}

_get_ipc_sem()
{
	WaitForSingleObject(Pg_shared_hnd, 5000);
}

_rel_ipc_sem()
{
	ReleaseSemaphore(Pg_shared_hnd, 1, NULL);
}

pg_dlerror(void)
{
	int x = 0;
	x = x / x;
}

pg_dlclose(void *handle)
{
	FreeLibrary(handle);
}

void *
pg_dlopen(char *filename)
{
	HINSTANCE hinstlib;

	hinstlib = LoadLibrary(filename);
	return (hinstlib);
}

void *
pg_dlsym(void *handle, char *funcname)
{
	void *proc;

	proc = GetProcAddress(handle, funcname);
	return (proc);
}

void
ftruncate(int fd, int offset)
{
	HANDLE hnd;

	_lseek(fd, offset, SEEK_SET);
	hnd = _get_osfhandle(fd);
	SetEndOfFile(hnd);
}

/* The rest are just stubs that are intended to serve as place holders
** in case we want to set breakpoints to see what's happening when
** these routines are called. They'll eventually have to be filled
** in but they're not necessary to get Postgres95 going.
*/
setuid(int i)
{
	int x = 1;
	x = x / x;
}

setsid()
{
	int x = 1;
	x = x / x;
}

vfork(void)
{
	int x = 0;
	x = x / x;
}

ttyname(int y)
{
	int x = 0;
	x = x / x;
}

step(char *string, char *expbuf)
{
	int x = 0;
	x = x / x;
}

siglongjmp(int env, int value)
{
	int x = 0;
	x = x / x;
}

pause(void)
{
	int x = 0;
	x = x / x;
}

kill(int process, int signal)
{
	int x = 1;
	x = x / x;
}

getuid(void)
{
	int x = 1;
	x = x / x;
}

geteuid( void )
{
	int x = 1;
	x = x / x;
}

int
fsync(int filedes)
{
}

fork(void)
{
	int x = 0;
	x = x / x;
}

char *
compile(char *instring,char *expbuf,char *endbuf,int eof)
{
	int x = 0;
	x = x / x;
}

beginRecipe(char *s)
{
	int x = 0;
	x = x / x;
}