/* Asynchronous subprocess control for GNU Emacs.
Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995,
1996, 1998, 1999, 2001, 2002, 2003, 2004,
- 2005 Free Software Foundation, Inc.
+ 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include <sys/types.h> /* some typedefs are used in sys/file.h */
#include <sys/file.h>
#include <sys/stat.h>
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
struct Lisp_Process *p;
{
union { int i; WAITTYPE wt; } u;
- u.i = XFASTINT (p->raw_status_low) + (XFASTINT (p->raw_status_high) << 16);
+ eassert (p->raw_status_new);
+ u.i = p->raw_status;
p->status = status_convert (u.wt);
- p->raw_status_low = Qnil;
- p->raw_status_high = Qnil;
+ p->raw_status_new = 0;
}
/* Convert a process status word in Unix format to
XSETINT (p->infd, -1);
XSETINT (p->outfd, -1);
- XSETFASTINT (p->pid, 0);
XSETFASTINT (p->tick, 0);
XSETFASTINT (p->update_tick, 0);
- p->raw_status_low = Qnil;
- p->raw_status_high = Qnil;
+ p->pid = 0;
+ p->raw_status_new = 0;
p->status = Qrun;
p->mark = Fmake_marker ();
= (struct coding_system *) xmalloc (sizeof (struct coding_system));
setup_coding_system (p->encode_coding_system,
proc_encode_coding_system[outch]);
+ if (proc_encode_coding_system[outch]->eol_type == CODING_EOL_UNDECIDED)
+ proc_encode_coding_system[outch]->eol_type = system_eol_type;
}
\f
DEFUN ("processp", Fprocessp, Sprocessp, 1, 1, 0,
return proc;
}
+
+#ifdef SIGCHLD
+/* Fdelete_process promises to immediately forget about the process, but in
+ reality, Emacs needs to remember those processes until they have been
+ treated by sigchld_handler; otherwise this handler would consider the
+ process as being synchronous and say that the synchronous process is
+ dead. */
+static Lisp_Object deleted_pid_list;
+#endif
+
DEFUN ("delete-process", Fdelete_process, Sdelete_process, 1, 1, 0,
doc: /* Delete PROCESS: kill it and forget about it immediately.
PROCESS may be a process, a buffer, the name of a process or buffer, or
process = get_process (process);
p = XPROCESS (process);
- p->raw_status_low = Qnil;
- p->raw_status_high = Qnil;
+ p->raw_status_new = 0;
if (NETCONN1_P (p))
{
p->status = Fcons (Qexit, Fcons (make_number (0), Qnil));
}
else if (XINT (p->infd) >= 0)
{
- Fkill_process (process, Qnil);
- /* Do this now, since remove_process will make sigchld_handler do nothing. */
- p->status
- = Fcons (Qsignal, Fcons (make_number (SIGKILL), Qnil));
- XSETINT (p->tick, ++process_tick);
- status_notify (p);
+#ifdef SIGCHLD
+ Lisp_Object symbol;
+
+ /* No problem storing the pid here, as it is still in Vprocess_alist. */
+ deleted_pid_list = Fcons (make_fixnum_or_float (p->pid),
+ /* GC treated elements set to nil. */
+ Fdelq (Qnil, deleted_pid_list));
+ /* If the process has already signaled, remove it from the list. */
+ if (p->raw_status_new)
+ update_status (p);
+ symbol = p->status;
+ if (CONSP (p->status))
+ symbol = XCAR (p->status);
+ if (EQ (symbol, Qsignal) || EQ (symbol, Qexit))
+ Fdelete (make_fixnum_or_float (p->pid), deleted_pid_list);
+ else
+#endif
+ {
+ Fkill_process (process, Qnil);
+ /* Do this now, since remove_process will make sigchld_handler do nothing. */
+ p->status
+ = Fcons (Qsignal, Fcons (make_number (SIGKILL), Qnil));
+ XSETINT (p->tick, ++process_tick);
+ status_notify (p);
+ }
}
remove_process (process);
return Qnil;
return process;
p = XPROCESS (process);
- if (!NILP (p->raw_status_low))
+ if (p->raw_status_new)
update_status (p);
status = p->status;
if (CONSP (status))
register Lisp_Object process;
{
CHECK_PROCESS (process);
- if (!NILP (XPROCESS (process)->raw_status_low))
+ if (XPROCESS (process)->raw_status_new)
update_status (XPROCESS (process));
if (CONSP (XPROCESS (process)->status))
return XCAR (XCDR (XPROCESS (process)->status));
register Lisp_Object process;
{
CHECK_PROCESS (process);
- return XPROCESS (process)->pid;
+ return (XPROCESS (process)->pid
+ ? make_fixnum_or_float (XPROCESS (process)->pid)
+ : Qnil);
}
DEFUN ("process-name", Fprocess_name, Sprocess_name, 1, 1, 0,
Finsert (1, &p->name);
Findent_to (i_status, minspace);
- if (!NILP (p->raw_status_low))
+ if (p->raw_status_new)
update_status (p);
symbol = p->status;
if (CONSP (p->status))
#endif
/* Make the process marker point into the process buffer (if any). */
- if (!NILP (buffer))
+ if (BUFFERP (buffer))
set_marker_both (XPROCESS (proc)->mark, buffer,
BUF_ZV (XBUFFER (buffer)),
BUF_ZV_BYTE (XBUFFER (buffer)));
abort ();
/* Was PROC started successfully? */
- if (XINT (XPROCESS (proc)->pid) <= 0)
+ if (XPROCESS (proc)->pid <= 0)
remove_process (proc);
return Qnil;
in the table after this function has returned; if it does
it might cause call-process to hang and subsequent asynchronous
processes to get their return values scrambled. */
- XSETINT (XPROCESS (process)->pid, -1);
+ XPROCESS (process)->pid = -1;
BLOCK_INPUT;
else
{
/* vfork succeeded. */
- XSETFASTINT (XPROCESS (process)->pid, pid);
+ XPROCESS (process)->pid = pid;
#ifdef WINDOWSNT
register_child (pid, inchannel);
}
/* Convert an address object (vector or string) to an internal sockaddr.
- Format of address has already been validated by size_lisp_to_sockaddr. */
+
+ The address format has been basically validated by
+ get_lisp_to_sockaddr_size, but this does not mean FAMILY is valid;
+ it could have come from user data. So if FAMILY is not valid,
+ we return after zeroing *SA. */
static void
conv_lisp_to_sockaddr (family, address, sa, len)
register int i;
bzero (sa, len);
- sa->sa_family = family;
if (VECTORP (address))
{
i = XINT (p->contents[--len]);
sin->sin_port = htons (i);
cp = (unsigned char *)&sin->sin_addr;
+ sa->sa_family = family;
}
#ifdef AF_INET6
else if (family == AF_INET6)
int j = XFASTINT (p->contents[i]) & 0xffff;
ip6[i] = ntohs (j);
}
- return;
+ sa->sa_family = family;
}
#endif
+ return;
}
else if (STRINGP (address))
{
cp = SDATA (address);
for (i = 0; i < sizeof (sockun->sun_path) && *cp; i++)
sockun->sun_path[i] = *cp++;
+ sa->sa_family = family;
}
#endif
return;
tem = Fplist_get (contact, QCfamily);
if (NILP (tem))
{
-#ifdef HAVE_GETADDRINFO
+#if defined(HAVE_GETADDRINFO) && defined(AF_INET6)
family = AF_UNSPEC;
#else
family = AF_INET;
p->kill_without_query = Qt;
if ((tem = Fplist_get (contact, QCstop), !NILP (tem)))
p->command = Qt;
- p->pid = Qnil;
+ p->pid = 0;
XSETINT (p->infd, inch);
XSETINT (p->outfd, outch);
if (is_server && socktype == SOCK_STREAM)
p->status = Qlisten;
+ /* Make the process marker point into the process buffer (if any). */
+ if (BUFFERP (buffer))
+ set_marker_both (p->mark, buffer,
+ BUF_ZV (XBUFFER (buffer)),
+ BUF_ZV_BYTE (XBUFFER (buffer)));
+
#ifdef NON_BLOCKING_CONNECT
if (is_non_blocking_client)
{
#ifdef IFF_DYNAMIC
{ IFF_DYNAMIC, "dynamic" },
#endif
-#ifdef IFF_OACTIV
- { IFF_OACTIV, "oactiv" }, /* OpenBSD: transmission in progress */
+#ifdef IFF_OACTIVE
+ { IFF_OACTIVE, "oactive" }, /* OpenBSD: transmission in progress */
#endif
#ifdef IFF_SIMPLEX
{ IFF_SIMPLEX, "simplex" }, /* OpenBSD: can't hear own transmissions */
res = Fcons (elt, res);
elt = Qnil;
-#if defined(SIOCGIFNETMASK) && defined(ifr_netmask)
+#if defined(SIOCGIFNETMASK) && (defined(HAVE_STRUCT_IFREQ_IFR_NETMASK) || defined(HAVE_STRUCT_IFREQ_IFR_ADDR))
if (ioctl (s, SIOCGIFNETMASK, &rq) == 0)
{
any++;
+#ifdef HAVE_STRUCT_IFREQ_IFR_NETMASK
elt = conv_sockaddr_to_lisp (&rq.ifr_netmask, sizeof (rq.ifr_netmask));
+#else
+ elt = conv_sockaddr_to_lisp (&rq.ifr_addr, sizeof (rq.ifr_addr));
+#endif
}
#endif
res = Fcons (elt, res);
It is read into the process' buffers or given to their filter functions.
Non-nil arg PROCESS means do not return until some output has been received
from PROCESS.
-Non-nil second arg TIMEOUT and third arg TIMEOUT-MSECS are number of
-seconds and microseconds to wait; return after that much time whether
-or not there is input.
+
+Non-nil second arg SECONDS and third arg MILLISEC are number of
+seconds and milliseconds to wait; return after that much time whether
+or not there is input. If SECONDS is a floating point number,
+it specifies a fractional number of seconds to wait.
+
If optional fourth arg JUST-THIS-ONE is non-nil, only accept output
from PROCESS, suspending reading output from other processes.
If JUST-THIS-ONE is an integer, don't run any timers either.
Return non-nil iff we received any output before the timeout expired. */)
- (process, timeout, timeout_msecs, just_this_one)
- register Lisp_Object process, timeout, timeout_msecs, just_this_one;
+ (process, seconds, millisec, just_this_one)
+ register Lisp_Object process, seconds, millisec, just_this_one;
{
- int seconds;
- int useconds;
+ int secs, usecs = 0;
if (! NILP (process))
CHECK_PROCESS (process);
else
just_this_one = Qnil;
- if (! NILP (timeout_msecs))
+ if (!NILP (seconds))
{
- CHECK_NUMBER (timeout_msecs);
- useconds = XINT (timeout_msecs);
- if (!INTEGERP (timeout))
- XSETINT (timeout, 0);
-
- {
- int carry = useconds / 1000000;
-
- XSETINT (timeout, XINT (timeout) + carry);
- useconds -= carry * 1000000;
+ if (INTEGERP (seconds))
+ secs = XINT (seconds);
+ else if (FLOATP (seconds))
+ {
+ double timeout = XFLOAT_DATA (seconds);
+ secs = (int) timeout;
+ usecs = (int) ((timeout - (double) secs) * 1000000);
+ }
+ else
+ wrong_type_argument (Qnumberp, seconds);
- /* I think this clause is necessary because C doesn't
- guarantee a particular rounding direction for negative
- integers. */
- if (useconds < 0)
- {
- XSETINT (timeout, XINT (timeout) - 1);
- useconds += 1000000;
- }
- }
- }
- else
- useconds = 0;
+ if (INTEGERP (millisec))
+ {
+ int carry;
+ usecs += XINT (millisec) * 1000;
+ carry = usecs / 1000000;
+ secs += carry;
+ if ((usecs -= carry * 1000000) < 0)
+ {
+ secs--;
+ usecs += 1000000;
+ }
+ }
- if (! NILP (timeout))
- {
- CHECK_NUMBER (timeout);
- seconds = XINT (timeout);
- if (seconds < 0 || (seconds == 0 && useconds == 0))
- seconds = -1;
+ if (secs < 0 || (secs == 0 && usecs == 0))
+ secs = -1, usecs = 0;
}
else
- seconds = NILP (process) ? -1 : 0;
+ secs = NILP (process) ? -1 : 0;
return
- (wait_reading_process_output (seconds, useconds, 0, 0,
+ (wait_reading_process_output (secs, usecs, 0, 0,
Qnil,
!NILP (process) ? XPROCESS (process) : NULL,
NILP (just_this_one) ? 0 :
p->sentinel = ps->sentinel;
p->filter = ps->filter;
p->command = Qnil;
- p->pid = Qnil;
+ p->pid = 0;
XSETINT (p->infd, s);
XSETINT (p->outfd, s);
p->status = Qrun;
{
}
+/* Use a wrapper around select to work around a bug in gdb 5.3.
+ Normally, the wrapper is optimzed away by inlining.
+
+ If emacs is stopped inside select, the gdb backtrace doesn't
+ show the function which called select, so it is practically
+ impossible to step through wait_reading_process_output. */
+
+#ifndef select
+static INLINE int
+select_wrapper (n, rfd, wfd, xfd, tmo)
+ int n;
+ SELECT_TYPE *rfd, *wfd, *xfd;
+ EMACS_TIME *tmo;
+{
+ return select (n, rfd, wfd, xfd, tmo);
+}
+#define select select_wrapper
+#endif
+
/* Read and dispose of subprocess output while waiting for timeout to
elapse and/or keyboard input to be available.
/* Don't wait for output from a non-running process. Just
read whatever data has already been received. */
- if (wait_proc != 0 && !NILP (wait_proc->raw_status_low))
+ if (wait_proc && wait_proc->raw_status_new)
update_status (wait_proc);
- if (wait_proc != 0
+ if (wait_proc
&& ! EQ (wait_proc->status, Qrun)
&& ! EQ (wait_proc->status, Qconnect))
{
/* Preserve status of processes already terminated. */
XSETINT (XPROCESS (proc)->tick, ++process_tick);
deactivate_process (proc);
- if (!NILP (XPROCESS (proc)->raw_status_low))
+ if (XPROCESS (proc)->raw_status_new)
update_status (XPROCESS (proc));
if (EQ (XPROCESS (proc)->status, Qrun))
XPROCESS (proc)->status
p->encode_coding_system = coding->symbol;
setup_coding_system (coding->symbol,
proc_encode_coding_system[XINT (p->outfd)]);
+ if (proc_encode_coding_system[XINT (p->outfd)]->eol_type
+ == CODING_EOL_UNDECIDED)
+ proc_encode_coding_system[XINT (p->outfd)]->eol_type
+ = system_eol_type;
}
}
p->encode_coding_system = coding->symbol;
setup_coding_system (coding->symbol,
proc_encode_coding_system[XINT (p->outfd)]);
+ if (proc_encode_coding_system[XINT (p->outfd)]->eol_type
+ == CODING_EOL_UNDECIDED)
+ proc_encode_coding_system[XINT (p->outfd)]->eol_type
+ = system_eol_type;
}
}
carryover = nbytes - coding->consumed;
VMS_PROC_STUFF *vs, *get_vms_process_pointer();
#endif /* VMS */
- if (! NILP (p->raw_status_low))
+ if (p->raw_status_new)
update_status (p);
if (! EQ (p->status, Qrun))
error ("Process %s not running", SDATA (p->name));
sending a multibyte text, thus we must encode it by the
original coding system specified for the current process. */
setup_coding_system (p->encode_coding_system, coding);
+ if (coding->eol_type == CODING_EOL_UNDECIDED)
+ coding->eol_type = system_eol_type;
/* src_multibyte should be set to 1 _after_ a call to
setup_coding_system, since it resets src_multibyte to
zero. */
proc = process_sent_to;
p = XPROCESS (proc);
#endif
- p->raw_status_low = Qnil;
- p->raw_status_high = Qnil;
+ p->raw_status_new = 0;
p->status = Fcons (Qexit, Fcons (make_number (256), Qnil));
XSETINT (p->tick, ++process_tick);
deactivate_process (proc);
gid = emacs_get_tty_pgrp (p);
- if (gid == XFASTINT (p->pid))
+ if (gid == p->pid)
return Qnil;
return Qt;
}
/* If we are using pgrps, get a pgrp number and make it negative. */
if (NILP (current_group))
/* Send the signal to the shell's process group. */
- gid = XFASTINT (p->pid);
+ gid = p->pid;
else
{
#ifdef SIGNALS_VIA_CHARACTERS
if (gid == -1)
/* If we can't get the information, assume
the shell owns the tty. */
- gid = XFASTINT (p->pid);
+ gid = p->pid;
/* It is not clear whether anything really can set GID to -1.
Perhaps on some system one of those ioctls can or could do so.
#else /* ! defined (TIOCGPGRP ) */
/* Can't select pgrps on this system, so we know that
the child itself heads the pgrp. */
- gid = XFASTINT (p->pid);
+ gid = p->pid;
#endif /* ! defined (TIOCGPGRP ) */
/* If current_group is lambda, and the shell owns the terminal,
don't send any signal. */
- if (EQ (current_group, Qlambda) && gid == XFASTINT (p->pid))
+ if (EQ (current_group, Qlambda) && gid == p->pid)
return;
}
{
#ifdef SIGCONT
case SIGCONT:
- p->raw_status_low = Qnil;
- p->raw_status_high = Qnil;
+ p->raw_status_new = 0;
p->status = Qrun;
XSETINT (p->tick, ++process_tick);
if (!nomsg)
#endif
case SIGKILL:
#ifdef VMS
- sys$forcex (&(XFASTINT (p->pid)), 0, 1);
+ sys$forcex (&(p->pid), 0, 1);
whoosh:
#endif
flush_pending_output (XINT (p->infd));
obvious alternative. */
if (no_pgrp)
{
- kill (XFASTINT (p->pid), signo);
+ kill (p->pid, signo);
return;
}
}
else
{
- gid = - XFASTINT (p->pid);
+ gid = - p->pid;
kill (gid, signo);
}
#else /* ! defined (TIOCSIGSEND) */
(process, sigcode)
Lisp_Object process, sigcode;
{
- Lisp_Object pid;
+ pid_t pid;
if (INTEGERP (process))
{
- pid = process;
+ pid = XINT (process);
+ goto got_it;
+ }
+
+ if (FLOATP (process))
+ {
+ pid = (pid_t) XFLOAT (process);
goto got_it;
}
Lisp_Object tem;
if (tem = Fget_process (process), NILP (tem))
{
- pid = Fstring_to_number (process, make_number (10));
- if (XINT (pid) != 0)
+ pid = XINT (Fstring_to_number (process, make_number (10)));
+ if (pid > 0)
goto got_it;
}
process = tem;
CHECK_PROCESS (process);
pid = XPROCESS (process)->pid;
- if (!INTEGERP (pid) || XINT (pid) <= 0)
+ if (pid <= 0)
error ("Cannot signal process %s", SDATA (XPROCESS (process)->name));
got_it:
#undef handle_signal
- return make_number (kill (XINT (pid), XINT (sigcode)));
+ return make_number (kill (pid, XINT (sigcode)));
}
DEFUN ("process-send-eof", Fprocess_send_eof, Sprocess_send_eof, 0, 1, 0,
coding = proc_encode_coding_system[XINT (XPROCESS (proc)->outfd)];
/* Make sure the process is really alive. */
- if (! NILP (XPROCESS (proc)->raw_status_low))
+ if (XPROCESS (proc)->raw_status_new)
update_status (XPROCESS (proc));
if (! EQ (XPROCESS (proc)->status, Qrun))
error ("Process %s not running", SDATA (XPROCESS (proc)->name));
for communication with the subprocess, call shutdown to cause EOF.
(In some old system, shutdown to socketpair doesn't work.
Then we just can't win.) */
- if (NILP (XPROCESS (proc)->pid)
+ if (XPROCESS (proc)->pid == 0
|| XINT (XPROCESS (proc)->outfd) == XINT (XPROCESS (proc)->infd))
shutdown (XINT (XPROCESS (proc)->outfd), 1);
/* In case of socketpair, outfd == infd, so don't close it. */
emacs_close (XINT (XPROCESS (proc)->outfd));
#endif /* not HAVE_SHUTDOWN */
new_outfd = emacs_open (NULL_DEVICE, O_WRONLY, 0);
+ if (new_outfd < 0)
+ abort ();
old_outfd = XINT (XPROCESS (proc)->outfd);
if (!proc_encode_coding_system[new_outfd])
** Malloc WARNING: This should never call malloc either directly or
indirectly; if it does, that is a bug */
+#ifdef SIGCHLD
SIGTYPE
sigchld_handler (signo)
int signo;
/* Find the process that signaled us, and record its status. */
+ /* The process can have been deleted by Fdelete_process. */
+ tail = Fmember (make_fixnum_or_float (pid), deleted_pid_list);
+ if (!NILP (tail))
+ {
+ Fsetcar (tail, Qnil);
+ goto sigchld_end_of_loop;
+ }
+
+ /* Otherwise, if it is asynchronous, it is in Vprocess_alist. */
p = 0;
for (tail = Vprocess_alist; GC_CONSP (tail); tail = XCDR (tail))
{
proc = XCDR (XCAR (tail));
p = XPROCESS (proc);
- if (GC_EQ (p->childp, Qt) && XINT (p->pid) == pid)
+ if (GC_EQ (p->childp, Qt) && p->pid == pid)
break;
p = 0;
}
{
proc = XCDR (XCAR (tail));
p = XPROCESS (proc);
- if (GC_INTEGERP (p->pid) && XINT (p->pid) == -1)
+ if (p->pid == -1)
break;
p = 0;
}
XSETINT (p->tick, ++process_tick);
u.wt = w;
- XSETINT (p->raw_status_low, u.i & 0xffff);
- XSETINT (p->raw_status_high, u.i >> 16);
+ p->raw_status = u.i;
+ p->raw_status_new = 1;
/* If process has terminated, stop waiting for its output. */
if ((WIFSIGNALED (w) || WIFEXITED (w))
EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0);
}
- /* There was no asynchronous process found for that id. Check
- if we have a synchronous process. */
+ /* There was no asynchronous process found for that pid: we have
+ a synchronous process. */
else
{
synch_process_alive = 0;
EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0);
}
+ sigchld_end_of_loop:
+ ;
+
/* On some systems, we must return right away.
If any more processes want to signal us, we will
get another signal.
#endif /* USG, but not HPUX with WNOHANG */
}
}
+#endif /* SIGCHLD */
\f
static Lisp_Object
buffer = p->buffer;
/* Get the text to use for the message. */
- if (!NILP (p->raw_status_low))
+ if (p->raw_status_new)
update_status (p);
msg = status_message (p);
FD_SET (0, &input_wait_mask);
Vprocess_alist = Qnil;
+#ifdef SIGCHLD
+ deleted_pid_list = Qnil;
+#endif
for (i = 0; i < MAXDESC; i++)
{
chan_process[i] = Qnil;
staticpro (&Qlast_nonmenu_event);
staticpro (&Vprocess_alist);
+#ifdef SIGCHLD
+ staticpro (&deleted_pid_list);
+#endif
DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
doc: /* *Non-nil means delete processes immediately when they exit.
is read in very small blocks, potentially resulting in very poor performance.
This behavior can be remedied to some extent by setting this variable to a
non-nil value, as it will automatically delay reading from such processes, to
-allowing them to produce more output before Emacs tries to read it.
+allow them to produce more output before Emacs tries to read it.
If the value is t, the delay is reset after each write to the process; any other
non-nil value means that the delay is not reset on write.
The variable takes effect when `start-process' is called. */);