summaryrefslogtreecommitdiff
path: root/src/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/process.c')
-rw-r--r--src/process.c129
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