* process.c: add comments about async-signal-safe.

* io.c: ditto.



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35918 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
akr 2012-06-05 10:16:11 +00:00
Родитель ff3b2cb1ce
Коммит 5b13036fce
3 изменённых файлов: 73 добавлений и 51 удалений

Просмотреть файл

@ -1,3 +1,9 @@
Tue Jun 5 19:15:14 2012 Tanaka Akira <akr@fsij.org>
* process.c: add comments about async-signal-safe.
* io.c: ditto.
Tue Jun 5 09:25:10 2012 Eric Hodel <drbrain@segment7.net>
* io.c: Edited documentation for IO and File open and new and

11
io.c
Просмотреть файл

@ -5421,6 +5421,7 @@ linux_get_maxfd(void)
}
#endif
/* This function should be async-signal-safe. */
void
rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
{
@ -5428,7 +5429,7 @@ rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
int max = max_file_descriptor;
#ifdef F_MAXFD
/* F_MAXFD is available since NetBSD 2.0. */
ret = fcntl(0, F_MAXFD);
ret = fcntl(0, F_MAXFD); /* async-signal-safe */
if (ret != -1)
maxhint = max = ret;
#elif defined(__linux__)
@ -5441,15 +5442,15 @@ rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
max = maxhint;
for (fd = lowfd; fd <= max; fd++) {
if (!NIL_P(noclose_fds) &&
RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd))))
RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
continue;
#ifdef FD_CLOEXEC
ret = fcntl(fd, F_GETFD);
ret = fcntl(fd, F_GETFD); /* async-signal-safe */
if (ret != -1 && !(ret & FD_CLOEXEC)) {
fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
}
#else
ret = close(fd);
ret = close(fd); /* async-signal-safe */
#endif
#define CONTIGUOUS_CLOSED_FDS 20
if (ret != -1) {

107
process.c
Просмотреть файл

@ -1048,14 +1048,17 @@ security(const char *str)
}
#if defined(HAVE_FORK) && !defined(__native_client__)
/* try_with_sh and exec_with_sh should be async-signal-safe. */
#define try_with_sh(prog, argv) ((saved_errno == ENOEXEC) ? exec_with_sh((prog), (argv)) : (void)0)
static void
exec_with_sh(const char *prog, char **argv)
{
*argv = (char *)prog;
*--argv = (char *)"sh";
execv("/bin/sh", argv);
execv("/bin/sh", argv); /* async-signal-safe */
}
#define ARGV_COUNT(n) ((n)+1)
#else
#define try_with_sh(prog, argv) (void)0
@ -1066,6 +1069,7 @@ exec_with_sh(const char *prog, char **argv)
#define ALLOC_ARGV_WITH_STR(n, v, s, l) \
(char **)(((s) = ALLOCV_N(char, (v), ARGV_SIZE(n) + (l)) + ARGV_SIZE(n)) - ARGV_SIZE(n))
/* This function should be async-signal-safe. */
static int
proc_exec_v(const char *prog, VALUE argv_str, VALUE envp_str)
{
@ -1083,7 +1087,7 @@ proc_exec_v(const char *prog, VALUE argv_str, VALUE envp_str)
if (!prog)
prog = argv[0];
prog = dln_find_exe_r(prog, 0, fbuf, sizeof(fbuf));
prog = dln_find_exe_r(prog, 0, fbuf, sizeof(fbuf)); /* xxx: not async-signal-safe because getenv(), strdup(), etc. */
if (!prog) {
errno = ENOENT;
return -1;
@ -1117,12 +1121,13 @@ proc_exec_v(const char *prog, VALUE argv_str, VALUE envp_str)
}
}
# endif /* __EMX__ */
before_exec();
before_exec(); /* async-signal-safe if forked_child is true */
if (envp_str)
execve(prog, argv, (char **)RSTRING_PTR(envp_str));
execve(prog, argv, (char **)RSTRING_PTR(envp_str)); /* async-signal-safe */
else
execv(prog, argv);
preserving_errno(try_with_sh(prog, argv); after_exec());
execv(prog, argv); /* async-signal-safe */
preserving_errno(try_with_sh(prog, argv); /* try_with_sh() is async-signal-safe. */
after_exec()); /* after_exec() is not async-signal-safe */
# if defined(__EMX__) || defined(OS2)
if (new_argv) {
xfree(new_argv[0]);
@ -1133,6 +1138,7 @@ proc_exec_v(const char *prog, VALUE argv_str, VALUE envp_str)
#endif
}
/* This function should be async-signal-safe. */
static int
rb_proc_exec_e(const char *str, VALUE envp_str)
{
@ -1169,12 +1175,12 @@ rb_proc_exec_e(const char *str, VALUE envp_str)
exit(status);
}
#else
before_exec();
before_exec(); /* async-signal-safe if forked_child is true. */
if (envp_str)
execle("/bin/sh", "sh", "-c", str, (char *)NULL, (char **)RSTRING_PTR(envp_str));
execle("/bin/sh", "sh", "-c", str, (char *)NULL, (char **)RSTRING_PTR(envp_str)); /* async-signal-safe */
else
execl("/bin/sh", "sh", "-c", str, (char *)NULL);
preserving_errno(after_exec());
execl("/bin/sh", "sh", "-c", str, (char *)NULL); /* async-signal-safe */
preserving_errno(after_exec()); /* xxx: not async-signal-safe because after_exec calls rb_thread_start_timer_thread. */
#endif
return -1;
#endif /* _WIN32 */
@ -2123,6 +2129,7 @@ intrcmp(const void *a, const void *b)
return *(int*)b - *(int*)a;
}
/* This function should be async-signal-safe when _save_ is not Qnil. */
static int
run_exec_dup2(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
{
@ -2137,7 +2144,7 @@ run_exec_dup2(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
} *pairs = 0;
n = RARRAY_LEN(ary);
pairs = (struct fd_pair *)malloc(sizeof(struct fd_pair) * n);
pairs = (struct fd_pair *)malloc(sizeof(struct fd_pair) * n); /* xxx: not async-signal-safe */
if (pairs == NULL) {
ERRMSG("malloc");
return -1;
@ -2153,7 +2160,7 @@ run_exec_dup2(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
/* sort the table by oldfd: O(n log n) */
if (!RTEST(save))
qsort(pairs, n, sizeof(struct fd_pair), intcmp);
qsort(pairs, n, sizeof(struct fd_pair), intcmp); /* hopefully async-signal-safe */
else
qsort(pairs, n, sizeof(struct fd_pair), intrcmp);
@ -2162,7 +2169,7 @@ run_exec_dup2(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
int newfd = pairs[i].newfd;
struct fd_pair key, *found;
key.oldfd = newfd;
found = bsearch(&key, pairs, n, sizeof(struct fd_pair), intcmp);
found = bsearch(&key, pairs, n, sizeof(struct fd_pair), intcmp); /* hopefully async-signal-safe */
pairs[i].num_newer = 0;
if (found) {
while (pairs < found && (found-1)->oldfd == newfd)
@ -2179,14 +2186,14 @@ run_exec_dup2(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
for (i = 0; i < n; i++) {
long j = i;
while (j != -1 && pairs[j].oldfd != -1 && pairs[j].num_newer == 0) {
if (save_redirect_fd(pairs[j].newfd, save, errmsg, errmsg_buflen) < 0)
if (save_redirect_fd(pairs[j].newfd, save, errmsg, errmsg_buflen) < 0) /* async-signal-safe */
goto fail;
ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd); /* async-signal-safe */
if (ret == -1) {
ERRMSG("dup2");
goto fail;
}
rb_update_max_fd(pairs[j].newfd);
rb_update_max_fd(pairs[j].newfd); /* async-signal-safe but don't need to call it in a child process. */
pairs[j].oldfd = -1;
j = pairs[j].older_index;
if (j != -1)
@ -2202,14 +2209,14 @@ run_exec_dup2(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
if (pairs[i].oldfd == pairs[i].newfd) { /* self cycle */
#ifdef F_GETFD
int fd = pairs[i].oldfd;
ret = fcntl(fd, F_GETFD);
ret = fcntl(fd, F_GETFD); /* async-signal-safe */
if (ret == -1) {
ERRMSG("fcntl(F_GETFD)");
goto fail;
}
if (ret & FD_CLOEXEC) {
ret &= ~FD_CLOEXEC;
ret = fcntl(fd, F_SETFD, ret);
ret = fcntl(fd, F_SETFD, ret); /* async-signal-safe */
if (ret == -1) {
ERRMSG("fcntl(F_SETFD)");
goto fail;
@ -2220,7 +2227,7 @@ run_exec_dup2(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
continue;
}
if (extra_fd == -1) {
extra_fd = redirect_dup(pairs[i].oldfd);
extra_fd = redirect_dup(pairs[i].oldfd); /* async-signal-safe */
if (extra_fd == -1) {
ERRMSG("dup");
goto fail;
@ -2228,7 +2235,7 @@ run_exec_dup2(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
rb_update_max_fd(extra_fd);
}
else {
ret = redirect_dup2(pairs[i].oldfd, extra_fd);
ret = redirect_dup2(pairs[i].oldfd, extra_fd); /* async-signal-safe */
if (ret == -1) {
ERRMSG("dup2");
goto fail;
@ -2239,7 +2246,7 @@ run_exec_dup2(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
j = pairs[i].older_index;
pairs[i].older_index = -1;
while (j != -1) {
ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd); /* async-signal-safe */
if (ret == -1) {
ERRMSG("dup2");
goto fail;
@ -2250,21 +2257,22 @@ run_exec_dup2(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
}
}
if (extra_fd != -1) {
ret = redirect_close(extra_fd);
ret = redirect_close(extra_fd); /* async-signal-safe */
if (ret == -1) {
ERRMSG("close");
goto fail;
}
}
free(pairs);
free(pairs); /* xxx: not async-signal-safe */
return 0;
fail:
free(pairs);
free(pairs); /* xxx: not async-signal-safe */
return -1;
}
/* This function should be async-signal-safe. */
static int
run_exec_close(VALUE ary, char *errmsg, size_t errmsg_buflen)
{
@ -2274,7 +2282,7 @@ run_exec_close(VALUE ary, char *errmsg, size_t errmsg_buflen)
for (i = 0; i < RARRAY_LEN(ary); i++) {
VALUE elt = RARRAY_PTR(ary)[i];
int fd = FIX2INT(RARRAY_PTR(elt)[0]);
ret = redirect_close(fd);
ret = redirect_close(fd); /* async-signal-safe */
if (ret == -1) {
ERRMSG("close");
return -1;
@ -2283,6 +2291,7 @@ run_exec_close(VALUE ary, char *errmsg, size_t errmsg_buflen)
return 0;
}
/* This function should be async-signal-safe when _save_ is not Qnil. */
static int
run_exec_open(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
{
@ -2297,7 +2306,7 @@ run_exec_open(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
int flags = NUM2INT(RARRAY_PTR(param)[1]);
int perm = NUM2INT(RARRAY_PTR(param)[2]);
int need_close = 1;
int fd2 = redirect_open(path, flags, perm);
int fd2 = redirect_open(path, flags, perm); /* async-signal-safe */
if (fd2 == -1) {
ERRMSG("open");
return -1;
@ -2310,9 +2319,9 @@ run_exec_open(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
need_close = 0;
}
else {
if (save_redirect_fd(fd, save, errmsg, errmsg_buflen) < 0)
if (save_redirect_fd(fd, save, errmsg, errmsg_buflen) < 0) /* async-signal-safe */
return -1;
ret = redirect_dup2(fd2, fd);
ret = redirect_dup2(fd2, fd); /* async-signal-safe */
if (ret == -1) {
ERRMSG("dup2");
return -1;
@ -2322,7 +2331,7 @@ run_exec_open(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
i++;
}
if (need_close) {
ret = redirect_close(fd2);
ret = redirect_close(fd2); /* async-signal-safe */
if (ret == -1) {
ERRMSG("close");
return -1;
@ -2332,6 +2341,7 @@ run_exec_open(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
return 0;
}
/* This function should be async-signal-safe when _save_ is not Qnil. */
static int
run_exec_dup2_child(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
{
@ -2343,9 +2353,9 @@ run_exec_dup2_child(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
int newfd = FIX2INT(RARRAY_PTR(elt)[0]);
int oldfd = FIX2INT(RARRAY_PTR(elt)[1]);
if (save_redirect_fd(newfd, save, errmsg, errmsg_buflen) < 0)
if (save_redirect_fd(newfd, save, errmsg, errmsg_buflen) < 0) /* async-signal-safe */
return -1;
ret = redirect_dup2(oldfd, newfd);
ret = redirect_dup2(oldfd, newfd); /* async-signal-safe */
if (ret == -1) {
ERRMSG("dup2");
return -1;
@ -2356,6 +2366,7 @@ run_exec_dup2_child(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
}
#ifdef HAVE_SETPGID
/* This function should be async-signal-safe when _save_ is not Qnil. */
static int
run_exec_pgroup(VALUE obj, VALUE save, char *errmsg, size_t errmsg_buflen)
{
@ -2373,15 +2384,16 @@ run_exec_pgroup(VALUE obj, VALUE save, char *errmsg, size_t errmsg_buflen)
}
pgroup = NUM2PIDT(obj);
if (pgroup == 0) {
pgroup = getpid();
pgroup = getpid(); /* async-signal-safe */
}
ret = setpgid(getpid(), pgroup);
ret = setpgid(getpid(), pgroup); /* async-signal-safe */
if (ret == -1) ERRMSG("setpgid");
return ret;
}
#endif
#if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
/* This function should be async-signal-safe when _save_ is not Qnil. */
static int
run_exec_rlimit(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
{
@ -2408,7 +2420,7 @@ run_exec_rlimit(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
}
rlim.rlim_cur = NUM2RLIM(RARRAY_PTR(elt)[1]);
rlim.rlim_max = NUM2RLIM(RARRAY_PTR(elt)[2]);
if (setrlimit(rtype, &rlim) == -1) {
if (setrlimit(rtype, &rlim) == -1) { /* hopefully async-signal-safe */
ERRMSG("setrlimit");
return -1;
}
@ -2441,6 +2453,7 @@ save_env(VALUE save)
}
#endif
/* This function should be async-signal-safe when _s_ is not NULL. */
int
rb_run_exec_options_err(const struct rb_exec_arg *e, struct rb_exec_arg *s, char *errmsg, size_t errmsg_buflen)
{
@ -2462,7 +2475,7 @@ rb_run_exec_options_err(const struct rb_exec_arg *e, struct rb_exec_arg *s, char
#ifdef HAVE_SETPGID
obj = rb_ary_entry(options, EXEC_OPTION_PGROUP);
if (RTEST(obj)) {
if (run_exec_pgroup(obj, soptions, errmsg, errmsg_buflen) == -1)
if (run_exec_pgroup(obj, soptions, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
return -1;
}
#endif
@ -2470,7 +2483,7 @@ rb_run_exec_options_err(const struct rb_exec_arg *e, struct rb_exec_arg *s, char
#if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
obj = rb_ary_entry(options, EXEC_OPTION_RLIMIT);
if (!NIL_P(obj)) {
if (run_exec_rlimit(obj, soptions, errmsg, errmsg_buflen) == -1)
if (run_exec_rlimit(obj, soptions, errmsg, errmsg_buflen) == -1) /* not async-signal-safe */
return -1;
}
#endif
@ -2501,14 +2514,14 @@ rb_run_exec_options_err(const struct rb_exec_arg *e, struct rb_exec_arg *s, char
obj = rb_ary_entry(options, EXEC_OPTION_UMASK);
if (!NIL_P(obj)) {
mode_t mask = NUM2MODET(obj);
mode_t oldmask = umask(mask); /* never fail */
mode_t oldmask = umask(mask); /* never fail */ /* async-signal-safe */
if (!NIL_P(soptions))
rb_ary_store(soptions, EXEC_OPTION_UMASK, MODET2NUM(oldmask));
}
obj = rb_ary_entry(options, EXEC_OPTION_DUP2);
if (!NIL_P(obj)) {
if (run_exec_dup2(obj, soptions, errmsg, errmsg_buflen) == -1)
if (run_exec_dup2(obj, soptions, errmsg, errmsg_buflen) == -1) /* xxx: not async-signal-safe */
return -1;
}
@ -2517,7 +2530,7 @@ rb_run_exec_options_err(const struct rb_exec_arg *e, struct rb_exec_arg *s, char
if (!NIL_P(soptions))
rb_warn("cannot close fd before spawn");
else {
if (run_exec_close(obj, errmsg, errmsg_buflen) == -1)
if (run_exec_close(obj, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
return -1;
}
}
@ -2525,19 +2538,19 @@ rb_run_exec_options_err(const struct rb_exec_arg *e, struct rb_exec_arg *s, char
#ifdef HAVE_FORK
obj = rb_ary_entry(options, EXEC_OPTION_CLOSE_OTHERS);
if (obj != Qfalse) {
rb_close_before_exec(3, FIX2INT(obj), e->redirect_fds);
rb_close_before_exec(3, FIX2INT(obj), e->redirect_fds); /* async-signal-safe */
}
#endif
obj = rb_ary_entry(options, EXEC_OPTION_OPEN);
if (!NIL_P(obj)) {
if (run_exec_open(obj, soptions, errmsg, errmsg_buflen) == -1)
if (run_exec_open(obj, soptions, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
return -1;
}
obj = rb_ary_entry(options, EXEC_OPTION_DUP2_CHILD);
if (!NIL_P(obj)) {
if (run_exec_dup2_child(obj, soptions, errmsg, errmsg_buflen) == -1)
if (run_exec_dup2_child(obj, soptions, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
return -1;
}
@ -2549,7 +2562,7 @@ rb_run_exec_options_err(const struct rb_exec_arg *e, struct rb_exec_arg *s, char
hide_obj(rb_str_new2(cwd)));
xfree(cwd);
}
if (chdir(RSTRING_PTR(obj)) == -1) {
if (chdir(RSTRING_PTR(obj)) == -1) { /* async-signal-safe */
ERRMSG("chdir");
return -1;
}
@ -2564,6 +2577,7 @@ rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s)
return rb_run_exec_options_err(e, s, NULL, 0);
}
/* This function should be async-signal-safe. */
int
rb_exec_err(const struct rb_exec_arg *e, char *errmsg, size_t errmsg_buflen)
{
@ -2574,15 +2588,15 @@ rb_exec_err(const struct rb_exec_arg *e, char *errmsg, size_t errmsg_buflen)
# define sargp NULL
#endif
if (rb_run_exec_options_err(e, sargp, errmsg, errmsg_buflen) < 0) {
if (rb_run_exec_options_err(e, sargp, errmsg, errmsg_buflen) < 0) { /* not async-signal-safe because run_exec_dup2. */
return -1;
}
if (e->use_shell) {
rb_proc_exec_e(prog, e->envp_str);
rb_proc_exec_e(prog, e->envp_str); /* not async-signal-safe because after_exec. */
}
else {
proc_exec_v(prog, e->argv_str, e->envp_str);
proc_exec_v(prog, e->argv_str, e->envp_str); /* async-signal-safe not checked */
}
#if !defined(HAVE_FORK)
preserving_errno(rb_run_exec_options_err(sargp, NULL, errmsg, errmsg_buflen));
@ -2614,6 +2628,7 @@ rb_exec(const struct rb_exec_arg *e)
}
#ifdef HAVE_FORK
/* This function should be async-signal-safe but rb_thread_atfork_before_exec is not checked. */
static int
rb_exec_atfork(void* arg, char *errmsg, size_t errmsg_buflen)
{