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

📄 postmaster.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 3 页
字号:
		fprintf(stderr, "%s: cannot create UNIX stream port\n",				progname);		exit(1);	}#endif	/* set up shared memory and semaphores */	EnableMemoryContext(TRUE);	reset_shared(PostPortName);	/*	 * Initialize the list of active backends.	This list is only used for	 * garbage collecting the backend processes.	 */	BackendList = DLNewList();	PortList = DLNewList();	if (silentflag)		pmdaemonize();	/*	 * Set up signal handlers for the postmaster process.	 */	pqsignal(SIGHUP, pmdie);	/* send SIGHUP, don't die */	pqsignal(SIGINT, pmdie);	/* die */	pqsignal(SIGQUIT, pmdie);	/* send SIGTERM and die */	pqsignal(SIGTERM, pmdie);	/* send SIGTERM,SIGKILL and die */	pqsignal(SIGPIPE, SIG_IGN); /* ignored */	pqsignal(SIGUSR1, pmdie);	/* send SIGUSR1 and die */	pqsignal(SIGUSR2, pmdie);	/* send SIGUSR2, don't die */	pqsignal(SIGCHLD, reaper);	/* handle child termination */	pqsignal(SIGTTIN, SIG_IGN); /* ignored */	pqsignal(SIGTTOU, SIG_IGN); /* ignored */	pqsignal(SIGWINCH, dumpstatus);		/* dump port status */	status = ServerLoop();	ExitPostmaster(status != STATUS_OK);	return 0;					/* not reached */}static voidpmdaemonize(void){	int			i;	if (fork())		_exit(0);/* GH: If there's no setsid(), we hopefully don't need silent mode. * Until there's a better solution. */#ifdef HAVE_SETSID	if (setsid() < 0)	{		fprintf(stderr, "%s: ", progname);		perror("cannot disassociate from controlling TTY");		exit(1);	}#endif#ifndef __CYGWIN32__	i = open(NULL_DEV, O_RDWR);#else	i = open(NULL_DEV, O_RDWR | O_BINARY);#endif	dup2(i, 0);	dup2(i, 1);	dup2(i, 2);	close(i);}static voidusage(const char *progname){	fprintf(stderr, "usage: %s [options]\n", progname);#ifdef USE_ASSERT_CHECKING	fprintf(stderr, "\t-A [1|0]\tenable/disable runtime assert checking\n");#endif	fprintf(stderr, "\t-B nbufs\tset number of shared buffers\n");	fprintf(stderr, "\t-D datadir\tset data directory\n");	fprintf(stderr, "\t-S \t\tsilent mode (disassociate from tty)\n");	fprintf(stderr, "\t-a system\tuse this authentication system\n");	fprintf(stderr, "\t-b backend\tuse a specific backend server executable\n");	fprintf(stderr, "\t-d [1|2|3]\tset debugging level\n");	fprintf(stderr, "\t-i \t\tlisten on TCP/IP sockets as well as Unix domain socket\n");	fprintf(stderr, "\t-N nprocs\tset max number of backends (1..%d, default %d)\n",			MAXBACKENDS, DEF_MAXBACKENDS);	fprintf(stderr, "\t-n \t\tdon't reinitialize shared memory after abnormal exit\n");	fprintf(stderr, "\t-o option\tpass 'option' to each backend servers\n");	fprintf(stderr, "\t-p port\tspecify port for postmaster to listen on\n");	fprintf(stderr, "\t-s \t\tsend SIGSTOP to all backend servers if one dies\n");	exit(1);}static intServerLoop(void){	fd_set		readmask,				writemask;	int			nSockets;	Dlelem	   *curr;	struct timeval now,				later;	struct timezone tz;	gettimeofday(&now, &tz);	nSockets = initMasks(&readmask, &writemask);#ifdef HAVE_SIGPROCMASK	sigprocmask(0, NULL, &oldsigmask);	sigemptyset(&newsigmask);	sigaddset(&newsigmask, SIGCHLD);#endif	for (;;)	{		Port	   *port;		fd_set		rmask,					wmask;#ifdef HAVE_SIGPROCMASK		sigprocmask(SIG_SETMASK, &oldsigmask, 0);#else		sigsetmask(orgsigmask);#endif		memmove((char *) &rmask, (char *) &readmask, sizeof(fd_set));		memmove((char *) &wmask, (char *) &writemask, sizeof(fd_set));		if (select(nSockets, &rmask, &wmask, (fd_set *) NULL,				   (struct timeval *) NULL) < 0)		{			if (errno == EINTR)				continue;			fprintf(stderr, "%s: ServerLoop: select failed: %s\n",					progname, strerror(errno));			return STATUS_ERROR;		}		/*		 * Select a random seed at the time of first receiving a request.		 */		while (random_seed == 0)		{			gettimeofday(&later, &tz);			/*			 * We are not sure how much precision is in tv_usec, so we			 * swap the nibbles of 'later' and XOR them with 'now'. On the			 * off chance that the result is 0, we loop until it isn't.			 */			random_seed = now.tv_usec ^				((later.tv_usec << 16) |				 ((later.tv_usec >> 16) & 0xffff));		}		/*		 * [TRH] To avoid race conditions, block SIGCHLD signals while we		 * are handling the request. (both reaper() and ConnCreate()		 * manipulate the BackEnd list, and reaper() calls free() which is		 * usually non-reentrant.)		 */#ifdef HAVE_SIGPROCMASK		sigprocmask(SIG_BLOCK, &newsigmask, &oldsigmask);#else		sigblock(sigmask(SIGCHLD));		/* XXX[TRH] portability */#endif		/* new connection pending on our well-known port's socket */#ifndef __CYGWIN32__		if (ServerSock_UNIX != INVALID_SOCK &&			FD_ISSET(ServerSock_UNIX, &rmask) &&			(port = ConnCreate(ServerSock_UNIX)) != NULL)			PacketReceiveSetup(&port->pktInfo,							   readStartupPacket,							   (void *) port);#endif		if (ServerSock_INET != INVALID_SOCK &&			FD_ISSET(ServerSock_INET, &rmask) &&			(port = ConnCreate(ServerSock_INET)) != NULL)			PacketReceiveSetup(&port->pktInfo,							   readStartupPacket,							   (void *) port);		/* Build up new masks for select(). */		nSockets = initMasks(&readmask, &writemask);		curr = DLGetHead(PortList);		while (curr)		{			Port	   *port = (Port *) DLE_VAL(curr);			int			status = STATUS_OK;			Dlelem	   *next;			if (FD_ISSET(port->sock, &rmask))			{				if (DebugLvl > 1)					fprintf(stderr, "%s: ServerLoop:\t\thandling reading %d\n",							progname, port->sock);				if (PacketReceiveFragment(&port->pktInfo, port->sock) != STATUS_OK)					status = STATUS_ERROR;			}			if (FD_ISSET(port->sock, &wmask))			{				if (DebugLvl > 1)					fprintf(stderr, "%s: ServerLoop:\t\thandling writing %d\n",							progname, port->sock);				if (PacketSendFragment(&port->pktInfo, port->sock) != STATUS_OK)					status = STATUS_ERROR;			}			/* Get this before the connection might be closed. */			next = DLGetSucc(curr);			/*			 * If there is no error and no outstanding data transfer going			 * on, then the authentication handshake must be complete to			 * the postmaster's satisfaction.  So, start the backend.			 */			if (status == STATUS_OK && port->pktInfo.state == Idle)			{				/* Can't start backend if max backend count is exceeded. */				if (CountChildren() >= MaxBackends)					PacketSendError(&port->pktInfo,									"Sorry, too many clients already");				else				{					/*					 * If the backend start fails then keep the connection					 * open to report it.  Otherwise, pretend there is an					 * error to close the connection which will now be					 * managed by the backend.					 */					if (BackendStartup(port) != STATUS_OK)						PacketSendError(&port->pktInfo,										"Backend startup failed");					else						status = STATUS_ERROR;				}			}			/* Close the connection if required. */			if (status != STATUS_OK)			{				StreamClose(port->sock);				DLRemove(curr);				free(port);				DLFreeElem(curr);			}			else			{				/* Set the masks for this connection. */				if (nSockets <= port->sock)					nSockets = port->sock + 1;				if (port->pktInfo.state == WritingPacket)					FD_SET(port->sock, &writemask);				else					FD_SET(port->sock, &readmask);			}			curr = next;		}	}}/* * Initialise the read and write masks for select() for the well-known ports * we are listening on.  Return the number of sockets to listen on. */static intinitMasks(fd_set *rmask, fd_set *wmask){	int			nsocks = -1;	FD_ZERO(rmask);	FD_ZERO(wmask);#ifndef __CYGWIN32__	if (ServerSock_UNIX != INVALID_SOCK)	{		FD_SET(ServerSock_UNIX, rmask);		if (ServerSock_UNIX > nsocks)			nsocks = ServerSock_UNIX;	}#endif	if (ServerSock_INET != INVALID_SOCK)	{		FD_SET(ServerSock_INET, rmask);		if (ServerSock_INET > nsocks)			nsocks = ServerSock_INET;	}	return nsocks + 1;}/* * Called when the startup packet has been read. */static intreadStartupPacket(void *arg, PacketLen len, void *pkt){	Port	   *port;	StartupPacket *si;	port = (Port *) arg;	si = (StartupPacket *) pkt;	/*	 * The first field is either a protocol version number or a special	 * request code.	 */	port->proto = ntohl(si->protoVersion);	if (port->proto == CANCEL_REQUEST_CODE)		return processCancelRequest(port, len, pkt);	/* Could add additional special packet types here */	/* Check we can handle the protocol the frontend is using. */	if (PG_PROTOCOL_MAJOR(port->proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) ||		PG_PROTOCOL_MAJOR(port->proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) ||		(PG_PROTOCOL_MAJOR(port->proto) == PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) &&		 PG_PROTOCOL_MINOR(port->proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST)))	{		PacketSendError(&port->pktInfo, "Unsupported frontend protocol.");		return STATUS_OK;		/* don't close the connection yet */	}	/*	 * Get the parameters from the startup packet as C strings.  The	 * packet destination was cleared first so a short packet has zeros	 * silently added and a long packet is silently truncated.	 */	StrNCpy(port->database, si->database, sizeof(port->database) - 1);	StrNCpy(port->user, si->user, sizeof(port->user) - 1);	StrNCpy(port->options, si->options, sizeof(port->options) - 1);	StrNCpy(port->tty, si->tty, sizeof(port->tty) - 1);	/* The database defaults to the user name. */	if (port->database[0] == '\0')		StrNCpy(port->database, si->user, sizeof(port->database) - 1);	/* Check a user name was given. */	if (port->user[0] == '\0')	{		PacketSendError(&port->pktInfo,					"No Postgres username specified in startup packet.");		return STATUS_OK;		/* don't close the connection yet */	}	/* Start the authentication itself. */	be_recvauth(port);	return STATUS_OK;			/* don't close the connection yet */}/* * The client has sent a cancel request packet, not a normal * start-a-new-backend packet.	Perform the necessary processing. * Note that in any case, we return STATUS_ERROR to close the * connection immediately.	Nothing is sent back to the client. */static intprocessCancelRequest(Port *port, PacketLen len, void *pkt){	CancelRequestPacket *canc = (CancelRequestPacket *) pkt;	int			backendPID;	long		cancelAuthCode;	Dlelem	   *curr;	Backend    *bp;	backendPID = (int) ntohl(canc->backendPID);	cancelAuthCode = (long) ntohl(canc->cancelAuthCode);	/* See if we have a matching backend */	for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr))	{		bp = (Backend *) DLE_VAL(curr);		if (bp->pid == backendPID)		{			if (bp->cancel_key == cancelAuthCode)			{				/* Found a match; signal that backend to cancel current op */				if (DebugLvl)					fprintf(stderr, "%s: processCancelRequest: sending SIGINT to process %d\n",							progname, bp->pid);				kill(bp->pid, SIGINT);			}			else			{				/* Right PID, wrong key: no way, Jose */				if (DebugLvl)					fprintf(stderr, "%s: processCancelRequest: bad key in cancel request for process %d\n",							progname, bp->pid);			}			return STATUS_ERROR;		}	}	/* No matching backend */	if (DebugLvl)		fprintf(stderr, "%s: processCancelRequest: bad PID in cancel request for process %d\n",				progname, backendPID);	return STATUS_ERROR;}/* * ConnCreate -- create a local connection data structure */static Port *ConnCreate(int serverFd){	Port	   *port;	if (!(port = (Port *) calloc(1, sizeof(Port))))	{		fprintf(stderr, "%s: ConnCreate: malloc failed\n",				progname);		ExitPostmaster(1);	}	if (StreamConnection(serverFd, port) != STATUS_OK)	{		StreamClose(port->sock);		free(port);		port = NULL;	}	else	{		DLAddHead(PortList, DLNewElem(port));		RandomSalt(port->salt);		port->pktInfo.state = Idle;	}	return port;}/* * reset_shared -- reset shared memory and semaphores */static voidreset_shared(unsigned short port){	ipc_key = port * 1000 + shmem_seq * 100;	CreateSharedMemoryAndSemaphores(ipc_key, MaxBackends);	ActiveBackends = FALSE;	shmem_seq += 1;	if (shmem_seq >= 10)		shmem_seq -= 10;}/* * pmdie -- signal handler for cleaning up after a kill signal. */static voidpmdie(SIGNAL_ARGS){	int			i;	TPRINTF(TRACE_VERBOSE, "pmdie %d", postgres_signal_arg);	/*	 * Kill self and/or children processes depending on signal number.	 */	switch (postgres_signal_arg)	{		case SIGHUP:			/* Send SIGHUP to all children (update options flags) */			SignalChildren(SIGHUP);			/* Don't die */			return;		case SIGINT:			/* Die without killing children */			break;		case SIGQUIT:			/* Shutdown all children with SIGTERM */			SignalChildren(SIGTERM);			/* Don't die */			return;		case SIGTERM:			/* Shutdown all children with SIGTERM and SIGKILL, then die */			SignalChildren(SIGTERM);			for (i = 0; i < 10; i++)			{				if (!DLGetHead(BackendList))					break;				sleep(1);			}			if (DLGetHead(BackendList))				SignalChildren(SIGKILL);			break;		case SIGUSR1:			/* Quick die all children with SIGUSR1 and die */			SignalChildren(SIGUSR1);			break;		case SIGUSR2:			/* Send SIGUSR2 to all children (AsyncNotifyHandler) */			SignalChildren(SIGUSR2);			/* Don't die */			return;	}	/* exit postmaster */	proc_exit(0);}/* * Reaper -- signal handler to cleanup after a backend (child) dies. */static voidreaper(SIGNAL_ARGS){/* GH: replace waitpid for !HAVE_WAITPID. Does this work ? */#ifdef HAVE_WAITPID	int			status;			/* backend exit status */#else	union wait	statusp;		/* backend exit status */#endif	int			pid;			/* process id of dead backend */	if (DebugLvl)		fprintf(stderr, "%s: reaping dead processes...\n",				progname);#ifdef HAVE_WAITPID	while ((pid = waitpid(-1, &status, WNOHANG)) > 0)	{		CleanupProc(pid, status);		pqsignal(SIGCHLD, reaper);	}#else	while ((pid = wait3(&statusp, WNOHANG, NULL)) > 0)	{		CleanupProc(pid, statusp.w_status);		pqsignal(SIGCHLD, reaper);	}#endif}/* * CleanupProc -- cleanup after terminated backend. * * Remove all local state associated with backend. * * Dillon's note: should log child's exit status in the system log. */static voidCleanupProc(int pid,

⌨️ 快捷键说明

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