This is the mail archive of the guile@cygnus.com mailing list for the guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: system primitive and signals, process groups, etc.



[Probably you've figured this all out now on your own, but...]

> guile
> guile> (system "xterm &")
> guile> [Hit Ctrl-C]
> 
> --> the xterm dies -- apparently because the shell gets a SIGINT and 
> the shell terminates thus causing the xterm to exit.  But:
> 
> guile
> guile> (system "xlogo &")
> guile> [Hit Ctrl-C]
> 
> --> xlogo lives on.

Here's what's going on.  Both xlogo and xterm are in the same process
group as Guile.  All signals generated from the terminal --- things like
SIGINT (usually C-c), SIGTSTP (usually C-z), SIGQUIT (usually C-\) ---
get sent to the terminal's current process group.

So when you hit C-c, guile, xterm, and xlogo all get SIGINT.  However,
as you can verify by sending these signals to the processes
individually by hand from another window, Guile handles SIGINT, xlogo
ignores it, and xterm exits.

SCWM is really acting like a little shell.  I think it should put the
programs it spawns in their own process groups.  You may need
something like this:

(define (background-system command)
  (let ((child-pid (primitive-fork)))
    (if (zero? child-pid)

	;; Okay, we're the child process.  We need to catch any and
	;; all errors and exit, or else we'll end up with two Guile
	;; repls trying to read from the same terminal.
	(begin
	  (catch #t
		 (lambda ()
		   
		   ;; Put ourselves in our own process group.
		   (setpgid (getpid) (getpid))
		      
		   ;; Try to execute the user's command.
		   (execl "/bin/sh" "sh" "-c" command))

		 (lambda args #f))

	  ;; If we return from the exec for any reason, it means it failed.
	  (quit 1))

	;; Okay, we're the parent process.  Return the child pid, in
	;; case we want to wait for it at some point in the future.
	child-pid)))

So now:

    guile> (background-system "xterm")
    3489
    guile> (background-system "xlogo")
    3515
    guile> ERROR: User interrupt
    ABORT: (signal)
    guile> ERROR: User interrupt
    ABORT: (signal)
    guile> 

Both xterm and xlogo remain live.

Note that you do want to wait for those processes periodically:

;;; I quit the xterm:
guile> (waitpid -1 WNOHANG)
(3489 . 0)  ;; pid and exit status

;;; I kill the xlogo's X connection, and then:
guile> (waitpid -1 WNOHANG)
(3515 . 256) ;; pid and a non-zero exit status

;;; What does "256" mean?
guile> (status:exit-val 256)
1

;;; Try waiting again, even though no children have died:
guile> (waitpid -1 WNOHANG)
ERROR: In procedure waitpid in expression (waitpid -1 WNOHANG):
ERROR: No child processes
ABORT: (system-error)
guile>

The error handling in background-system should be improved: if the
child process gets an error, it should print that to its stderr, not
swallow it.  Otherwise, you could get pretty frustrated...