mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 10:30:33 +03:00 
			
		
		
		
	Use signals for postmaster death on Linux.
Linux provides a way to ask for a signal when your parent process dies. Use that to make PostmasterIsAlive() very cheap. Based on a suggestion from Andres Freund. Author: Thomas Munro, Heikki Linnakangas Reviewed-By: Michael Paquier Discussion: https://postgr.es/m/7261eb39-0369-f2f4-1bb5-62f3b6083b5e%40iki.fi Discussion: https://postgr.es/m/20180411002643.6buofht4ranhei7k%40alap3.anarazel.de
This commit is contained in:
		| @@ -1112,7 +1112,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout, | ||||
| 			 * WL_POSTMASTER_DEATH event would be painful. Re-checking doesn't | ||||
| 			 * cost much. | ||||
| 			 */ | ||||
| 			if (!PostmasterIsAlive()) | ||||
| 			if (!PostmasterIsAliveInternal()) | ||||
| 			{ | ||||
| 				occurred_events->fd = PGINVALID_SOCKET; | ||||
| 				occurred_events->events = WL_POSTMASTER_DEATH; | ||||
| @@ -1230,7 +1230,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout, | ||||
| 			 * WL_POSTMASTER_DEATH event would be painful. Re-checking doesn't | ||||
| 			 * cost much. | ||||
| 			 */ | ||||
| 			if (!PostmasterIsAlive()) | ||||
| 			if (!PostmasterIsAliveInternal()) | ||||
| 			{ | ||||
| 				occurred_events->fd = PGINVALID_SOCKET; | ||||
| 				occurred_events->events = WL_POSTMASTER_DEATH; | ||||
| @@ -1390,7 +1390,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout, | ||||
| 		 * even though there is no known reason to think that the event could | ||||
| 		 * be falsely set on Windows. | ||||
| 		 */ | ||||
| 		if (!PostmasterIsAlive()) | ||||
| 		if (!PostmasterIsAliveInternal()) | ||||
| 		{ | ||||
| 			occurred_events->fd = PGINVALID_SOCKET; | ||||
| 			occurred_events->events = WL_POSTMASTER_DEATH; | ||||
|   | ||||
| @@ -17,6 +17,10 @@ | ||||
| #include <signal.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #ifdef HAVE_SYS_PRCTL_H | ||||
| #include <sys/prctl.h> | ||||
| #endif | ||||
|  | ||||
| #include "miscadmin.h" | ||||
| #include "postmaster/postmaster.h" | ||||
| #include "replication/walsender.h" | ||||
| @@ -71,6 +75,35 @@ struct PMSignalData | ||||
|  | ||||
| NON_EXEC_STATIC volatile PMSignalData *PMSignalState = NULL; | ||||
|  | ||||
| /* | ||||
|  * Signal handler to be notified if postmaster dies. | ||||
|  */ | ||||
| #ifdef USE_POSTMASTER_DEATH_SIGNAL | ||||
| volatile sig_atomic_t postmaster_possibly_dead = false; | ||||
|  | ||||
| static void | ||||
| postmaster_death_handler(int signo) | ||||
| { | ||||
| 	postmaster_possibly_dead = true; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * The available signals depend on the OS.  SIGUSR1 and SIGUSR2 are already | ||||
|  * used for other things, so choose another one. | ||||
|  * | ||||
|  * Currently, we assume that we can always find a signal to use.  That | ||||
|  * seems like a reasonable assumption for all platforms that are modern | ||||
|  * enough to have a parent-death signaling mechanism. | ||||
|  */ | ||||
| #if defined(SIGINFO) | ||||
| #define POSTMASTER_DEATH_SIGNAL SIGINFO | ||||
| #elif defined(SIGPWR) | ||||
| #define POSTMASTER_DEATH_SIGNAL SIGPWR | ||||
| #else | ||||
| #error "cannot find a signal to use for postmaster death" | ||||
| #endif | ||||
|  | ||||
| #endif							/* USE_POSTMASTER_DEATH_SIGNAL */ | ||||
|  | ||||
| /* | ||||
|  * PMSignalShmemSize | ||||
| @@ -266,28 +299,94 @@ MarkPostmasterChildInactive(void) | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * PostmasterIsAlive - check whether postmaster process is still alive | ||||
|  * PostmasterIsAliveInternal - check whether postmaster process is still alive | ||||
|  * | ||||
|  * This is the slow path of PostmasterIsAlive(), where the caller has already | ||||
|  * checked 'postmaster_possibly_dead'.  (On platforms that don't support | ||||
|  * a signal for parent death, PostmasterIsAlive() is just an alias for this.) | ||||
|  */ | ||||
| bool | ||||
| PostmasterIsAlive(void) | ||||
| PostmasterIsAliveInternal(void) | ||||
| { | ||||
| #ifndef WIN32 | ||||
| 	char		c; | ||||
| 	ssize_t		rc; | ||||
| #ifdef USE_POSTMASTER_DEATH_SIGNAL | ||||
| 	/* | ||||
| 	 * Reset the flag before checking, so that we don't miss a signal if | ||||
| 	 * postmaster dies right after the check.  If postmaster was indeed dead, | ||||
| 	 * we'll re-arm it before returning to caller. | ||||
| 	 */ | ||||
| 	postmaster_possibly_dead = false; | ||||
| #endif | ||||
|  | ||||
| 	rc = read(postmaster_alive_fds[POSTMASTER_FD_WATCH], &c, 1); | ||||
| 	if (rc < 0) | ||||
| #ifndef WIN32 | ||||
| 	{ | ||||
| 		if (errno == EAGAIN || errno == EWOULDBLOCK) | ||||
| 		char		c; | ||||
| 		ssize_t		rc; | ||||
|  | ||||
| 		rc = read(postmaster_alive_fds[POSTMASTER_FD_WATCH], &c, 1); | ||||
|  | ||||
| 		/* | ||||
| 		 * In the usual case, the postmaster is still alive, and there is no | ||||
| 		 * data in the pipe. | ||||
| 		 */ | ||||
| 		if (rc < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) | ||||
| 			return true; | ||||
| 		else | ||||
| 			elog(FATAL, "read on postmaster death monitoring pipe failed: %m"); | ||||
| 	} | ||||
| 	else if (rc > 0) | ||||
| 		elog(FATAL, "unexpected data in postmaster death monitoring pipe"); | ||||
| 		{ | ||||
| 			/* | ||||
| 			 * Postmaster is dead, or something went wrong with the read() | ||||
| 			 * call. | ||||
| 			 */ | ||||
|  | ||||
| #ifdef USE_POSTMASTER_DEATH_SIGNAL | ||||
| 			postmaster_possibly_dead = true; | ||||
| #endif | ||||
|  | ||||
| 			if (rc < 0) | ||||
| 				elog(FATAL, "read on postmaster death monitoring pipe failed: %m"); | ||||
| 			else if (rc > 0) | ||||
| 				elog(FATAL, "unexpected data in postmaster death monitoring pipe"); | ||||
|  | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return false; | ||||
| #else							/* WIN32 */ | ||||
| 	return (WaitForSingleObject(PostmasterHandle, 0) == WAIT_TIMEOUT); | ||||
| 	if (WaitForSingleObject(PostmasterHandle, 0) == WAIT_TIMEOUT) | ||||
| 		return true; | ||||
| 	else | ||||
| 	{ | ||||
| #ifdef USE_POSTMASTER_DEATH_SIGNAL | ||||
| 		postmaster_possibly_dead = true; | ||||
| #endif | ||||
| 		return false; | ||||
| 	} | ||||
| #endif							/* WIN32 */ | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * PostmasterDeathSignalInit - request signal on postmaster death if possible | ||||
|  */ | ||||
| void | ||||
| PostmasterDeathSignalInit(void) | ||||
| { | ||||
| #ifdef USE_POSTMASTER_DEATH_SIGNAL | ||||
| 	int 		signum = POSTMASTER_DEATH_SIGNAL; | ||||
|  | ||||
| 	/* Register our signal handler. */ | ||||
| 	pqsignal(signum, postmaster_death_handler); | ||||
|  | ||||
| 	/* Request a signal on parent exit. */ | ||||
| #if defined(PR_SET_PDEATHSIG) | ||||
| 	if (prctl(PR_SET_PDEATHSIG, signum) < 0) | ||||
| 		elog(ERROR, "could not request parent death signal: %m"); | ||||
| #else | ||||
| #error "USE_POSTMASTER_DEATH_SIGNAL set, but there is no mechanism to request the signal" | ||||
| #endif | ||||
|  | ||||
| 	/* | ||||
| 	 * Just in case the parent was gone already and we missed it, we'd better | ||||
| 	 * check the slow way on the first call. | ||||
| 	 */ | ||||
| 	postmaster_possibly_dead = true; | ||||
| #endif							/* USE_POSTMASTER_DEATH_SIGNAL */ | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user