/* Asynchronous subprocess control for GNU Emacs.
Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995,
1996, 1998, 1999, 2001, 2002, 2003, 2004,
- 2005, 2006 Free Software Foundation, Inc.
+ 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#define POLL_FOR_INPUT
#endif
+static Lisp_Object get_process ();
+static void exec_sentinel ();
+
+extern EMACS_TIME timer_check ();
+extern int timers_run;
+\f
/* Mask of bits indicating the descriptors that we wait for input on. */
static SELECT_TYPE input_wait_mask;
#define DATAGRAM_CONN_P(proc) (0)
#endif
-static Lisp_Object get_process ();
-static void exec_sentinel ();
-
-extern EMACS_TIME timer_check ();
-extern int timers_run;
-
/* Maximum number of bytes to send to a pty without an eof. */
static int pty_max_bytes;
+/* Nonzero means don't run process sentinels. This is used
+ when exiting. */
+int inhibit_sentinels;
+
#ifdef HAVE_PTYS
#ifdef HAVE_PTY_H
#include <pty.h>
{
#ifdef SIGCHLD
Lisp_Object symbol;
+ /* Assignment to EMACS_INT stops GCC whining about limited range
+ of data type. */
+ EMACS_INT pid = p->pid;
/* No problem storing the pid here, as it is still in Vprocess_alist. */
- deleted_pid_list = Fcons (make_fixnum_or_float (p->pid),
+ deleted_pid_list = Fcons (make_fixnum_or_float (pid),
/* GC treated elements set to nil. */
Fdelq (Qnil, deleted_pid_list));
/* If the process has already signaled, remove it from the list. */
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);
+ deleted_pid_list
+ = Fdelete (make_fixnum_or_float (pid), deleted_pid_list);
else
#endif
{
(process)
register Lisp_Object process;
{
+ /* Assignment to EMACS_INT stops GCC whining about limited range of
+ data type. */
+ EMACS_INT pid;
+
CHECK_PROCESS (process);
- return (XPROCESS (process)->pid
- ? make_fixnum_or_float (XPROCESS (process)->pid)
- : Qnil);
+ pid = XPROCESS (process)->pid;
+ return (pid ? make_fixnum_or_float (pid) : Qnil);
}
DEFUN ("process-name", Fprocess_name, Sprocess_name, 1, 1, 0,
if (VECTORP (address)) /* AF_INET or AF_INET6 */
{
register struct Lisp_Vector *p = XVECTOR (address);
- Lisp_Object args[6];
+ Lisp_Object args[10];
int nargs, i;
if (p->size == 4 || (p->size == 5 && !NILP (omit_port)))
args[0] = build_string ("<Family %d>");
args[1] = Fcar (address);
return Fformat (2, args);
-
}
return Qnil;
register struct Lisp_Process *p;
char tembuf[300];
int w_proc, w_buffer, w_tty;
+ int exited = 0;
Lisp_Object i_status, i_buffer, i_tty, i_command;
w_proc = 4; /* Proc */
}
}
- if (EQ (symbol, Qsignal) || EQ (symbol, Qexit))
- remove_process (proc);
+ if (EQ (symbol, Qsignal) || EQ (symbol, Qexit) || EQ (symbol, Qclosed))
+ exited++;
Findent_to (i_buffer, minspace);
if (NILP (p->buffer))
insert_string ("\n");
}
}
+ if (exited)
+ status_notify (NULL);
return Qnil;
}
char **new_argv;
Lisp_Object current_dir;
{
- int pid, inchannel, outchannel;
+ int inchannel, outchannel;
+ pid_t pid;
int sv[2];
#ifdef POSIX_SIGNALS
sigset_t procmask;
/* Make QCaddress an alias for :local (server) or :remote (client). */
QCaddress = is_server ? QClocal : QCremote;
- /* :wait BOOL */
+ /* :nowait BOOL */
if (!is_server && socktype == SOCK_STREAM
&& (tem = Fplist_get (contact, QCnowait), !NILP (tem)))
{
#endif
}
+ immediate_quit = 0;
+
#ifdef HAVE_GETADDRINFO
if (res != &ai)
- freeaddrinfo (res);
+ {
+ BLOCK_INPUT;
+ freeaddrinfo (res);
+ UNBLOCK_INPUT;
+ }
#endif
- immediate_quit = 0;
-
/* Discard the unwind protect for closing S, if any. */
specpdl_ptr = specpdl + count1;
when not inside wait_reading_process_output. */
static int waiting_for_user_input_p;
+static Lisp_Object
+wait_reading_process_output_unwind (data)
+ Lisp_Object data;
+{
+ waiting_for_user_input_p = XINT (data);
+ return Qnil;
+}
+
/* This is here so breakpoints can be put on it. */
static void
wait_reading_process_output_1 ()
EMACS_TIME timeout, end_time;
int wait_channel = -1;
int got_some_input = 0;
- /* Either nil or a cons cell, the car of which is of interest and
- may be changed outside of this routine. */
- int saved_waiting_for_user_input_p = waiting_for_user_input_p;
+ int count = SPECPDL_INDEX ();
FD_ZERO (&Available);
#ifdef NON_BLOCKING_CONNECT
if (wait_proc != NULL)
wait_channel = XINT (wait_proc->infd);
+ record_unwind_protect (wait_reading_process_output_unwind,
+ make_number (waiting_for_user_input_p));
waiting_for_user_input_p = read_kbd;
/* Since we may need to wait several times,
} /* end for each file descriptor */
} /* end while exit conditions not met */
- waiting_for_user_input_p = saved_waiting_for_user_input_p;
+ unbind_to (count, Qnil);
/* If calling from keyboard input, do not quit
since we want to return C-g as an input character.
}
carryover = nbytes - coding->consumed;
+ if (carryover < 0)
+ abort ();
+
if (SCHARS (p->decoding_buf) < carryover)
p->decoding_buf = make_uninit_string (carryover);
bcopy (chars + coding->consumed, SDATA (p->decoding_buf),
}
}
carryover = nbytes - coding->consumed;
+ if (carryover < 0)
+ abort ();
+
if (SCHARS (p->decoding_buf) < carryover)
p->decoding_buf = make_uninit_string (carryover);
bcopy (chars + coding->consumed, SDATA (p->decoding_buf),
carryover);
XSETINT (p->decoding_carryover, carryover);
+
/* Adjust the multibyteness of TEXT to that of the buffer. */
if (NILP (current_buffer->enable_multibyte_characters)
!= ! STRING_MULTIBYTE (text))
UNGCPRO;
}
+static Lisp_Object
+send_process_object_unwind (buf)
+ Lisp_Object buf;
+{
+ Lisp_Object tembuf;
+
+ if (XBUFFER (buf) == current_buffer)
+ return Qnil;
+ tembuf = Fcurrent_buffer ();
+ Fset_buffer (buf);
+ Fkill_buffer (tembuf);
+ return Qnil;
+}
+
+/* Send current contents of region between START and END to PROC.
+ If START is a string, send it instead.
+ This function can evaluate Lisp code and can garbage collect. */
+
+static void
+send_process_object (proc, start, end)
+ Lisp_Object proc, start, end;
+{
+ int count = SPECPDL_INDEX ();
+ Lisp_Object object = STRINGP (start) ? start : Fcurrent_buffer ();
+ struct buffer *given_buffer = current_buffer;
+ unsigned char *buf;
+ int len;
+
+ record_unwind_protect (send_process_object_unwind, Fcurrent_buffer ());
+
+ if (STRINGP (object) ? STRING_MULTIBYTE (object)
+ : ! NILP (XBUFFER (object)->enable_multibyte_characters))
+ {
+ struct Lisp_Process *p = XPROCESS (proc);
+ struct coding_system *coding;
+
+ if (p->raw_status_new)
+ update_status (p);
+ if (! EQ (p->status, Qrun))
+ error ("Process %s not running", SDATA (p->name));
+ if (XINT (p->outfd) < 0)
+ error ("Output file descriptor of %s is closed", SDATA (p->name));
+
+ coding = proc_encode_coding_system[XINT (p->outfd)];
+ if (! EQ (coding->symbol, p->encode_coding_system))
+ /* The coding system for encoding was changed to raw-text
+ because we sent a unibyte text previously. Now we are
+ 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 (! NILP (coding->pre_write_conversion))
+ {
+ struct gcpro gcpro1, gcpro2;
+
+ GCPRO2 (proc, object);
+ call2 (coding->pre_write_conversion, start, end);
+ UNGCPRO;
+ if (given_buffer != current_buffer)
+ {
+ start = make_number (BEGV), end = make_number (ZV);
+ object = Fcurrent_buffer ();
+ }
+ }
+ }
+
+ if (BUFFERP (object))
+ {
+ EMACS_INT start_byte;
+
+ if (XINT (start) < GPT && XINT (end) > GPT)
+ move_gap (XINT (end));
+ start_byte = CHAR_TO_BYTE (XINT (start));
+ buf = BYTE_POS_ADDR (start_byte);
+ len = CHAR_TO_BYTE (XINT (end)) - start_byte;
+ }
+ else
+ {
+ buf = SDATA (object);
+ len = SBYTES (object);
+ }
+ send_process (proc, buf, len, object);
+
+ unbind_to (count, Qnil);
+}
+
DEFUN ("process-send-region", Fprocess_send_region, Sprocess_send_region,
3, 3, 0,
doc: /* Send current contents of region as input to PROCESS.
Lisp_Object process, start, end;
{
Lisp_Object proc;
- int start1, end1;
proc = get_process (process);
validate_region (&start, &end);
-
- if (XINT (start) < GPT && XINT (end) > GPT)
- move_gap (XINT (start));
-
- start1 = CHAR_TO_BYTE (XINT (start));
- end1 = CHAR_TO_BYTE (XINT (end));
- send_process (proc, BYTE_POS_ADDR (start1), end1 - start1,
- Fcurrent_buffer ());
-
+ send_process_object (proc, start, end);
return Qnil;
}
Lisp_Object proc;
CHECK_STRING (string);
proc = get_process (process);
- send_process (proc, SDATA (string),
- SBYTES (string), string);
+ send_process_object (proc, string, Qnil);
return Qnil;
}
\f
DEFUN ("signal-process", Fsignal_process, Ssignal_process,
2, 2, "sProcess (name or number): \nnSignal code: ",
doc: /* Send PROCESS the signal with code SIGCODE.
-PROCESS may also be an integer specifying the process id of the
+PROCESS may also be a number specifying the process id of the
process to signal; in this case, the process need not be a child of
this Emacs.
SIGCODE may be an integer, or a symbol whose name is a signal name. */)
if (FLOATP (process))
{
- pid = (pid_t) XFLOAT (process);
+ pid = (pid_t) XFLOAT_DATA (process);
goto got_it;
}
got_it:
-#define handle_signal(NAME, VALUE) \
- else if (!strcmp (name, NAME)) \
+#define parse_signal(NAME, VALUE) \
+ else if (!xstricmp (name, NAME)) \
XSETINT (sigcode, VALUE)
if (INTEGERP (sigcode))
CHECK_SYMBOL (sigcode);
name = SDATA (SYMBOL_NAME (sigcode));
- if (!strncmp(name, "SIG", 3))
+ if (!strncmp(name, "SIG", 3) || !strncmp(name, "sig", 3))
name += 3;
if (0)
;
+#ifdef SIGUSR1
+ parse_signal ("usr1", SIGUSR1);
+#endif
+#ifdef SIGUSR2
+ parse_signal ("usr2", SIGUSR2);
+#endif
+#ifdef SIGTERM
+ parse_signal ("term", SIGTERM);
+#endif
#ifdef SIGHUP
- handle_signal ("HUP", SIGHUP);
+ parse_signal ("hup", SIGHUP);
#endif
#ifdef SIGINT
- handle_signal ("INT", SIGINT);
+ parse_signal ("int", SIGINT);
#endif
#ifdef SIGQUIT
- handle_signal ("QUIT", SIGQUIT);
+ parse_signal ("quit", SIGQUIT);
#endif
#ifdef SIGILL
- handle_signal ("ILL", SIGILL);
+ parse_signal ("ill", SIGILL);
#endif
#ifdef SIGABRT
- handle_signal ("ABRT", SIGABRT);
+ parse_signal ("abrt", SIGABRT);
#endif
#ifdef SIGEMT
- handle_signal ("EMT", SIGEMT);
+ parse_signal ("emt", SIGEMT);
#endif
#ifdef SIGKILL
- handle_signal ("KILL", SIGKILL);
+ parse_signal ("kill", SIGKILL);
#endif
#ifdef SIGFPE
- handle_signal ("FPE", SIGFPE);
+ parse_signal ("fpe", SIGFPE);
#endif
#ifdef SIGBUS
- handle_signal ("BUS", SIGBUS);
+ parse_signal ("bus", SIGBUS);
#endif
#ifdef SIGSEGV
- handle_signal ("SEGV", SIGSEGV);
+ parse_signal ("segv", SIGSEGV);
#endif
#ifdef SIGSYS
- handle_signal ("SYS", SIGSYS);
+ parse_signal ("sys", SIGSYS);
#endif
#ifdef SIGPIPE
- handle_signal ("PIPE", SIGPIPE);
+ parse_signal ("pipe", SIGPIPE);
#endif
#ifdef SIGALRM
- handle_signal ("ALRM", SIGALRM);
-#endif
-#ifdef SIGTERM
- handle_signal ("TERM", SIGTERM);
+ parse_signal ("alrm", SIGALRM);
#endif
#ifdef SIGURG
- handle_signal ("URG", SIGURG);
+ parse_signal ("urg", SIGURG);
#endif
#ifdef SIGSTOP
- handle_signal ("STOP", SIGSTOP);
+ parse_signal ("stop", SIGSTOP);
#endif
#ifdef SIGTSTP
- handle_signal ("TSTP", SIGTSTP);
+ parse_signal ("tstp", SIGTSTP);
#endif
#ifdef SIGCONT
- handle_signal ("CONT", SIGCONT);
+ parse_signal ("cont", SIGCONT);
#endif
#ifdef SIGCHLD
- handle_signal ("CHLD", SIGCHLD);
+ parse_signal ("chld", SIGCHLD);
#endif
#ifdef SIGTTIN
- handle_signal ("TTIN", SIGTTIN);
+ parse_signal ("ttin", SIGTTIN);
#endif
#ifdef SIGTTOU
- handle_signal ("TTOU", SIGTTOU);
+ parse_signal ("ttou", SIGTTOU);
#endif
#ifdef SIGIO
- handle_signal ("IO", SIGIO);
+ parse_signal ("io", SIGIO);
#endif
#ifdef SIGXCPU
- handle_signal ("XCPU", SIGXCPU);
+ parse_signal ("xcpu", SIGXCPU);
#endif
#ifdef SIGXFSZ
- handle_signal ("XFSZ", SIGXFSZ);
+ parse_signal ("xfsz", SIGXFSZ);
#endif
#ifdef SIGVTALRM
- handle_signal ("VTALRM", SIGVTALRM);
+ parse_signal ("vtalrm", SIGVTALRM);
#endif
#ifdef SIGPROF
- handle_signal ("PROF", SIGPROF);
+ parse_signal ("prof", SIGPROF);
#endif
#ifdef SIGWINCH
- handle_signal ("WINCH", SIGWINCH);
+ parse_signal ("winch", SIGWINCH);
#endif
#ifdef SIGINFO
- handle_signal ("INFO", SIGINFO);
-#endif
-#ifdef SIGUSR1
- handle_signal ("USR1", SIGUSR1);
-#endif
-#ifdef SIGUSR2
- handle_signal ("USR2", SIGUSR2);
+ parse_signal ("info", SIGINFO);
#endif
else
error ("Undefined signal name %s", name);
}
-#undef handle_signal
+#undef parse_signal
return make_number (kill (pid, XINT (sigcode)));
}
while (1)
{
- register int pid;
+ pid_t pid;
WAITTYPE w;
Lisp_Object tail;
#endif /* no WUNTRACED */
/* Keep trying to get a status until we get a definitive result. */
do
- {
+ {
+ /* For some reason, this sleep() prevents Emacs from sending
+ loadavg to 5-8(!) for ~10 seconds.
+ See http://thread.gmane.org/gmane.emacs.devel/67722 or
+ http://www.google.com/search?q=busyloop+in+sigchld_handler */
+ usleep (1000);
errno = 0;
pid = wait3 (&w, WNOHANG | WUNTRACED, 0);
}
/* 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))
+ for (tail = deleted_pid_list; GC_CONSP (tail); tail = XCDR (tail))
{
- Fsetcar (tail, Qnil);
- goto sigchld_end_of_loop;
+ Lisp_Object xpid = XCAR (tail);
+ if ((GC_INTEGERP (xpid) && pid == (pid_t) XINT (xpid))
+ || (GC_FLOATP (xpid) && pid == (pid_t) XFLOAT_DATA (xpid)))
+ {
+ XSETCAR (tail, Qnil);
+ goto sigchld_end_of_loop;
+ }
}
/* Otherwise, if it is asynchronous, it is in Vprocess_alist. */
int outer_running_asynch_code = running_asynch_code;
int waiting = waiting_for_user_input_p;
+ if (inhibit_sentinels)
+ return;
+
/* No need to gcpro these, because all we do with them later
is test them for EQness, and none of them should be a string. */
odeactivate = Vdeactivate_mark;
{
register int i;
+ inhibit_sentinels = 0;
+
#ifdef SIGCHLD
#ifndef CANNOT_DUMP
if (! noninteractive || initialized)
DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
doc: /* *Non-nil means delete processes immediately when they exit.
-nil means don't delete them until `list-processes' is run. */);
+A value of nil means don't delete them until `list-processes' is run. */);
delete_exited_processes = 1;