diff options
Diffstat (limited to 'src/process.c')
-rw-r--r-- | src/process.c | 129 |
1 files changed, 108 insertions, 21 deletions
diff --git a/src/process.c b/src/process.c index cec0acc4236..6b8b483cdf7 100644 --- a/src/process.c +++ b/src/process.c @@ -119,6 +119,11 @@ static struct rlimit nofile_limit; #include "gnutls.h" #endif +#ifdef HAVE_ANDROID +#include "android.h" +#include "androidterm.h" +#endif + #ifdef HAVE_WINDOW_SYSTEM #include TERM_HEADER #endif /* HAVE_WINDOW_SYSTEM */ @@ -876,7 +881,8 @@ allocate_pty (char pty_name[PTY_NAME_SIZE]) /* Check to make certain that both sides are available. This avoids a nasty yet stupid bug in rlogins. */ - if (faccessat (AT_FDCWD, pty_name, R_OK | W_OK, AT_EACCESS) != 0) + if (sys_faccessat (AT_FDCWD, pty_name, + R_OK | W_OK, AT_EACCESS) != 0) { emacs_close (fd); continue; @@ -1732,6 +1738,18 @@ DEFUN ("process-list", Fprocess_list, Sprocess_list, 0, 0, 0, } +static Lisp_Object +get_required_string_keyword_param (Lisp_Object kwargs, Lisp_Object keyword) +{ + Lisp_Object arg = plist_member (kwargs, keyword); + if (NILP (arg) || !CONSP (arg) || !CONSP (XCDR (arg))) + error ("Missing %s keyword parameter", SSDATA (SYMBOL_NAME (keyword))); + Lisp_Object val = XCAR (XCDR (arg)); + if (!STRINGP (val)) + error ("%s value not a string", SSDATA (SYMBOL_NAME (keyword))); + return val; +} + /* Starting asynchronous inferior processes. */ DEFUN ("make-process", Fmake_process, Smake_process, 0, MANY, 0, @@ -1796,7 +1814,7 @@ such handler, proceed as if FILE-HANDLER were nil. usage: (make-process &rest ARGS) */) (ptrdiff_t nargs, Lisp_Object *args) { - Lisp_Object buffer, name, command, program, proc, contact, current_dir, tem; + Lisp_Object buffer, command, program, proc, contact, current_dir, tem; Lisp_Object xstderr, stderrproc; specpdl_ref count = SPECPDL_INDEX (); @@ -1825,8 +1843,7 @@ usage: (make-process &rest ARGS) */) chdir, since it's in a vfork. */ current_dir = get_current_directory (true); - name = plist_get (contact, QCname); - CHECK_STRING (name); + Lisp_Object name = get_required_string_keyword_param (contact, QCname); command = plist_get (contact, QCcommand); if (CONSP (command)) @@ -2003,7 +2020,7 @@ usage: (make-process &rest ARGS) */) { tem = Qnil; openp (Vexec_path, program, Vexec_suffixes, &tem, - make_fixnum (X_OK), false, false); + make_fixnum (X_OK), false, false, NULL); if (NILP (tem)) report_file_error ("Searching for program", program); tem = Fexpand_file_name (tem, Qnil); @@ -2409,7 +2426,7 @@ usage: (make-pipe-process &rest ARGS) */) { Lisp_Object proc, contact; struct Lisp_Process *p; - Lisp_Object name, buffer; + Lisp_Object buffer; Lisp_Object tem; int inchannel, outchannel; @@ -2418,8 +2435,7 @@ usage: (make-pipe-process &rest ARGS) */) contact = Flist (nargs, args); - name = plist_get (contact, QCname); - CHECK_STRING (name); + Lisp_Object name = get_required_string_keyword_param (contact, QCname); proc = make_process (name); specpdl_ref specpdl_count = SPECPDL_INDEX (); record_unwind_protect (remove_process, proc); @@ -3939,7 +3955,7 @@ usage: (make-network-process &rest ARGS) */) #endif EMACS_INT port = 0; Lisp_Object tem; - Lisp_Object name, buffer, host, service, address; + Lisp_Object buffer, host, service, address; Lisp_Object filter, sentinel, use_external_socket_p; Lisp_Object addrinfos = Qnil; int socktype; @@ -3976,7 +3992,7 @@ usage: (make-network-process &rest ARGS) */) else error ("Unsupported connection type"); - name = plist_get (contact, QCname); + Lisp_Object name = get_required_string_keyword_param (contact, QCname); buffer = plist_get (contact, QCbuffer); filter = plist_get (contact, QCfilter); sentinel = plist_get (contact, QCsentinel); @@ -3986,7 +4002,6 @@ usage: (make-network-process &rest ARGS) */) if (!NILP (server) && nowait) error ("`:server' is incompatible with `:nowait'"); - CHECK_STRING (name); /* :local ADDRESS or :remote ADDRESS */ if (NILP (server)) @@ -5194,6 +5209,27 @@ wait_reading_process_output_1 (void) { } +#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY \ + && defined THREADS_ENABLED + +/* Wrapper around `android_select' that exposes a calling interface with + an extra argument for compatibility with `thread_pselect'. */ + +static int +android_select_wrapper (int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, const struct timespec *timeout, + const sigset_t *sigmask) +{ + /* sigmask is not supported. */ + if (sigmask) + emacs_abort (); + + return android_select (nfds, readfds, writefds, exceptfds, + (struct timespec *) timeout); +} + +#endif /* HAVE_ANDROID && !ANDROID_STUBIFY && THREADS_ENABLED */ + /* Read and dispose of subprocess output while waiting for timeout to elapse and/or keyboard input to be available. @@ -5403,7 +5439,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, /* If there is unread keyboard input, also return. */ if (read_kbd != 0 - && requeued_events_pending_p ()) + && requeued_command_events_pending_p ()) break; /* This is so a breakpoint can be put here. */ @@ -5686,7 +5722,23 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, timeout = short_timeout; #endif - /* Non-macOS HAVE_GLIB builds call thread_select in xgselect.c. */ + /* Android requires using a replacement for pselect in + android.c to poll for events. */ +#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY +#ifndef THREADS_ENABLED + nfds = android_select (max_desc + 1, + &Available, (check_write ? &Writeok : 0), + NULL, &timeout); +#else /* THREADS_ENABLED */ + nfds = thread_select (android_select_wrapper, + max_desc + 1, + &Available, (check_write ? &Writeok : 0), + NULL, &timeout, NULL); +#endif /* THREADS_ENABLED */ +#else + + /* Non-macOS HAVE_GLIB builds call thread_select in + xgselect.c. */ #if defined HAVE_GLIB && !defined HAVE_NS nfds = xg_select (max_desc + 1, &Available, (check_write ? &Writeok : 0), @@ -5702,6 +5754,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, (check_write ? &Writeok : 0), NULL, &timeout, NULL); #endif /* !HAVE_GLIB */ +#endif /* HAVE_ANDROID && !ANDROID_STUBIFY */ #ifdef HAVE_GNUTLS /* Merge tls_available into Available. */ @@ -5796,7 +5849,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, /* If there is unread keyboard input, also return. */ if (read_kbd != 0 - && requeued_events_pending_p ()) + && requeued_command_events_pending_p ()) break; /* If we are not checking for keyboard input now, @@ -7137,7 +7190,8 @@ See function `signal-process' for more details on usage. */) { ptrdiff_t len; tem = string_to_number (SSDATA (process), 10, &len); - if (NILP (tem) || len != SBYTES (process)) + if ((IEEE_FLOATING_POINT ? NILP (tem) : !NUMBERP (tem)) + || len != SBYTES (process)) return Qnil; } process = tem; @@ -7240,10 +7294,10 @@ process has been transmitted to the serial port. */) send_process (proc, "\004", 1, Qnil); else if (EQ (XPROCESS (proc)->type, Qserial)) { -#ifndef WINDOWSNT +#if !defined WINDOWSNT && defined HAVE_TCDRAIN if (tcdrain (XPROCESS (proc)->outfd) != 0) report_file_error ("Failed tcdrain", Qnil); -#endif /* not WINDOWSNT */ +#endif /* not WINDOWSNT && not TCDRAIN */ /* Do nothing on Windows because writes are blocking. */ } else @@ -7396,8 +7450,31 @@ child_signal_notify (void) int fd = child_signal_write_fd; eassert (0 <= fd); char dummy = 0; - if (emacs_write (fd, &dummy, 1) != 1) - emacs_perror ("writing to child signal FD"); + /* We used to error out here, like this: + + if (emacs_write (fd, &dummy, 1) != 1) + emacs_perror ("writing to child signal FD"); + + But this calls `emacs_perror', which in turn invokes a localized + version of strerror, which is not reentrant and must not be + called within a signal handler: + + __lll_lock_wait_private () at /lib64/libc.so.6 + malloc () at /lib64/libc.so.6 + _nl_make_l10nflist.localalias () at /lib64/libc.so.6 + _nl_find_domain () at /lib64/libc.so.6 + __dcigettext () at /lib64/libc.so.6 + strerror_l () at /lib64/libc.so.6 + emacs_perror (message=message@entry=0x6babc2) + child_signal_notify () at process.c:7419 + handle_child_signal (sig=17) at process.c:7533 + deliver_process_signal (sig=17, handler=0x6186b0>) + <signal handler called> () at /lib64/libc.so.6 + _int_malloc () at /lib64/libc.so.6 + in malloc () at /lib64/libc.so.6. + + So we no longer check errors of emacs_write here. */ + emacs_write (fd, &dummy, 1); #endif } @@ -7463,6 +7540,16 @@ handle_child_signal (int sig) { changed = true; if (STRINGP (XCDR (head))) + /* handle_child_signal is called in an async signal + handler but needs to unlink temporary files which + might've been created in an Android content + provider. + + emacs_unlink is not async signal safe because + deleting files from content providers must proceed + through Java code. Consequently, if XCDR (head) + lies on a content provider it will not be removed, + which is a bug. */ unlink (SSDATA (XCDR (head))); XSETCAR (tail, Qnil); } @@ -7949,7 +8036,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, /* If there is unread keyboard input, also return. */ if (read_kbd != 0 - && requeued_events_pending_p ()) + && requeued_command_events_pending_p ()) break; if (timespec_valid_p (timer_delay)) @@ -8022,7 +8109,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, /* If there is unread keyboard input, also return. */ if (read_kbd - && requeued_events_pending_p ()) + && requeued_command_events_pending_p ()) break; /* If wait_for_cell. check for keyboard input |