⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 proc.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * proc.c *	  routines to manage per-process shared memory data structure * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.57 1999/05/25 22:42:03 momjian Exp $ * *------------------------------------------------------------------------- *//* *	Each postgres backend gets one of these.  We'll use it to *	clean up after the process should the process suddenly die. * * * Interface (a): *		ProcSleep(), ProcWakeup(), ProcWakeupNext(), *		ProcQueueAlloc() -- create a shm queue for sleeping processes *		ProcQueueInit() -- create a queue without allocing memory * * Locking and waiting for buffers can cause the backend to be * put to sleep.  Whoever releases the lock, etc. wakes the * process up again (and gives it an error code so it knows * whether it was awoken on an error condition). * * Interface (b): * * ProcReleaseLocks -- frees the locks associated with this process, * ProcKill -- destroys the shared memory state (and locks) *		associated with the process. * * 5/15/91 -- removed the buffer pool based lock chain in favor *		of a shared memory lock chain.	The write-protection is *		more expensive if the lock chain is in the buffer pool. *		The only reason I kept the lock chain in the buffer pool *		in the first place was to allow the lock table to grow larger *		than available shared memory and that isn't going to work *		without a lot of unimplemented support anyway. * * 4/7/95 -- instead of allocating a set of 1 semaphore per process, we *		allocate a semaphore from a set of PROC_NSEMS_PER_SET semaphores *		shared among backends (we keep a few sets of semaphores around). *		This is so that we can support more backends. (system-wide semaphore *		sets run out pretty fast.)				  -ay 4/95 * * $Header: /usr/local/cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.57 1999/05/25 22:42:03 momjian Exp $ */#include <sys/time.h>#include <unistd.h>#include <string.h>#include <signal.h>#include <sys/types.h>#if defined(solaris_sparc)#include <sys/ipc.h>#include <sys/sem.h>#endif#include "postgres.h"#include "miscadmin.h"#include "libpq/pqsignal.h"#include "access/xact.h"#include "utils/hsearch.h"#include "storage/ipc.h"/* In Ultrix, sem.h must be included after ipc.h */#include <sys/sem.h>#include "storage/buf.h"#include "storage/lock.h"#include "storage/lmgr.h"#include "storage/shmem.h"#include "storage/spin.h"#include "storage/proc.h"#include "utils/trace.h"static void HandleDeadLock(int sig);static void ProcFreeAllSemaphores(void);#define DeadlockCheckTimer pg_options[OPT_DEADLOCKTIMEOUT]/* -------------------- * Spin lock for manipulating the shared process data structure: * ProcGlobal.... Adding an extra spin lock seemed like the smallest * hack to get around reading and updating this structure in shared * memory. -mer 17 July 1991 * -------------------- */SPINLOCK	ProcStructLock;/* * For cleanup routines.  Don't cleanup if the initialization * has not happened. */static bool ProcInitialized = FALSE;static PROC_HDR *ProcGlobal = NULL;PROC	   *MyProc = NULL;static void ProcKill(int exitStatus, int pid);static void ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum);static void ProcFreeSem(IpcSemaphoreKey semKey, int semNum);static char *DeadLockMessage = "Deadlock detected -- See the lock(l) manual page for a possible cause.";/* * InitProcGlobal - *	  initializes the global process table. We put it here so that *	  the postmaster can do this initialization. (ProcFreeAllSemaphores needs *	  to read this table on exiting the postmaster. If we have the first *	  backend do this, starting up and killing the postmaster without *	  starting any backends will be a problem.) * *	  We also allocate all the per-process semaphores we will need to support *	  the requested number of backends.  We used to allocate semaphores *	  only when backends were actually started up, but that is bad because *	  it lets Postgres fail under load --- a lot of Unix systems are *	  (mis)configured with small limits on the number of semaphores, and *	  running out when trying to start another backend is a common failure. *	  So, now we grab enough semaphores to support the desired max number *	  of backends immediately at initialization --- if the sysadmin has set *	  MaxBackends higher than his kernel will support, he'll find out sooner *	  rather than later. */voidInitProcGlobal(IPCKey key, int maxBackends){	bool		found = false;	/* attach to the free list */	ProcGlobal = (PROC_HDR *)		ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);	/* --------------------	 * We're the first - initialize.	 * XXX if found should ever be true, it is a sign of impending doom ...	 * ought to complain if so?	 * --------------------	 */	if (!found)	{		int			i;		ProcGlobal->freeProcs = INVALID_OFFSET;		ProcGlobal->currKey = IPCGetProcessSemaphoreInitKey(key);		for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)			ProcGlobal->freeSemMap[i] = 0;		/*		 * Arrange to delete semas on exit --- set this up now so that we		 * will clean up if pre-allocation fails...		 */		on_shmem_exit(ProcFreeAllSemaphores, NULL);		/*		 * Pre-create the semaphores for the first maxBackends processes,		 * unless we are running as a standalone backend.		 */		if (key != PrivateIPCKey)		{			for (i = 0;				 i < (maxBackends + PROC_NSEMS_PER_SET - 1) / PROC_NSEMS_PER_SET;				 i++)			{				IPCKey		semKey = ProcGlobal->currKey + i;				int			semId;				int			semstat;				semId = IpcSemaphoreCreate(semKey,										   PROC_NSEMS_PER_SET,										   IPCProtection,										   IpcSemaphoreDefaultStartValue,										   0,										   &semstat);				/* mark this sema set allocated */				ProcGlobal->freeSemMap[i] = (1 << PROC_NSEMS_PER_SET);			}		}	}}/* ------------------------ * InitProc -- create a per-process data structure for this process * used by the lock manager on semaphore queues. * ------------------------ */voidInitProcess(IPCKey key){	bool		found = false;	int			semstat;	unsigned long location,				myOffset;	/* ------------------	 * Routine called if deadlock timer goes off. See ProcSleep()	 * ------------------	 */	pqsignal(SIGALRM, HandleDeadLock);	SpinAcquire(ProcStructLock);	/* attach to the free list */	ProcGlobal = (PROC_HDR *)		ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);	if (!found)	{		/* this should not happen. InitProcGlobal() is called before this. */		elog(ERROR, "InitProcess: Proc Header uninitialized");	}	if (MyProc != NULL)	{		SpinRelease(ProcStructLock);		elog(ERROR, "ProcInit: you already exist");		return;	}	/* try to get a proc from the free list first */	myOffset = ProcGlobal->freeProcs;	if (myOffset != INVALID_OFFSET)	{		MyProc = (PROC *) MAKE_PTR(myOffset);		ProcGlobal->freeProcs = MyProc->links.next;	}	else	{		/*		 * have to allocate one.  We can't use the normal shmem index		 * table mechanism because the proc structure is stored by PID		 * instead of by a global name (need to look it up by PID when we		 * cleanup dead processes).		 */		MyProc = (PROC *) ShmemAlloc((unsigned) sizeof(PROC));		if (!MyProc)		{			SpinRelease(ProcStructLock);			elog(FATAL, "cannot create new proc: out of memory");		}		/* this cannot be initialized until after the buffer pool */		SHMQueueInit(&(MyProc->lockQueue));	}	/*	 * zero out the spin lock counts and set the sLocks field for	 * ProcStructLock to 1 as we have acquired this spinlock above but	 * didn't record it since we didn't have MyProc until now.	 */	MemSet(MyProc->sLocks, 0, sizeof(MyProc->sLocks));	MyProc->sLocks[ProcStructLock] = 1;	if (IsUnderPostmaster)	{		IPCKey		semKey;		int			semNum;		int			semId;		union semun semun;		ProcGetNewSemKeyAndNum(&semKey, &semNum);		/*		 * Note: because of the pre-allocation done in InitProcGlobal,		 * this call should always attach to an existing semaphore. It		 * will (try to) create a new group of semaphores only if the		 * postmaster tries to start more backends than it said it would.		 */		semId = IpcSemaphoreCreate(semKey,								   PROC_NSEMS_PER_SET,								   IPCProtection,								   IpcSemaphoreDefaultStartValue,								   0,								   &semstat);		/*		 * we might be reusing a semaphore that belongs to a dead backend.		 * So be careful and reinitialize its value here.		 */		semun.val = IpcSemaphoreDefaultStartValue;		semctl(semId, semNum, SETVAL, semun);		IpcSemaphoreLock(semId, semNum, IpcExclusiveLock);		MyProc->sem.semId = semId;		MyProc->sem.semNum = semNum;		MyProc->sem.semKey = semKey;	}	else		MyProc->sem.semId = -1;	/* ----------------------	 * Release the lock.	 * ----------------------	 */	SpinRelease(ProcStructLock);	MyProc->pid = MyProcPid;	MyProc->xid = InvalidTransactionId;	MyProc->xmin = InvalidTransactionId;	/* ----------------	 * Start keeping spin lock stats from here on.	Any botch before	 * this initialization is forever botched	 * ----------------	 */	MemSet(MyProc->sLocks, 0, MAX_SPINS * sizeof(*MyProc->sLocks));	/* -------------------------	 * Install ourselves in the shmem index table.	The name to	 * use is determined by the OS-assigned process id.  That	 * allows the cleanup process to find us after any untimely	 * exit.	 * -------------------------	 */	location = MAKE_OFFSET(MyProc);	if ((!ShmemPIDLookup(MyProcPid, &location)) || (location != MAKE_OFFSET(MyProc)))		elog(FATAL, "InitProc: ShmemPID table broken");	MyProc->errType = NO_ERROR;	SHMQueueElemInit(&(MyProc->links));	on_shmem_exit(ProcKill, (caddr_t) MyProcPid);	ProcInitialized = TRUE;}/* * ProcReleaseLocks() -- release all locks associated with this process * */voidProcReleaseLocks(){	if (!MyProc)		return;	LockReleaseAll(1, &MyProc->lockQueue);}/* * ProcRemove - *	  used by the postmaster to clean up the global tables. This also frees *	  up the semaphore used for the lmgr of the process. (We have to do *	  this is the postmaster instead of doing a IpcSemaphoreKill on exiting *	  the process because the semaphore set is shared among backends and *	  we don't want to remove other's semaphores on exit.) */boolProcRemove(int pid){	SHMEM_OFFSET location;	PROC	   *proc;	location = INVALID_OFFSET;	location = ShmemPIDDestroy(pid);	if (location == INVALID_OFFSET)		return FALSE;	proc = (PROC *) MAKE_PTR(location);	SpinAcquire(ProcStructLock);	ProcFreeSem(proc->sem.semKey, proc->sem.semNum);	proc->links.next = ProcGlobal->freeProcs;	ProcGlobal->freeProcs = MAKE_OFFSET(proc);	SpinRelease(ProcStructLock);	return TRUE;}/* * ProcKill() -- Destroy the per-proc data structure for *		this process. Release any of its held spin locks. */static voidProcKill(int exitStatus, int pid){	PROC	   *proc;	SHMEM_OFFSET location;	/* --------------------	 * If this is a FATAL exit the postmaster will have to kill all the	 * existing backends and reinitialize shared memory.  So all we don't	 * need to do anything here.	 * --------------------	 */	if (exitStatus != 0)		return;	ShmemPIDLookup(MyProcPid, &location);	if (location == INVALID_OFFSET)		return;	proc = (PROC *) MAKE_PTR(location);	Assert(proc == MyProc || pid != MyProcPid);	MyProc = NULL;	/* ---------------	 * Assume one lock table.	 * ---------------	 */	ProcReleaseSpins(proc);	LockReleaseAll(DEFAULT_LOCKMETHOD, &proc->lockQueue);#ifdef USER_LOCKS	/*	 * Assume we have a second lock table.	 */	LockReleaseAll(USER_LOCKMETHOD, &proc->lockQueue);#endif	/* ----------------	 * get off the wait queue	 * ----------------	 */	LockLockTable();	if (proc->links.next != INVALID_OFFSET)	{		Assert(proc->waitLock->waitProcs.size > 0);		SHMQueueDelete(&(proc->links));		--proc->waitLock->waitProcs.size;	}	SHMQueueElemInit(&(proc->links));	UnlockLockTable();	return;}/* * ProcQueue package: routines for putting processes to sleep *		and  waking them up *//* * ProcQueueAlloc -- alloc/attach to a shared memory process queue * * Returns: a pointer to the queue or NULL * Side Effects: Initializes the queue if we allocated one */#ifdef NOT_USEDPROC_QUEUE *ProcQueueAlloc(char *name){	bool		found;	PROC_QUEUE *queue = (PROC_QUEUE *)	ShmemInitStruct(name, (unsigned) sizeof(PROC_QUEUE), &found);	if (!queue)		return NULL;	if (!found)		ProcQueueInit(queue);	return queue;}#endif/* * ProcQueueInit -- initialize a shared memory process queue */voidProcQueueInit(PROC_QUEUE *queue){	SHMQueueInit(&(queue->links));	queue->size = 0;}/* * ProcSleep -- put a process to sleep * * P() on the semaphore should put us to sleep.  The process * semaphore is cleared by default, so the first time we try

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -