mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-04 00:02:52 -05:00 
			
		
		
		
	Add shared memory and semaphore routines for Win32.
Also update copyright to be ours, with approval from Jan.
This commit is contained in:
		
							parent
							
								
									d670bf378c
								
							
						
					
					
						commit
						1a67e4869c
					
				
							
								
								
									
										239
									
								
								src/backend/port/win32/sem.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								src/backend/port/win32/sem.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,239 @@
 | 
				
			|||||||
 | 
					/*-------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * sem.c
 | 
				
			||||||
 | 
					 *	  Microsoft Windows Win32 Semaphores Emulation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "postgres.h"
 | 
				
			||||||
 | 
					#include "storage/shmem.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
						int			m_numSems;
 | 
				
			||||||
 | 
						off_t		m_semaphoreHandles;	// offset from beginning of header
 | 
				
			||||||
 | 
						off_t		m_semaphoreCounts;	// offset from beginning of header
 | 
				
			||||||
 | 
					} win32_sem_set_hdr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Control of a semaphore pool. The pool is an area in which we stored all
 | 
				
			||||||
 | 
					** the semIds of the pool. The first long is the number of semaphore
 | 
				
			||||||
 | 
					** allocated in the pool followed by semaphore handles
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					semctl(int semId, int semNum, int flag, union semun semun)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						win32_sem_set_hdr* the_set = (win32_sem_set_hdr*)MAKE_PTR(semId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* semNum might be 0 */
 | 
				
			||||||
 | 
						/* semun.array contains the sem initial values */
 | 
				
			||||||
 | 
						int* sem_counts = (int*)((off_t)the_set + the_set->m_semaphoreCounts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Fix the count of all sem of the pool to semun.array */
 | 
				
			||||||
 | 
						if (flag == SETALL)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							int i;
 | 
				
			||||||
 | 
							struct sembuf sops;
 | 
				
			||||||
 | 
							sops.sem_flg = IPC_NOWAIT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (i = 0; i < the_set->m_numSems; ++i) {
 | 
				
			||||||
 | 
								if (semun.array[i] == sem_counts[i])
 | 
				
			||||||
 | 
									continue; /* Nothing to do */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (semun.array[i] < sem_counts[i])
 | 
				
			||||||
 | 
									sops.sem_op = -1;
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									sops.sem_op = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								sops.sem_num = i;
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
								/* Quickly lock/unlock the semaphore (if we can) */
 | 
				
			||||||
 | 
								if (semop(semId, &sops, 1) < 0)
 | 
				
			||||||
 | 
									return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Fix the count of one semaphore to semun.val */
 | 
				
			||||||
 | 
						else if (flag == SETVAL)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (semun.val != sem_counts[semNum]) {
 | 
				
			||||||
 | 
								struct sembuf sops;
 | 
				
			||||||
 | 
								sops.sem_flg = IPC_NOWAIT;
 | 
				
			||||||
 | 
								sops.sem_num = semNum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (semun.val < sem_counts[semNum])
 | 
				
			||||||
 | 
									sops.sem_op = -1;
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									sops.sem_op = 1;
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
								/* Quickly lock/unlock the semaphore (if we can) */
 | 
				
			||||||
 | 
								if (semop(semId, &sops, 1) < 0)
 | 
				
			||||||
 | 
									return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Delete the pool */
 | 
				
			||||||
 | 
						else if (flag == IPC_RMID)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							int i;
 | 
				
			||||||
 | 
							HANDLE* sem_handles = (HANDLE*)((off_t)the_set + the_set->m_semaphoreHandles);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Loop over all semaphore to delete them */
 | 
				
			||||||
 | 
							for (i = 0; i < the_set->m_numSems; ++i)
 | 
				
			||||||
 | 
								CloseHandle(sem_handles[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Get the current semaphore count */
 | 
				
			||||||
 | 
						else if (flag == GETNCNT)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return the_set->m_numSems;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Get the current semaphore count of the first semaphore in the pool */
 | 
				
			||||||
 | 
						else if (flag == GETVAL)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return sem_counts[semNum];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Other commands not yet supported */
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							errno = EINVAL;
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Find a pool id based on IPC key */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					semget(int semKey, int semNum, int flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char semname[32];
 | 
				
			||||||
 | 
						char cur_num[20];
 | 
				
			||||||
 | 
						DWORD last_error;
 | 
				
			||||||
 | 
						char* num_part;
 | 
				
			||||||
 | 
						bool ans = true;
 | 
				
			||||||
 | 
						SECURITY_ATTRIBUTES sec_attrs;
 | 
				
			||||||
 | 
						HANDLE cur_handle;
 | 
				
			||||||
 | 
						bool found = false;
 | 
				
			||||||
 | 
						Size sem_set_size = sizeof(win32_sem_set_hdr) + semNum * (sizeof(HANDLE) + sizeof(int));
 | 
				
			||||||
 | 
						HANDLE* sem_handles = NULL;
 | 
				
			||||||
 | 
						int* sem_counts = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sec_attrs.nLength = sizeof(sec_attrs);
 | 
				
			||||||
 | 
						sec_attrs.lpSecurityDescriptor = NULL;
 | 
				
			||||||
 | 
						sec_attrs.bInheritHandle = TRUE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sprintf(semname, "PG_SEMSET.%d.", semKey);
 | 
				
			||||||
 | 
						num_part = semname + strlen(semname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strcpy(num_part, _itoa(_getpid() * -1, cur_num, 10));	/* For shared memory, include the pid */
 | 
				
			||||||
 | 
						win32_sem_set_hdr* new_set = (win32_sem_set_hdr*)ShmemInitStruct(semname, sem_set_size, &found);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (found) {
 | 
				
			||||||
 | 
							/* This should *never* happen */
 | 
				
			||||||
 | 
							errno = EEXIST;
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						new_set->m_numSems = semNum;
 | 
				
			||||||
 | 
						new_set->m_semaphoreHandles = sizeof(win32_sem_set_hdr);	// array starts after header
 | 
				
			||||||
 | 
						new_set->m_semaphoreCounts = new_set->m_semaphoreHandles + (sizeof(HANDLE) * semNum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sem_handles = (HANDLE*)((off_t)new_set + new_set->m_semaphoreHandles);
 | 
				
			||||||
 | 
						sem_counts = (int*)((off_t)new_set + new_set->m_semaphoreCounts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int i=0; i<semNum && ans; ++i) {
 | 
				
			||||||
 | 
							strcpy(num_part, _itoa(i, cur_num, 10));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (flags & IPC_CREAT)
 | 
				
			||||||
 | 
								cur_handle = CreateSemaphore(&sec_attrs, 0, 1, semname);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								cur_handle = OpenSemaphore(SEMAPHORE_ALL_ACCESS, TRUE, semname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sem_handles[i] = cur_handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							last_error = GetLastError();
 | 
				
			||||||
 | 
							if (!cur_handle)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								errno = EACCES;
 | 
				
			||||||
 | 
								ans = false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else if (last_error == ERROR_ALREADY_EXISTS && (flags & (IPC_CREAT | IPC_EXCL)))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								errno = EEXIST;
 | 
				
			||||||
 | 
								ans = false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ans) {
 | 
				
			||||||
 | 
							return MAKE_OFFSET(new_set);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							// Blow away what we've got right now...
 | 
				
			||||||
 | 
							for (int i=0; i<semNum; ++i) {
 | 
				
			||||||
 | 
								if (sem_handles[i])
 | 
				
			||||||
 | 
									CloseHandle(sem_handles[i]);
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Acquire or release in the semaphore pool */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					semop(int semId, struct sembuf * sops, int nsops)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						win32_sem_set_hdr* the_set = (win32_sem_set_hdr*)MAKE_PTR(semId);
 | 
				
			||||||
 | 
						HANDLE* sem_handles = (HANDLE*)((off_t)the_set + the_set->m_semaphoreHandles);
 | 
				
			||||||
 | 
						int* sem_counts = (int*)((off_t)the_set + the_set->m_semaphoreCounts);
 | 
				
			||||||
 | 
						HANDLE cur_handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (nsops != 1) {
 | 
				
			||||||
 | 
							/* Not supported (we return on 1st success, and don't cancel earlier ops) */
 | 
				
			||||||
 | 
							errno = E2BIG;
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cur_handle = sem_handles[sops[0].sem_num];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sops[0].sem_op == -1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							DWORD ret;
 | 
				
			||||||
 | 
							if (sops[0].sem_flg & IPC_NOWAIT)
 | 
				
			||||||
 | 
								ret = WaitForSingleObject(cur_handle, 0);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								ret = WaitForSingleObject(cur_handle, INFINITE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ret == WAIT_OBJECT_0) {
 | 
				
			||||||
 | 
								/* We got it! */
 | 
				
			||||||
 | 
								sem_counts[sops[0].sem_num]--;
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							} else if (ret == WAIT_TIMEOUT)
 | 
				
			||||||
 | 
								/* Couldn't get it */
 | 
				
			||||||
 | 
								errno = EAGAIN;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								errno = EIDRM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if (sops[0].sem_op > 0) {
 | 
				
			||||||
 | 
							/* Don't want the lock anymore */
 | 
				
			||||||
 | 
							sem_counts[sops[0].sem_num]++;
 | 
				
			||||||
 | 
							ReleaseSemaphore(cur_handle, sops[0].sem_op, NULL);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							/* Not supported */
 | 
				
			||||||
 | 
							errno = ERANGE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* If we get down here, then something is wrong */
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										120
									
								
								src/backend/port/win32/shm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								src/backend/port/win32/shm.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,120 @@
 | 
				
			|||||||
 | 
					/*-------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * shm.c
 | 
				
			||||||
 | 
					 *	  Microsoft Windows Win32 Shared Memory Emulation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "postgres.h"
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static DWORD s_segsize = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Detach from a shared mem area based on its address */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					shmdt(const void *shmaddr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (UnmapViewOfFile(shmaddr))
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Attach to an existing area */
 | 
				
			||||||
 | 
					void *
 | 
				
			||||||
 | 
					shmat(int memId, void* shmaddr, int flag)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* KEW_TODO -- shmat needs to count # attached to shared mem */
 | 
				
			||||||
 | 
						void *lpmem = MapViewOfFileEx((HANDLE)memId,
 | 
				
			||||||
 | 
								  FILE_MAP_WRITE | FILE_MAP_READ,
 | 
				
			||||||
 | 
								  0, 0, /* (DWORD)pshmdsc->segsize */ s_segsize, shmaddr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (lpmem == NULL) {
 | 
				
			||||||
 | 
							lpmem = (void *)-1;
 | 
				
			||||||
 | 
							errno = GetLastError();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return lpmem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Control a shared mem area */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					shmctl(int shmid, int flag, struct shmid_ds * dummy)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (flag == IPC_RMID)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							/* Delete the area */
 | 
				
			||||||
 | 
							CloseHandle((HANDLE)shmid);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (flag == IPC_STAT)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							/* Can only test for if exists */
 | 
				
			||||||
 | 
							int hmap = shmget(shmid, 0, 0);
 | 
				
			||||||
 | 
							if (hmap < 0) {
 | 
				
			||||||
 | 
								/* Shared memory does not exist */
 | 
				
			||||||
 | 
								errno = EINVAL;
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								/* Shared memory does exist and must be in use */
 | 
				
			||||||
 | 
								shmctl(hmap, IPC_RMID, NULL);	/* Release our hold on it */
 | 
				
			||||||
 | 
								errno = 0;
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						errno = EINVAL;
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Get an area based on the IPC key */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					shmget(int memKey, int size, int flag)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    HANDLE  hmap;
 | 
				
			||||||
 | 
						char szShareMem[32];
 | 
				
			||||||
 | 
						DWORD dwRet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s_segsize = size;
 | 
				
			||||||
 | 
					    sprintf(szShareMem, "sharemem.%d", memKey);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (flag & IPC_CREAT) {
 | 
				
			||||||
 | 
							hmap = CreateFileMapping((HANDLE)0xFFFFFFFF,  /* Use the swap file    */
 | 
				
			||||||
 | 
										 NULL,
 | 
				
			||||||
 | 
										 PAGE_READWRITE,      /* Memory is Read/Write */
 | 
				
			||||||
 | 
										 0L,                  /* Size Upper 32 Bits   */
 | 
				
			||||||
 | 
										 (DWORD)s_segsize,      /* Size Lower 32 bits*/
 | 
				
			||||||
 | 
										 szShareMem);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
							hmap = OpenFileMapping(FILE_MAP_ALL_ACCESS,
 | 
				
			||||||
 | 
													FALSE,
 | 
				
			||||||
 | 
													szShareMem);
 | 
				
			||||||
 | 
							if (!hmap) {
 | 
				
			||||||
 | 
								errno = ENOENT;
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dwRet = GetLastError();
 | 
				
			||||||
 | 
						if (dwRet == ERROR_ALREADY_EXISTS && hmap && (flag & (IPC_CREAT | IPC_EXCL))) {
 | 
				
			||||||
 | 
							/* Caller wanted to create the segment -- error if already exists */
 | 
				
			||||||
 | 
							CloseHandle(hmap);
 | 
				
			||||||
 | 
							errno = EEXIST;
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if (!hmap)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							/* Unable to get shared memory */
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (int)hmap;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user