~yolanda.robla/ubuntu/trusty/nodejs/add_distribution

« back to all changes in this revision

Viewing changes to deps/uv/src/unix/process.c

  • Committer: Package Import Robot
  • Author(s): Jérémy Lal
  • Date: 2013-08-14 00:16:46 UTC
  • mfrom: (7.1.40 sid)
  • Revision ID: package-import@ubuntu.com-20130814001646-bzlysfh8sd6mukbo
Tags: 0.10.15~dfsg1-4
* Update 2005 patch, adding a handful of tests that can fail on
  slow platforms.
* Add 1004 patch to fix test failures when writing NaN to buffer
  on mipsel.

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
#include "uv.h"
23
23
#include "internal.h"
24
24
 
 
25
#include <stdio.h>
 
26
#include <stdlib.h>
25
27
#include <assert.h>
26
28
#include <errno.h>
 
29
 
 
30
#include <sys/types.h>
27
31
#include <sys/wait.h>
28
 
#include <fcntl.h> /* O_CLOEXEC, O_NONBLOCK */
 
32
#include <unistd.h>
 
33
#include <fcntl.h>
29
34
#include <poll.h>
30
 
#include <unistd.h>
31
 
#include <stdio.h>
32
35
 
33
 
#ifdef __APPLE__
 
36
#if defined(__APPLE__) && !TARGET_OS_IPHONE
34
37
# include <crt_externs.h>
35
38
# define environ (*_NSGetEnviron())
36
39
#else
38
41
#endif
39
42
 
40
43
 
41
 
static void uv__chld(EV_P_ ev_child* watcher, int revents) {
42
 
  int status = watcher->rstatus;
43
 
  int exit_status = 0;
44
 
  int term_signal = 0;
45
 
  uv_process_t *process = watcher->data;
46
 
 
47
 
  assert(&process->child_watcher == watcher);
48
 
  assert(revents & EV_CHILD);
49
 
 
50
 
  ev_child_stop(EV_A_ &process->child_watcher);
51
 
 
52
 
  if (WIFEXITED(status)) {
53
 
    exit_status = WEXITSTATUS(status);
54
 
  }
55
 
 
56
 
  if (WIFSIGNALED(status)) {
57
 
    term_signal = WTERMSIG(status);
58
 
  }
59
 
 
60
 
  if (process->exit_cb) {
 
44
static ngx_queue_t* uv__process_queue(uv_loop_t* loop, int pid) {
 
45
  assert(pid > 0);
 
46
  return loop->process_handles + pid % ARRAY_SIZE(loop->process_handles);
 
47
}
 
48
 
 
49
 
 
50
static uv_process_t* uv__process_find(uv_loop_t* loop, int pid) {
 
51
  uv_process_t* handle;
 
52
  ngx_queue_t* h;
 
53
  ngx_queue_t* q;
 
54
 
 
55
  h = uv__process_queue(loop, pid);
 
56
 
 
57
  ngx_queue_foreach(q, h) {
 
58
    handle = ngx_queue_data(q, uv_process_t, queue);
 
59
    if (handle->pid == pid) return handle;
 
60
  }
 
61
 
 
62
  return NULL;
 
63
}
 
64
 
 
65
 
 
66
static void uv__chld(uv_signal_t* handle, int signum) {
 
67
  uv_process_t* process;
 
68
  int exit_status;
 
69
  int term_signal;
 
70
  int status;
 
71
  pid_t pid;
 
72
 
 
73
  assert(signum == SIGCHLD);
 
74
 
 
75
  for (;;) {
 
76
    pid = waitpid(-1, &status, WNOHANG);
 
77
 
 
78
    if (pid == 0)
 
79
      return;
 
80
 
 
81
    if (pid == -1) {
 
82
      if (errno == ECHILD)
 
83
        return; /* XXX stop signal watcher? */
 
84
      else
 
85
        abort();
 
86
    }
 
87
 
 
88
    process = uv__process_find(handle->loop, pid);
 
89
    if (process == NULL)
 
90
      continue; /* XXX bug? abort? */
 
91
 
 
92
    uv__handle_stop(process);
 
93
 
 
94
    if (process->exit_cb == NULL)
 
95
      continue;
 
96
 
 
97
    exit_status = 0;
 
98
    term_signal = 0;
 
99
 
 
100
    if (WIFEXITED(status))
 
101
      exit_status = WEXITSTATUS(status);
 
102
 
 
103
    if (WIFSIGNALED(status))
 
104
      term_signal = WTERMSIG(status);
 
105
 
 
106
    if (process->errorno) {
 
107
      uv__set_sys_error(process->loop, process->errorno);
 
108
      exit_status = -1; /* execve() failed */
 
109
    }
 
110
 
61
111
    process->exit_cb(process, exit_status, term_signal);
62
112
  }
63
113
}
64
114
 
65
115
 
66
 
#define UV__F_IPC        (1 << 0)
67
 
#define UV__F_NONBLOCK   (1 << 1)
68
 
 
69
 
static int uv__make_socketpair(int fds[2], int flags) {
70
 
#ifdef SOCK_NONBLOCK
71
 
  int fl;
72
 
 
73
 
  fl = SOCK_CLOEXEC;
74
 
 
75
 
  if (flags & UV__F_NONBLOCK)
76
 
    fl |= SOCK_NONBLOCK;
77
 
 
78
 
  if (socketpair(AF_UNIX, SOCK_STREAM|fl, 0, fds) == 0)
 
116
int uv__make_socketpair(int fds[2], int flags) {
 
117
#if defined(__linux__)
 
118
  static int no_cloexec;
 
119
 
 
120
  if (no_cloexec)
 
121
    goto skip;
 
122
 
 
123
  if (socketpair(AF_UNIX, SOCK_STREAM | UV__SOCK_CLOEXEC | flags, 0, fds) == 0)
79
124
    return 0;
80
125
 
 
126
  /* Retry on EINVAL, it means SOCK_CLOEXEC is not supported.
 
127
   * Anything else is a genuine error.
 
128
   */
81
129
  if (errno != EINVAL)
82
130
    return -1;
83
131
 
84
 
  /* errno == EINVAL so maybe the kernel headers lied about
85
 
   * the availability of SOCK_NONBLOCK. This can happen if people
86
 
   * build libuv against newer kernel headers than the kernel
87
 
   * they actually run the software on.
88
 
   */
 
132
  no_cloexec = 1;
 
133
 
 
134
skip:
89
135
#endif
90
136
 
91
137
  if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
103
149
}
104
150
 
105
151
 
106
 
static int uv__make_pipe(int fds[2], int flags) {
107
 
#if HAVE_SYS_PIPE2
108
 
  int fl;
109
 
 
110
 
  fl = O_CLOEXEC;
111
 
 
112
 
  if (flags & UV__F_NONBLOCK)
113
 
    fl |= O_NONBLOCK;
114
 
 
115
 
  if (sys_pipe2(fds, fl) == 0)
 
152
int uv__make_pipe(int fds[2], int flags) {
 
153
#if defined(__linux__)
 
154
  static int no_pipe2;
 
155
 
 
156
  if (no_pipe2)
 
157
    goto skip;
 
158
 
 
159
  if (uv__pipe2(fds, flags | UV__O_CLOEXEC) == 0)
116
160
    return 0;
117
161
 
118
162
  if (errno != ENOSYS)
119
163
    return -1;
120
164
 
121
 
  /* errno == ENOSYS so maybe the kernel headers lied about
122
 
   * the availability of pipe2(). This can happen if people
123
 
   * build libuv against newer kernel headers than the kernel
124
 
   * they actually run the software on.
125
 
   */
 
165
  no_pipe2 = 1;
 
166
 
 
167
skip:
126
168
#endif
127
169
 
128
170
  if (pipe(fds))
144
186
 * Used for initializing stdio streams like options.stdin_stream. Returns
145
187
 * zero on success.
146
188
 */
147
 
static int uv__process_init_pipe(uv_pipe_t* handle, int fds[2], int flags) {
148
 
  if (handle->type != UV_NAMED_PIPE) {
149
 
    errno = EINVAL;
 
189
static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
 
190
  int mask;
 
191
  int fd;
 
192
 
 
193
  mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM;
 
194
 
 
195
  switch (container->flags & mask) {
 
196
  case UV_IGNORE:
 
197
    return 0;
 
198
 
 
199
  case UV_CREATE_PIPE:
 
200
    assert(container->data.stream != NULL);
 
201
    if (container->data.stream->type != UV_NAMED_PIPE) {
 
202
      errno = EINVAL;
 
203
      return -1;
 
204
    }
 
205
    return uv__make_socketpair(fds, 0);
 
206
 
 
207
  case UV_INHERIT_FD:
 
208
  case UV_INHERIT_STREAM:
 
209
    if (container->flags & UV_INHERIT_FD)
 
210
      fd = container->data.fd;
 
211
    else
 
212
      fd = uv__stream_fd(container->data.stream);
 
213
 
 
214
    if (fd == -1) {
 
215
      errno = EINVAL;
 
216
      return -1;
 
217
    }
 
218
 
 
219
    fds[1] = fd;
 
220
    return 0;
 
221
 
 
222
  default:
 
223
    assert(0 && "Unexpected flags");
150
224
    return -1;
151
225
  }
152
 
 
153
 
  if (handle->ipc)
154
 
    return uv__make_socketpair(fds, flags);
 
226
}
 
227
 
 
228
 
 
229
static int uv__process_open_stream(uv_stdio_container_t* container,
 
230
                                   int pipefds[2],
 
231
                                   int writable) {
 
232
  int flags;
 
233
 
 
234
  if (!(container->flags & UV_CREATE_PIPE) || pipefds[0] < 0)
 
235
    return 0;
 
236
 
 
237
  if (close(pipefds[1]))
 
238
    if (errno != EINTR && errno != EINPROGRESS)
 
239
      abort();
 
240
 
 
241
  pipefds[1] = -1;
 
242
  uv__nonblock(pipefds[0], 1);
 
243
 
 
244
  if (container->data.stream->type == UV_NAMED_PIPE &&
 
245
      ((uv_pipe_t*)container->data.stream)->ipc)
 
246
    flags = UV_STREAM_READABLE | UV_STREAM_WRITABLE;
 
247
  else if (writable)
 
248
    flags = UV_STREAM_WRITABLE;
155
249
  else
156
 
    return uv__make_pipe(fds, flags);
157
 
}
158
 
 
159
 
 
160
 
#ifndef SPAWN_WAIT_EXEC
161
 
# define SPAWN_WAIT_EXEC 1
162
 
#endif
163
 
 
164
 
int uv_spawn2(uv_loop_t* loop, uv_process_t* process,
165
 
    uv_process_options2_t options) {
166
 
  /*
167
 
   * Save environ in the case that we get it clobbered
168
 
   * by the child process.
169
 
   */
170
 
  char** save_our_env = environ;
171
 
  int stdin_pipe[2] = { -1, -1 };
172
 
  int stdout_pipe[2] = { -1, -1 };
173
 
  int stderr_pipe[2] = { -1, -1 };
174
 
#if SPAWN_WAIT_EXEC
 
250
    flags = UV_STREAM_READABLE;
 
251
 
 
252
  return uv__stream_open(container->data.stream, pipefds[0], flags);
 
253
}
 
254
 
 
255
 
 
256
static void uv__process_close_stream(uv_stdio_container_t* container) {
 
257
  if (!(container->flags & UV_CREATE_PIPE)) return;
 
258
  uv__stream_close((uv_stream_t*)container->data.stream);
 
259
}
 
260
 
 
261
 
 
262
static void uv__write_int(int fd, int val) {
 
263
  ssize_t n;
 
264
 
 
265
  do
 
266
    n = write(fd, &val, sizeof(val));
 
267
  while (n == -1 && errno == EINTR);
 
268
 
 
269
  if (n == -1 && errno == EPIPE)
 
270
    return; /* parent process has quit */
 
271
 
 
272
  assert(n == sizeof(val));
 
273
}
 
274
 
 
275
 
 
276
static void uv__process_child_init(uv_process_options_t options,
 
277
                                   int stdio_count,
 
278
                                   int (*pipes)[2],
 
279
                                   int error_fd) {
 
280
  int close_fd;
 
281
  int use_fd;
 
282
  int fd;
 
283
 
 
284
  if (options.flags & UV_PROCESS_DETACHED)
 
285
    setsid();
 
286
 
 
287
  for (fd = 0; fd < stdio_count; fd++) {
 
288
    close_fd = pipes[fd][0];
 
289
    use_fd = pipes[fd][1];
 
290
 
 
291
    if (use_fd >= 0)
 
292
      close(close_fd);
 
293
    else if (fd >= 3)
 
294
      continue;
 
295
    else {
 
296
      /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is
 
297
       * set
 
298
       */
 
299
      use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
 
300
 
 
301
      if (use_fd == -1) {
 
302
        uv__write_int(error_fd, errno);
 
303
        perror("failed to open stdio");
 
304
        _exit(127);
 
305
      }
 
306
    }
 
307
 
 
308
    if (fd == use_fd)
 
309
      uv__cloexec(use_fd, 0);
 
310
    else {
 
311
      dup2(use_fd, fd);
 
312
      close(use_fd);
 
313
    }
 
314
 
 
315
    if (fd <= 2)
 
316
      uv__nonblock(fd, 0);
 
317
  }
 
318
 
 
319
  if (options.cwd && chdir(options.cwd)) {
 
320
    uv__write_int(error_fd, errno);
 
321
    perror("chdir()");
 
322
    _exit(127);
 
323
  }
 
324
 
 
325
  if ((options.flags & UV_PROCESS_SETGID) && setgid(options.gid)) {
 
326
    uv__write_int(error_fd, errno);
 
327
    perror("setgid()");
 
328
    _exit(127);
 
329
  }
 
330
 
 
331
  if ((options.flags & UV_PROCESS_SETUID) && setuid(options.uid)) {
 
332
    uv__write_int(error_fd, errno);
 
333
    perror("setuid()");
 
334
    _exit(127);
 
335
  }
 
336
 
 
337
  if (options.env) {
 
338
    environ = options.env;
 
339
  }
 
340
 
 
341
  execvp(options.file, options.args);
 
342
  uv__write_int(error_fd, errno);
 
343
  perror("execvp()");
 
344
  _exit(127);
 
345
}
 
346
 
 
347
 
 
348
int uv_spawn(uv_loop_t* loop,
 
349
             uv_process_t* process,
 
350
             const uv_process_options_t options) {
175
351
  int signal_pipe[2] = { -1, -1 };
176
 
  struct pollfd pfd;
177
 
#endif
178
 
  int status;
 
352
  int (*pipes)[2];
 
353
  int stdio_count;
 
354
  ngx_queue_t* q;
 
355
  ssize_t r;
179
356
  pid_t pid;
180
 
  int flags;
 
357
  int i;
181
358
 
182
359
  assert(options.file != NULL);
183
 
  assert(!(options.flags & ~(UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS |
 
360
  assert(!(options.flags & ~(UV_PROCESS_DETACHED |
184
361
                             UV_PROCESS_SETGID |
185
 
                             UV_PROCESS_SETUID)));
186
 
 
 
362
                             UV_PROCESS_SETUID |
 
363
                             UV_PROCESS_WINDOWS_HIDE |
 
364
                             UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
187
365
 
188
366
  uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
189
 
  loop->counters.process_init++;
190
 
 
191
 
  process->exit_cb = options.exit_cb;
192
 
 
193
 
  if (options.stdin_stream &&
194
 
      uv__process_init_pipe(options.stdin_stream, stdin_pipe, 0)) {
195
 
    goto error;
196
 
  }
197
 
 
198
 
  if (options.stdout_stream &&
199
 
      uv__process_init_pipe(options.stdout_stream, stdout_pipe, 0)) {
200
 
    goto error;
201
 
  }
202
 
 
203
 
  if (options.stderr_stream &&
204
 
      uv__process_init_pipe(options.stderr_stream, stderr_pipe, 0)) {
205
 
    goto error;
206
 
  }
 
367
  ngx_queue_init(&process->queue);
 
368
 
 
369
  stdio_count = options.stdio_count;
 
370
  if (stdio_count < 3)
 
371
    stdio_count = 3;
 
372
 
 
373
  pipes = malloc(stdio_count * sizeof(*pipes));
 
374
  if (pipes == NULL) {
 
375
    errno = ENOMEM;
 
376
    goto error;
 
377
  }
 
378
 
 
379
  for (i = 0; i < stdio_count; i++) {
 
380
    pipes[i][0] = -1;
 
381
    pipes[i][1] = -1;
 
382
  }
 
383
 
 
384
  for (i = 0; i < options.stdio_count; i++)
 
385
    if (uv__process_init_stdio(options.stdio + i, pipes[i]))
 
386
      goto error;
207
387
 
208
388
  /* This pipe is used by the parent to wait until
209
389
   * the child has called `execve()`. We need this
223
403
   *
224
404
   * To avoid ambiguity, we create a pipe with both ends
225
405
   * marked close-on-exec. Then, after the call to `fork()`,
226
 
   * the parent polls the read end until it sees POLLHUP.
 
406
   * the parent polls the read end until it EOFs or errors with EPIPE.
227
407
   */
228
 
#if SPAWN_WAIT_EXEC
229
 
  if (uv__make_pipe(signal_pipe, UV__F_NONBLOCK))
 
408
  if (uv__make_pipe(signal_pipe, 0))
230
409
    goto error;
231
 
#endif
 
410
 
 
411
  uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD);
232
412
 
233
413
  pid = fork();
234
414
 
235
415
  if (pid == -1) {
236
 
#if SPAWN_WAIT_EXEC
237
 
    uv__close(signal_pipe[0]);
238
 
    uv__close(signal_pipe[1]);
239
 
#endif
240
 
    environ = save_our_env;
 
416
    close(signal_pipe[0]);
 
417
    close(signal_pipe[1]);
241
418
    goto error;
242
419
  }
243
420
 
244
421
  if (pid == 0) {
245
 
    if (stdin_pipe[0] >= 0) {
246
 
      uv__close(stdin_pipe[1]);
247
 
      dup2(stdin_pipe[0],  STDIN_FILENO);
248
 
    } else {
249
 
      /* Reset flags that might be set by Node */
250
 
      uv__cloexec(STDIN_FILENO, 0);
251
 
      uv__nonblock(STDIN_FILENO, 0);
252
 
    }
253
 
 
254
 
    if (stdout_pipe[1] >= 0) {
255
 
      uv__close(stdout_pipe[0]);
256
 
      dup2(stdout_pipe[1], STDOUT_FILENO);
257
 
    } else {
258
 
      /* Reset flags that might be set by Node */
259
 
      uv__cloexec(STDOUT_FILENO, 0);
260
 
      uv__nonblock(STDOUT_FILENO, 0);
261
 
    }
262
 
 
263
 
    if (stderr_pipe[1] >= 0) {
264
 
      uv__close(stderr_pipe[0]);
265
 
      dup2(stderr_pipe[1], STDERR_FILENO);
266
 
    } else {
267
 
      /* Reset flags that might be set by Node */
268
 
      uv__cloexec(STDERR_FILENO, 0);
269
 
      uv__nonblock(STDERR_FILENO, 0);
270
 
    }
271
 
 
272
 
    if (options.cwd && chdir(options.cwd)) {
273
 
      perror("chdir()");
274
 
      _exit(127);
275
 
    }
276
 
 
277
 
    if ((options.flags & UV_PROCESS_SETGID) && setgid(options.gid)) {
278
 
      perror("setgid()");
279
 
      _exit(127);
280
 
    }
281
 
 
282
 
    if ((options.flags & UV_PROCESS_SETUID) && setuid(options.uid)) {
283
 
      perror("setuid()");
284
 
      _exit(127);
285
 
    }
286
 
 
287
 
    environ = options.env;
288
 
 
289
 
    execvp(options.file, options.args);
290
 
    perror("execvp()");
291
 
    _exit(127);
292
 
    /* Execution never reaches here. */
293
 
  }
294
 
 
295
 
  /* Parent. */
296
 
 
297
 
  /* Restore environment. */
298
 
  environ = save_our_env;
299
 
 
300
 
#if SPAWN_WAIT_EXEC
301
 
  /* POLLHUP signals child has exited or execve()'d. */
302
 
  uv__close(signal_pipe[1]);
303
 
  do {
304
 
    pfd.fd = signal_pipe[0];
305
 
    pfd.events = POLLIN|POLLHUP;
306
 
    pfd.revents = 0;
307
 
    errno = 0, status = poll(&pfd, 1, -1);
308
 
  }
309
 
  while (status == -1 && (errno == EINTR || errno == ENOMEM));
310
 
 
311
 
  assert((status == 1) && "poll() on pipe read end failed");
312
 
  uv__close(signal_pipe[0]);
313
 
#endif
 
422
    uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]);
 
423
    abort();
 
424
  }
 
425
 
 
426
  close(signal_pipe[1]);
 
427
 
 
428
  process->errorno = 0;
 
429
  do
 
430
    r = read(signal_pipe[0], &process->errorno, sizeof(process->errorno));
 
431
  while (r == -1 && errno == EINTR);
 
432
 
 
433
  if (r == 0)
 
434
    ; /* okay, EOF */
 
435
  else if (r == sizeof(process->errorno))
 
436
    ; /* okay, read errorno */
 
437
  else if (r == -1 && errno == EPIPE)
 
438
    ; /* okay, got EPIPE */
 
439
  else
 
440
    abort();
 
441
 
 
442
  close(signal_pipe[0]);
 
443
 
 
444
  for (i = 0; i < options.stdio_count; i++) {
 
445
    if (uv__process_open_stream(options.stdio + i, pipes[i], i == 0)) {
 
446
      while (i--) uv__process_close_stream(options.stdio + i);
 
447
      goto error;
 
448
    }
 
449
  }
 
450
 
 
451
  q = uv__process_queue(loop, pid);
 
452
  ngx_queue_insert_tail(q, &process->queue);
314
453
 
315
454
  process->pid = pid;
316
 
 
317
 
  ev_child_init(&process->child_watcher, uv__chld, pid, 0);
318
 
  ev_child_start(process->loop->ev, &process->child_watcher);
319
 
  process->child_watcher.data = process;
320
 
 
321
 
  if (stdin_pipe[1] >= 0) {
322
 
    assert(options.stdin_stream);
323
 
    assert(stdin_pipe[0] >= 0);
324
 
    uv__close(stdin_pipe[0]);
325
 
    uv__nonblock(stdin_pipe[1], 1);
326
 
    flags = UV_WRITABLE | (options.stdin_stream->ipc ? UV_READABLE : 0);
327
 
    uv__stream_open((uv_stream_t*)options.stdin_stream, stdin_pipe[1],
328
 
        flags);
329
 
  }
330
 
 
331
 
  if (stdout_pipe[0] >= 0) {
332
 
    assert(options.stdout_stream);
333
 
    assert(stdout_pipe[1] >= 0);
334
 
    uv__close(stdout_pipe[1]);
335
 
    uv__nonblock(stdout_pipe[0], 1);
336
 
    flags = UV_READABLE | (options.stdout_stream->ipc ? UV_WRITABLE : 0);
337
 
    uv__stream_open((uv_stream_t*)options.stdout_stream, stdout_pipe[0],
338
 
        flags);
339
 
  }
340
 
 
341
 
  if (stderr_pipe[0] >= 0) {
342
 
    assert(options.stderr_stream);
343
 
    assert(stderr_pipe[1] >= 0);
344
 
    uv__close(stderr_pipe[1]);
345
 
    uv__nonblock(stderr_pipe[0], 1);
346
 
    flags = UV_READABLE | (options.stderr_stream->ipc ? UV_WRITABLE : 0);
347
 
    uv__stream_open((uv_stream_t*)options.stderr_stream, stderr_pipe[0],
348
 
        flags);
349
 
  }
350
 
 
 
455
  process->exit_cb = options.exit_cb;
 
456
  uv__handle_start(process);
 
457
 
 
458
  free(pipes);
351
459
  return 0;
352
460
 
353
461
error:
354
462
  uv__set_sys_error(process->loop, errno);
355
 
  uv__close(stdin_pipe[0]);
356
 
  uv__close(stdin_pipe[1]);
357
 
  uv__close(stdout_pipe[0]);
358
 
  uv__close(stdout_pipe[1]);
359
 
  uv__close(stderr_pipe[0]);
360
 
  uv__close(stderr_pipe[1]);
 
463
 
 
464
  for (i = 0; i < stdio_count; i++) {
 
465
    close(pipes[i][0]);
 
466
    close(pipes[i][1]);
 
467
  }
 
468
  free(pipes);
 
469
 
361
470
  return -1;
362
471
}
363
472
 
383
492
    return uv_ok_;
384
493
  }
385
494
}
 
495
 
 
496
 
 
497
void uv__process_close(uv_process_t* handle) {
 
498
  /* TODO stop signal watcher when this is the last handle */
 
499
  ngx_queue_remove(&handle->queue);
 
500
  uv__handle_stop(handle);
 
501
}