📄 ipc.c
字号:
/*------------------------------------------------------------------------- * * ipc.c * POSTGRES inter-process communication definitions. * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /usr/local/cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.37 1999/05/25 16:11:07 momjian Exp $ * * NOTES * * Currently, semaphores are used (my understanding anyway) in two * different ways: * 1. as mutexes on machines that don't have test-and-set (eg. * mips R3000). * 2. for putting processes to sleep when waiting on a lock * and waking them up when the lock is free. * The number of semaphores in (1) is fixed and those are shared * among all backends. In (2), there is 1 semaphore per process and those * are not shared with anyone else. * -ay 4/95 * *------------------------------------------------------------------------- */#include <sys/types.h>#include <sys/file.h>#include <stdio.h>#include <string.h>#include <errno.h>#include "postgres.h"#include "storage/ipc.h"#include "storage/s_lock.h"/* In Ultrix, sem.h and shm.h must be included AFTER ipc.h */#include <sys/sem.h>#include <sys/shm.h>#include "utils/memutils.h"#include "libpq/libpq.h"#include "utils/trace.h"#if defined(solaris_sparc)#include <string.h>#include <sys/ipc.h>#endifstatic int UsePrivateMemory = 0;static void IpcMemoryDetach(int status, char *shmaddr);/* ---------------------------------------------------------------- * exit() handling stuff * ---------------------------------------------------------------- */#define MAX_ON_EXITS 20static struct ONEXIT{ void (*function) (); caddr_t arg;} on_proc_exit_list[MAX_ON_EXITS], on_shmem_exit_list[MAX_ON_EXITS];static int on_proc_exit_index, on_shmem_exit_index;typedef struct _PrivateMemStruct{ int id; char *memptr;} PrivateMem;PrivateMem IpcPrivateMem[16];static intPrivateMemoryCreate(IpcMemoryKey memKey, uint32 size){ static int memid = 0; UsePrivateMemory = 1; IpcPrivateMem[memid].id = memid; IpcPrivateMem[memid].memptr = malloc(size); if (IpcPrivateMem[memid].memptr == NULL) elog(ERROR, "PrivateMemoryCreate: not enough memory to malloc"); MemSet(IpcPrivateMem[memid].memptr, 0, size); /* XXX PURIFY */ return memid++;}static char *PrivateMemoryAttach(IpcMemoryId memid){ return IpcPrivateMem[memid].memptr;}/* ---------------------------------------------------------------- * proc_exit * * this function calls all the callbacks registered * for it (to free resources) and then calls exit. * This should be the only function to call exit(). * -cim 2/6/90 * ---------------------------------------------------------------- */static int proc_exit_inprogress = 0;voidproc_exit(int code){ int i; TPRINTF(TRACE_VERBOSE, "proc_exit(%d) [#%d]", code, proc_exit_inprogress); /* * If proc_exit is called too many times something bad is happenig, so * exit immediately. */ if (proc_exit_inprogress > 9) { elog(ERROR, "infinite recursion in proc_exit"); goto exit; } /* ---------------- * if proc_exit_inprocess is true, then it means that we * are being invoked from within an on_exit() handler * and so we return immediately to avoid recursion. * ---------------- */ if (proc_exit_inprogress++) return; /* do our shared memory exits first */ shmem_exit(code); /* ---------------- * call all the callbacks registered before calling exit(). * ---------------- */ for (i = on_proc_exit_index - 1; i >= 0; --i) (*on_proc_exit_list[i].function) (code, on_proc_exit_list[i].arg);exit: TPRINTF(TRACE_VERBOSE, "exit(%d)", code); exit(code);}/* ------------------ * Run all of the on_shmem_exit routines but don't exit in the end. * This is used by the postmaster to re-initialize shared memory and * semaphores after a backend dies horribly * ------------------ */static int shmem_exit_inprogress = 0;voidshmem_exit(int code){ int i; TPRINTF(TRACE_VERBOSE, "shmem_exit(%d) [#%d]", code, shmem_exit_inprogress); /* * If shmem_exit is called too many times something bad is happenig, * so exit immediately. */ if (shmem_exit_inprogress > 9) { elog(ERROR, "infinite recursion in shmem_exit"); exit(-1); } /* ---------------- * if shmem_exit_inprocess is true, then it means that we * are being invoked from within an on_exit() handler * and so we return immediately to avoid recursion. * ---------------- */ if (shmem_exit_inprogress++) return; /* ---------------- * call all the callbacks registered before calling exit(). * ---------------- */ for (i = on_shmem_exit_index - 1; i >= 0; --i) (*on_shmem_exit_list[i].function) (code, on_shmem_exit_list[i].arg); on_shmem_exit_index = 0; shmem_exit_inprogress = 0;}/* ---------------------------------------------------------------- * on_proc_exit * * this function adds a callback function to the list of * functions invoked by proc_exit(). -cim 2/6/90 * ---------------------------------------------------------------- */int on_proc_exit(void (*function) (), caddr_t arg){ if (on_proc_exit_index >= MAX_ON_EXITS) return -1; on_proc_exit_list[on_proc_exit_index].function = function; on_proc_exit_list[on_proc_exit_index].arg = arg; ++on_proc_exit_index; return 0;}/* ---------------------------------------------------------------- * on_shmem_exit * * this function adds a callback function to the list of * functions invoked by shmem_exit(). -cim 2/6/90 * ---------------------------------------------------------------- */int on_shmem_exit(void (*function) (), caddr_t arg){ if (on_shmem_exit_index >= MAX_ON_EXITS) return -1; on_shmem_exit_list[on_shmem_exit_index].function = function; on_shmem_exit_list[on_shmem_exit_index].arg = arg; ++on_shmem_exit_index; return 0;}/* ---------------------------------------------------------------- * on_exit_reset * * this function clears all proc_exit() registered functions. * ---------------------------------------------------------------- */voidon_exit_reset(void){ on_shmem_exit_index = 0; on_proc_exit_index = 0;}/****************************************************************************//* IPCPrivateSemaphoreKill(status, semId) *//* *//****************************************************************************/static voidIPCPrivateSemaphoreKill(int status, int semId) /* caddr_t */{ union semun semun; semctl(semId, 0, IPC_RMID, semun);}/****************************************************************************//* IPCPrivateMemoryKill(status, shmId) *//* *//****************************************************************************/static voidIPCPrivateMemoryKill(int status, int shmId) /* caddr_t */{ if (UsePrivateMemory) { /* free ( IpcPrivateMem[shmId].memptr ); */ } else { if (shmctl(shmId, IPC_RMID, (struct shmid_ds *) NULL) < 0) { elog(NOTICE, "IPCPrivateMemoryKill: shmctl(%d, %d, 0) failed: %m", shmId, IPC_RMID); } }}/****************************************************************************//* IpcSemaphoreCreate(semKey, semNum, permission, semStartValue) *//* *//* - returns a semaphore identifier: *//* *//* if key doesn't exist: return a new id, status:= IpcSemIdNotExist *//* if key exists: return the old id, status:= IpcSemIdExist *//* if semNum > MAX : return # of argument, status:=IpcInvalidArgument *//* *//****************************************************************************//* * Note: * XXX This should be split into two different calls. One should * XXX be used to create a semaphore set. The other to "attach" a * XXX existing set. It should be an error for the semaphore set * XXX to to already exist or for it not to, respectively. * * Currently, the semaphore sets are "attached" and an error * is detected only when a later shared memory attach fails. */IpcSemaphoreIdIpcSemaphoreCreate(IpcSemaphoreKey semKey, int semNum, int permission, int semStartValue, int removeOnExit, int *status){ int i; int errStatus; int semId; u_short array[IPC_NMAXSEM]; union semun semun; /* get a semaphore if non-existent */ /* check arguments */ if (semNum > IPC_NMAXSEM || semNum <= 0) { *status = IpcInvalidArgument; return 2; /* returns the number of the invalid * argument */ } semId = semget(semKey, 0, 0); if (semId == -1) { *status = IpcSemIdNotExist; /* there doesn't exist a semaphore */#ifdef DEBUG_IPC EPRINTF("calling semget with %d, %d , %d\n", semKey, semNum, IPC_CREAT | permission);#endif semId = semget(semKey, semNum, IPC_CREAT | permission); if (semId < 0) { EPRINTF("IpcSemaphoreCreate: semget failed (%s) " "key=%d, num=%d, permission=%o", strerror(errno), semKey, semNum, permission); proc_exit(3); } for (i = 0; i < semNum; i++) array[i] = semStartValue; semun.array = array; errStatus = semctl(semId, 0, SETALL, semun); if (errStatus == -1) { EPRINTF("IpcSemaphoreCreate: semctl failed (%s) id=%d", strerror(errno), semId); } if (removeOnExit) on_shmem_exit(IPCPrivateSemaphoreKill, (caddr_t) semId); } else { /* there is a semaphore id for this key */ *status = IpcSemIdExist; }#ifdef DEBUG_IPC
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -