diff options
| author | Philipp Stephani | 2020-12-24 15:27:45 +0100 |
|---|---|---|
| committer | Philipp Stephani | 2020-12-24 15:34:23 +0100 |
| commit | bf7041a6f6ea2d57f842b9b2915cc58a90b01406 (patch) | |
| tree | 30576ef17b8ab3ba1514fd67e303635d21fa286e /src/process.c | |
| parent | 3096437593ca6d1ea07809f7d0e2198705f20e55 (diff) | |
| download | emacs-bf7041a6f6ea2d57f842b9b2915cc58a90b01406.tar.gz emacs-bf7041a6f6ea2d57f842b9b2915cc58a90b01406.zip | |
Centralize subprocess creation in a single function.
Getting the vfork + execve combination right isn't easy, and the code
was partially duplicated between callproc.c and process.c. Centralize
the spawn operation in a single function that deals with the nasty
details. Going forward, we should be able to use posix_spawn from
either libc or Gnulib (or CreateProcessW on Windows) in the non-pty
case.
* src/callproc.c (emacs_spawn): New function to start an asynchronous
subprocess. Merge code from 'call_process' and 'create_process' into
this function.
(call_process): Use new 'emacs_spawn' function.
(child_setup): Make static, since there are no users outside this
compilation unit left.
(CHILD_SETUP_TYPE): Move from header file, since there are no users
outside this compilation unit left.
* src/process.c (create_process): Use new 'emacs_spawn' function.
Diffstat (limited to 'src/process.c')
| -rw-r--r-- | src/process.c | 149 |
1 files changed, 7 insertions, 142 deletions
diff --git a/src/process.c b/src/process.c index 15b4a23784e..f3de9251b7a 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -2047,13 +2047,12 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) | |||
| 2047 | { | 2047 | { |
| 2048 | struct Lisp_Process *p = XPROCESS (process); | 2048 | struct Lisp_Process *p = XPROCESS (process); |
| 2049 | int inchannel, outchannel; | 2049 | int inchannel, outchannel; |
| 2050 | pid_t pid; | 2050 | pid_t pid = -1; |
| 2051 | int vfork_errno; | 2051 | int vfork_errno; |
| 2052 | int forkin, forkout, forkerr = -1; | 2052 | int forkin, forkout, forkerr = -1; |
| 2053 | bool pty_flag = 0; | 2053 | bool pty_flag = 0; |
| 2054 | char pty_name[PTY_NAME_SIZE]; | 2054 | char pty_name[PTY_NAME_SIZE]; |
| 2055 | Lisp_Object lisp_pty_name = Qnil; | 2055 | Lisp_Object lisp_pty_name = Qnil; |
| 2056 | sigset_t oldset; | ||
| 2057 | 2056 | ||
| 2058 | inchannel = outchannel = -1; | 2057 | inchannel = outchannel = -1; |
| 2059 | 2058 | ||
| @@ -2130,154 +2129,20 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) | |||
| 2130 | setup_process_coding_systems (process); | 2129 | setup_process_coding_systems (process); |
| 2131 | char *const *env = make_environment_block (current_dir); | 2130 | char *const *env = make_environment_block (current_dir); |
| 2132 | 2131 | ||
| 2133 | block_input (); | ||
| 2134 | block_child_signal (&oldset); | ||
| 2135 | |||
| 2136 | #ifndef WINDOWSNT | ||
| 2137 | /* vfork, and prevent local vars from being clobbered by the vfork. */ | ||
| 2138 | Lisp_Object volatile current_dir_volatile = current_dir; | ||
| 2139 | Lisp_Object volatile lisp_pty_name_volatile = lisp_pty_name; | ||
| 2140 | char **volatile new_argv_volatile = new_argv; | ||
| 2141 | int volatile forkin_volatile = forkin; | ||
| 2142 | int volatile forkout_volatile = forkout; | ||
| 2143 | int volatile forkerr_volatile = forkerr; | ||
| 2144 | struct Lisp_Process *p_volatile = p; | ||
| 2145 | char *const *volatile env_volatile = env; | ||
| 2146 | |||
| 2147 | #ifdef DARWIN_OS | ||
| 2148 | /* Darwin doesn't let us run setsid after a vfork, so use fork when | ||
| 2149 | necessary. Also, reset SIGCHLD handling after a vfork, as | ||
| 2150 | apparently macOS can mistakenly deliver SIGCHLD to the child. */ | ||
| 2151 | if (pty_flag) | ||
| 2152 | pid = fork (); | ||
| 2153 | else | ||
| 2154 | { | ||
| 2155 | pid = vfork (); | ||
| 2156 | if (pid == 0) | ||
| 2157 | signal (SIGCHLD, SIG_DFL); | ||
| 2158 | } | ||
| 2159 | #else | ||
| 2160 | pid = vfork (); | ||
| 2161 | #endif | ||
| 2162 | |||
| 2163 | current_dir = current_dir_volatile; | ||
| 2164 | lisp_pty_name = lisp_pty_name_volatile; | ||
| 2165 | new_argv = new_argv_volatile; | ||
| 2166 | forkin = forkin_volatile; | ||
| 2167 | forkout = forkout_volatile; | ||
| 2168 | forkerr = forkerr_volatile; | ||
| 2169 | p = p_volatile; | ||
| 2170 | env = env_volatile; | ||
| 2171 | |||
| 2172 | pty_flag = p->pty_flag; | 2132 | pty_flag = p->pty_flag; |
| 2133 | eassert (pty_flag == ! NILP (lisp_pty_name)); | ||
| 2173 | 2134 | ||
| 2174 | if (pid == 0) | 2135 | vfork_errno |
| 2175 | #endif /* not WINDOWSNT */ | 2136 | = emacs_spawn (&pid, forkin, forkout, forkerr, new_argv, env, |
| 2176 | { | 2137 | SSDATA (current_dir), |
| 2177 | /* Make the pty be the controlling terminal of the process. */ | 2138 | pty_flag ? SSDATA (lisp_pty_name) : NULL); |
| 2178 | #ifdef HAVE_PTYS | ||
| 2179 | dissociate_controlling_tty (); | ||
| 2180 | 2139 | ||
| 2181 | /* Make the pty's terminal the controlling terminal. */ | 2140 | eassert ((vfork_errno == 0) == (0 < pid)); |
| 2182 | if (pty_flag && forkin >= 0) | ||
| 2183 | { | ||
| 2184 | #ifdef TIOCSCTTY | ||
| 2185 | /* We ignore the return value | ||
| 2186 | because faith@cs.unc.edu says that is necessary on Linux. */ | ||
| 2187 | ioctl (forkin, TIOCSCTTY, 0); | ||
| 2188 | #endif | ||
| 2189 | } | ||
| 2190 | #if defined (LDISC1) | ||
| 2191 | if (pty_flag && forkin >= 0) | ||
| 2192 | { | ||
| 2193 | struct termios t; | ||
| 2194 | tcgetattr (forkin, &t); | ||
| 2195 | t.c_lflag = LDISC1; | ||
| 2196 | if (tcsetattr (forkin, TCSANOW, &t) < 0) | ||
| 2197 | emacs_perror ("create_process/tcsetattr LDISC1"); | ||
| 2198 | } | ||
| 2199 | #else | ||
| 2200 | #if defined (NTTYDISC) && defined (TIOCSETD) | ||
| 2201 | if (pty_flag && forkin >= 0) | ||
| 2202 | { | ||
| 2203 | /* Use new line discipline. */ | ||
| 2204 | int ldisc = NTTYDISC; | ||
| 2205 | ioctl (forkin, TIOCSETD, &ldisc); | ||
| 2206 | } | ||
| 2207 | #endif | ||
| 2208 | #endif | ||
| 2209 | 2141 | ||
| 2210 | #if !defined (DONT_REOPEN_PTY) | ||
| 2211 | /*** There is a suggestion that this ought to be a | ||
| 2212 | conditional on TIOCSPGRP, or !defined TIOCSCTTY. | ||
| 2213 | Trying the latter gave the wrong results on Debian GNU/Linux 1.1; | ||
| 2214 | that system does seem to need this code, even though | ||
| 2215 | both TIOCSCTTY is defined. */ | ||
| 2216 | /* Now close the pty (if we had it open) and reopen it. | ||
| 2217 | This makes the pty the controlling terminal of the subprocess. */ | ||
| 2218 | if (pty_flag) | ||
| 2219 | { | ||
| 2220 | |||
| 2221 | /* I wonder if emacs_close (emacs_open (SSDATA (lisp_pty_name), ...)) | ||
| 2222 | would work? */ | ||
| 2223 | if (forkin >= 0) | ||
| 2224 | emacs_close (forkin); | ||
| 2225 | forkout = forkin = emacs_open (SSDATA (lisp_pty_name), O_RDWR, 0); | ||
| 2226 | |||
| 2227 | if (forkin < 0) | ||
| 2228 | { | ||
| 2229 | emacs_perror (SSDATA (lisp_pty_name)); | ||
| 2230 | _exit (EXIT_CANCELED); | ||
| 2231 | } | ||
| 2232 | |||
| 2233 | } | ||
| 2234 | #endif /* not DONT_REOPEN_PTY */ | ||
| 2235 | |||
| 2236 | #ifdef SETUP_SLAVE_PTY | ||
| 2237 | if (pty_flag) | ||
| 2238 | { | ||
| 2239 | SETUP_SLAVE_PTY; | ||
| 2240 | } | ||
| 2241 | #endif /* SETUP_SLAVE_PTY */ | ||
| 2242 | #endif /* HAVE_PTYS */ | ||
| 2243 | |||
| 2244 | signal (SIGINT, SIG_DFL); | ||
| 2245 | signal (SIGQUIT, SIG_DFL); | ||
| 2246 | #ifdef SIGPROF | ||
| 2247 | signal (SIGPROF, SIG_DFL); | ||
| 2248 | #endif | ||
| 2249 | |||
| 2250 | /* Emacs ignores SIGPIPE, but the child should not. */ | ||
| 2251 | signal (SIGPIPE, SIG_DFL); | ||
| 2252 | |||
| 2253 | /* Stop blocking SIGCHLD in the child. */ | ||
| 2254 | unblock_child_signal (&oldset); | ||
| 2255 | |||
| 2256 | if (pty_flag) | ||
| 2257 | child_setup_tty (forkout); | ||
| 2258 | |||
| 2259 | if (forkerr < 0) | ||
| 2260 | forkerr = forkout; | ||
| 2261 | #ifdef WINDOWSNT | ||
| 2262 | pid = child_setup (forkin, forkout, forkerr, new_argv, env, | ||
| 2263 | SSDATA (current_dir)); | ||
| 2264 | #else /* not WINDOWSNT */ | ||
| 2265 | child_setup (forkin, forkout, forkerr, new_argv, env, | ||
| 2266 | SSDATA (current_dir)); | ||
| 2267 | #endif /* not WINDOWSNT */ | ||
| 2268 | } | ||
| 2269 | |||
| 2270 | /* Back in the parent process. */ | ||
| 2271 | |||
| 2272 | vfork_errno = errno; | ||
| 2273 | p->pid = pid; | 2142 | p->pid = pid; |
| 2274 | if (pid >= 0) | 2143 | if (pid >= 0) |
| 2275 | p->alive = 1; | 2144 | p->alive = 1; |
| 2276 | 2145 | ||
| 2277 | /* Stop blocking in the parent. */ | ||
| 2278 | unblock_child_signal (&oldset); | ||
| 2279 | unblock_input (); | ||
| 2280 | |||
| 2281 | /* Environment block no longer needed. */ | 2146 | /* Environment block no longer needed. */ |
| 2282 | unbind_to (count, Qnil); | 2147 | unbind_to (count, Qnil); |
| 2283 | 2148 | ||