contrib/chg/procutil.c
changeset 41336 763b45bc4483
parent 35959 9724f54923ec
equal deleted inserted replaced
41335:b81ca9a3f4e4 41336:763b45bc4483
    23 static pid_t peerpid = 0;
    23 static pid_t peerpid = 0;
    24 
    24 
    25 static void forwardsignal(int sig)
    25 static void forwardsignal(int sig)
    26 {
    26 {
    27 	assert(peerpid > 0);
    27 	assert(peerpid > 0);
    28 	if (kill(peerpid, sig) < 0)
    28 	if (kill(peerpid, sig) < 0) {
    29 		abortmsgerrno("cannot kill %d", peerpid);
    29 		abortmsgerrno("cannot kill %d", peerpid);
       
    30 	}
    30 	debugmsg("forward signal %d", sig);
    31 	debugmsg("forward signal %d", sig);
    31 }
    32 }
    32 
    33 
    33 static void forwardsignaltogroup(int sig)
    34 static void forwardsignaltogroup(int sig)
    34 {
    35 {
    35 	/* prefer kill(-pgid, sig), fallback to pid if pgid is invalid */
    36 	/* prefer kill(-pgid, sig), fallback to pid if pgid is invalid */
    36 	pid_t killpid = peerpgid > 1 ? -peerpgid : peerpid;
    37 	pid_t killpid = peerpgid > 1 ? -peerpgid : peerpid;
    37 	if (kill(killpid, sig) < 0)
    38 	if (kill(killpid, sig) < 0) {
    38 		abortmsgerrno("cannot kill %d", killpid);
    39 		abortmsgerrno("cannot kill %d", killpid);
       
    40 	}
    39 	debugmsg("forward signal %d to %d", sig, killpid);
    41 	debugmsg("forward signal %d to %d", sig, killpid);
    40 }
    42 }
    41 
    43 
    42 static void handlestopsignal(int sig)
    44 static void handlestopsignal(int sig)
    43 {
    45 {
    44 	sigset_t unblockset, oldset;
    46 	sigset_t unblockset, oldset;
    45 	struct sigaction sa, oldsa;
    47 	struct sigaction sa, oldsa;
    46 	if (sigemptyset(&unblockset) < 0)
    48 	if (sigemptyset(&unblockset) < 0) {
    47 		goto error;
    49 		goto error;
    48 	if (sigaddset(&unblockset, sig) < 0)
    50 	}
    49 		goto error;
    51 	if (sigaddset(&unblockset, sig) < 0) {
       
    52 		goto error;
       
    53 	}
    50 	memset(&sa, 0, sizeof(sa));
    54 	memset(&sa, 0, sizeof(sa));
    51 	sa.sa_handler = SIG_DFL;
    55 	sa.sa_handler = SIG_DFL;
    52 	sa.sa_flags = SA_RESTART;
    56 	sa.sa_flags = SA_RESTART;
    53 	if (sigemptyset(&sa.sa_mask) < 0)
    57 	if (sigemptyset(&sa.sa_mask) < 0) {
    54 		goto error;
    58 		goto error;
       
    59 	}
    55 
    60 
    56 	forwardsignal(sig);
    61 	forwardsignal(sig);
    57 	if (raise(sig) < 0) /* resend to self */
    62 	if (raise(sig) < 0) { /* resend to self */
    58 		goto error;
    63 		goto error;
    59 	if (sigaction(sig, &sa, &oldsa) < 0)
    64 	}
    60 		goto error;
    65 	if (sigaction(sig, &sa, &oldsa) < 0) {
    61 	if (sigprocmask(SIG_UNBLOCK, &unblockset, &oldset) < 0)
    66 		goto error;
    62 		goto error;
    67 	}
       
    68 	if (sigprocmask(SIG_UNBLOCK, &unblockset, &oldset) < 0) {
       
    69 		goto error;
       
    70 	}
    63 	/* resent signal will be handled before sigprocmask() returns */
    71 	/* resent signal will be handled before sigprocmask() returns */
    64 	if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0)
    72 	if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0) {
    65 		goto error;
    73 		goto error;
    66 	if (sigaction(sig, &oldsa, NULL) < 0)
    74 	}
    67 		goto error;
    75 	if (sigaction(sig, &oldsa, NULL) < 0) {
       
    76 		goto error;
       
    77 	}
    68 	return;
    78 	return;
    69 
    79 
    70 error:
    80 error:
    71 	abortmsgerrno("failed to handle stop signal");
    81 	abortmsgerrno("failed to handle stop signal");
    72 }
    82 }
    73 
    83 
    74 static void handlechildsignal(int sig UNUSED_)
    84 static void handlechildsignal(int sig UNUSED_)
    75 {
    85 {
    76 	if (peerpid == 0 || pagerpid == 0)
    86 	if (peerpid == 0 || pagerpid == 0) {
    77 		return;
    87 		return;
       
    88 	}
    78 	/* if pager exits, notify the server with SIGPIPE immediately.
    89 	/* if pager exits, notify the server with SIGPIPE immediately.
    79 	 * otherwise the server won't get SIGPIPE if it does not write
    90 	 * otherwise the server won't get SIGPIPE if it does not write
    80 	 * anything. (issue5278) */
    91 	 * anything. (issue5278) */
    81 	if (waitpid(pagerpid, NULL, WNOHANG) == pagerpid)
    92 	if (waitpid(pagerpid, NULL, WNOHANG) == pagerpid) {
    82 		kill(peerpid, SIGPIPE);
    93 		kill(peerpid, SIGPIPE);
       
    94 	}
    83 }
    95 }
    84 
    96 
    85 void setupsignalhandler(pid_t pid, pid_t pgid)
    97 void setupsignalhandler(pid_t pid, pid_t pgid)
    86 {
    98 {
    87 	if (pid <= 0)
    99 	if (pid <= 0) {
    88 		return;
   100 		return;
       
   101 	}
    89 	peerpid = pid;
   102 	peerpid = pid;
    90 	peerpgid = (pgid <= 1 ? 0 : pgid);
   103 	peerpgid = (pgid <= 1 ? 0 : pgid);
    91 
   104 
    92 	struct sigaction sa;
   105 	struct sigaction sa;
    93 	memset(&sa, 0, sizeof(sa));
   106 	memset(&sa, 0, sizeof(sa));
    96 	 * - SIGHUP: usually generated by the kernel, when termination of a
   109 	 * - SIGHUP: usually generated by the kernel, when termination of a
    97 	 *   process causes that process group to become orphaned
   110 	 *   process causes that process group to become orphaned
    98 	 * - SIGINT: usually generated by the terminal */
   111 	 * - SIGINT: usually generated by the terminal */
    99 	sa.sa_handler = forwardsignaltogroup;
   112 	sa.sa_handler = forwardsignaltogroup;
   100 	sa.sa_flags = SA_RESTART;
   113 	sa.sa_flags = SA_RESTART;
   101 	if (sigemptyset(&sa.sa_mask) < 0)
   114 	if (sigemptyset(&sa.sa_mask) < 0) {
   102 		goto error;
   115 		goto error;
   103 	if (sigaction(SIGHUP, &sa, NULL) < 0)
   116 	}
   104 		goto error;
   117 	if (sigaction(SIGHUP, &sa, NULL) < 0) {
   105 	if (sigaction(SIGINT, &sa, NULL) < 0)
   118 		goto error;
   106 		goto error;
   119 	}
       
   120 	if (sigaction(SIGINT, &sa, NULL) < 0) {
       
   121 		goto error;
       
   122 	}
   107 
   123 
   108 	/* terminate frontend by double SIGTERM in case of server freeze */
   124 	/* terminate frontend by double SIGTERM in case of server freeze */
   109 	sa.sa_handler = forwardsignal;
   125 	sa.sa_handler = forwardsignal;
   110 	sa.sa_flags |= SA_RESETHAND;
   126 	sa.sa_flags |= SA_RESETHAND;
   111 	if (sigaction(SIGTERM, &sa, NULL) < 0)
   127 	if (sigaction(SIGTERM, &sa, NULL) < 0) {
   112 		goto error;
   128 		goto error;
       
   129 	}
   113 
   130 
   114 	/* notify the worker about window resize events */
   131 	/* notify the worker about window resize events */
   115 	sa.sa_flags = SA_RESTART;
   132 	sa.sa_flags = SA_RESTART;
   116 	if (sigaction(SIGWINCH, &sa, NULL) < 0)
   133 	if (sigaction(SIGWINCH, &sa, NULL) < 0) {
   117 		goto error;
   134 		goto error;
       
   135 	}
   118 	/* forward user-defined signals */
   136 	/* forward user-defined signals */
   119 	if (sigaction(SIGUSR1, &sa, NULL) < 0)
   137 	if (sigaction(SIGUSR1, &sa, NULL) < 0) {
   120 		goto error;
   138 		goto error;
   121 	if (sigaction(SIGUSR2, &sa, NULL) < 0)
   139 	}
   122 		goto error;
   140 	if (sigaction(SIGUSR2, &sa, NULL) < 0) {
       
   141 		goto error;
       
   142 	}
   123 	/* propagate job control requests to worker */
   143 	/* propagate job control requests to worker */
   124 	sa.sa_handler = forwardsignal;
   144 	sa.sa_handler = forwardsignal;
   125 	sa.sa_flags = SA_RESTART;
   145 	sa.sa_flags = SA_RESTART;
   126 	if (sigaction(SIGCONT, &sa, NULL) < 0)
   146 	if (sigaction(SIGCONT, &sa, NULL) < 0) {
   127 		goto error;
   147 		goto error;
       
   148 	}
   128 	sa.sa_handler = handlestopsignal;
   149 	sa.sa_handler = handlestopsignal;
   129 	sa.sa_flags = SA_RESTART;
   150 	sa.sa_flags = SA_RESTART;
   130 	if (sigaction(SIGTSTP, &sa, NULL) < 0)
   151 	if (sigaction(SIGTSTP, &sa, NULL) < 0) {
   131 		goto error;
   152 		goto error;
       
   153 	}
   132 	/* get notified when pager exits */
   154 	/* get notified when pager exits */
   133 	sa.sa_handler = handlechildsignal;
   155 	sa.sa_handler = handlechildsignal;
   134 	sa.sa_flags = SA_RESTART;
   156 	sa.sa_flags = SA_RESTART;
   135 	if (sigaction(SIGCHLD, &sa, NULL) < 0)
   157 	if (sigaction(SIGCHLD, &sa, NULL) < 0) {
   136 		goto error;
   158 		goto error;
       
   159 	}
   137 
   160 
   138 	return;
   161 	return;
   139 
   162 
   140 error:
   163 error:
   141 	abortmsgerrno("failed to set up signal handlers");
   164 	abortmsgerrno("failed to set up signal handlers");
   145 {
   168 {
   146 	struct sigaction sa;
   169 	struct sigaction sa;
   147 	memset(&sa, 0, sizeof(sa));
   170 	memset(&sa, 0, sizeof(sa));
   148 	sa.sa_handler = SIG_DFL;
   171 	sa.sa_handler = SIG_DFL;
   149 	sa.sa_flags = SA_RESTART;
   172 	sa.sa_flags = SA_RESTART;
   150 	if (sigemptyset(&sa.sa_mask) < 0)
   173 	if (sigemptyset(&sa.sa_mask) < 0) {
   151 		goto error;
   174 		goto error;
   152 
   175 	}
   153 	if (sigaction(SIGHUP, &sa, NULL) < 0)
   176 
   154 		goto error;
   177 	if (sigaction(SIGHUP, &sa, NULL) < 0) {
   155 	if (sigaction(SIGTERM, &sa, NULL) < 0)
   178 		goto error;
   156 		goto error;
   179 	}
   157 	if (sigaction(SIGWINCH, &sa, NULL) < 0)
   180 	if (sigaction(SIGTERM, &sa, NULL) < 0) {
   158 		goto error;
   181 		goto error;
   159 	if (sigaction(SIGCONT, &sa, NULL) < 0)
   182 	}
   160 		goto error;
   183 	if (sigaction(SIGWINCH, &sa, NULL) < 0) {
   161 	if (sigaction(SIGTSTP, &sa, NULL) < 0)
   184 		goto error;
   162 		goto error;
   185 	}
   163 	if (sigaction(SIGCHLD, &sa, NULL) < 0)
   186 	if (sigaction(SIGCONT, &sa, NULL) < 0) {
   164 		goto error;
   187 		goto error;
       
   188 	}
       
   189 	if (sigaction(SIGTSTP, &sa, NULL) < 0) {
       
   190 		goto error;
       
   191 	}
       
   192 	if (sigaction(SIGCHLD, &sa, NULL) < 0) {
       
   193 		goto error;
       
   194 	}
   165 
   195 
   166 	/* ignore Ctrl+C while shutting down to make pager exits cleanly */
   196 	/* ignore Ctrl+C while shutting down to make pager exits cleanly */
   167 	sa.sa_handler = SIG_IGN;
   197 	sa.sa_handler = SIG_IGN;
   168 	if (sigaction(SIGINT, &sa, NULL) < 0)
   198 	if (sigaction(SIGINT, &sa, NULL) < 0) {
   169 		goto error;
   199 		goto error;
       
   200 	}
   170 
   201 
   171 	peerpid = 0;
   202 	peerpid = 0;
   172 	return;
   203 	return;
   173 
   204 
   174 error:
   205 error:
   178 /* This implementation is based on hgext/pager.py (post 369741ef7253)
   209 /* This implementation is based on hgext/pager.py (post 369741ef7253)
   179  * Return 0 if pager is not started, or pid of the pager */
   210  * Return 0 if pager is not started, or pid of the pager */
   180 pid_t setuppager(const char *pagercmd, const char *envp[])
   211 pid_t setuppager(const char *pagercmd, const char *envp[])
   181 {
   212 {
   182 	assert(pagerpid == 0);
   213 	assert(pagerpid == 0);
   183 	if (!pagercmd)
   214 	if (!pagercmd) {
   184 		return 0;
   215 		return 0;
       
   216 	}
   185 
   217 
   186 	int pipefds[2];
   218 	int pipefds[2];
   187 	if (pipe(pipefds) < 0)
   219 	if (pipe(pipefds) < 0) {
   188 		return 0;
   220 		return 0;
       
   221 	}
   189 	pid_t pid = fork();
   222 	pid_t pid = fork();
   190 	if (pid < 0)
   223 	if (pid < 0) {
   191 		goto error;
   224 		goto error;
       
   225 	}
   192 	if (pid > 0) {
   226 	if (pid > 0) {
   193 		close(pipefds[0]);
   227 		close(pipefds[0]);
   194 		if (dup2(pipefds[1], fileno(stdout)) < 0)
   228 		if (dup2(pipefds[1], fileno(stdout)) < 0) {
   195 			goto error;
   229 			goto error;
       
   230 		}
   196 		if (isatty(fileno(stderr))) {
   231 		if (isatty(fileno(stderr))) {
   197 			if (dup2(pipefds[1], fileno(stderr)) < 0)
   232 			if (dup2(pipefds[1], fileno(stderr)) < 0) {
   198 				goto error;
   233 				goto error;
       
   234 			}
   199 		}
   235 		}
   200 		close(pipefds[1]);
   236 		close(pipefds[1]);
   201 		pagerpid = pid;
   237 		pagerpid = pid;
   202 		return pid;
   238 		return pid;
   203 	} else {
   239 	} else {
   220 	return 0;
   256 	return 0;
   221 }
   257 }
   222 
   258 
   223 void waitpager(void)
   259 void waitpager(void)
   224 {
   260 {
   225 	if (pagerpid == 0)
   261 	if (pagerpid == 0) {
   226 		return;
   262 		return;
       
   263 	}
   227 
   264 
   228 	/* close output streams to notify the pager its input ends */
   265 	/* close output streams to notify the pager its input ends */
   229 	fclose(stdout);
   266 	fclose(stdout);
   230 	fclose(stderr);
   267 	fclose(stderr);
   231 	while (1) {
   268 	while (1) {
   232 		pid_t ret = waitpid(pagerpid, NULL, 0);
   269 		pid_t ret = waitpid(pagerpid, NULL, 0);
   233 		if (ret == -1 && errno == EINTR)
   270 		if (ret == -1 && errno == EINTR) {
   234 			continue;
   271 			continue;
       
   272 		}
   235 		break;
   273 		break;
   236 	}
   274 	}
   237 }
   275 }