Can a subprocess started by `start-process` outlive the parent emacs process? - asynchronous

I am writing some code in Emacs Lisp where I want to start a subprocess using start-process or a similar function. However, when the parent emacs process exits, I don't want the subprocess to exit. However, it seems that exiting the parent emacs process always kills all the subprocesses as well. The following code snippet demonstrates this:
(require 'async)
(async-sandbox
(lambda ()
(require 'package)
(package-initialize)
(require 'async)
(shell-command "{ echo -n 'SPAWNING: '; date; } > ~/temp/ASYNC_LOG")
(start-process-shell-command "subproc" nil
"{ echo -n 'STARTED: '; date; } >> ~/temp/ASYNC_LOG;
sleep 5;
{ echo -n 'FINISHED: '; date; } >> ~/temp/ASYNC_LOG;")
(shell-command "{ echo -n 'SPAWNED: '; date; } >> ~/temp/ASYNC_LOG")
(shell-command "sleep 2")
(shell-command "{ echo -n 'FINISHED WAITING: '; date; } >> ~/temp/ASYNC_LOG")
))
This code spawns one emacs process synchronously (async-sandbox (lambda () ...) so that we can quit that process to trigger the problem. That process then spawns a subprocess asynchronously (start-process-shell-command ...). The parent process sleeps for 2 seconds, while the subprocess sleeps for 5, so the parent process will exit first. When I run this code, I never see the "FINISHED" line in the log file, indicating that the subprocess is killed after 2 seconds. If I change the parent to wait for 7 seconds, then I see the FINISHED line in the output.
So is there any similar way to start a subprocess so that it won't be killed when its parent exits?

Here's how I start stuff from dired:
(require 'dired-aux)
(setq dired-guess-shell-alist-user
'(("\\.pdf\\'" "evince")
("\\.eps\\'" "evince")
("\\.jpe?g\\'" "eog")
("\\.png\\'" "eog")
("\\.gif\\'" "eog")
("\\.tex\\'" "pdflatex" "latex")
("\\.\\(?:mp4\\|mkv\\|avi\\|flv\\)\\'" "vlc")))
(defvar dired-filelist-cmd
'(("vlc" "-L")))
(defun dired-start-process (cmd &optional file-list)
(interactive
(let ((files (dired-get-marked-files t current-prefix-arg)))
(list
(dired-read-shell-command "& on %s: " current-prefix-arg files)
files)))
(apply
#'start-process
(list cmd nil shell-file-name shell-command-switch
(format "nohup 1>/dev/null 2>/dev/null %s \"%s\""
(if (> (length file-list) 1)
(format "%s %s"
cmd
(cadr (assoc cmd dired-filelist-cmd)))
cmd)
(mapconcat #'expand-file-name file-list "\" \"")))))

What Emacs does upon termination is to send a signal to its spawned processes (I assume they are those present in process-list). This behavior is hardcoded in Emacs C code (you could try to hack process-list removing the process you want to outlive Emacs, but I am not sure about the side effects of that; possibly they will be ugly)
You can find out what signal Emacs sends easily (just write a signal handler for one of your processes). I would guess it is SIGHUP, so the processes know that connection to the user (Emacs) has been lost.
What you can do is to make your process to handle SIGHUP in such a way it does not die, by adding a handler for that signal for instance. If you have zero control over that process code, you may wrap it with a "nohup" (this is what #abo-abo is basically doing; see abo-abo other answer for implementation details)

Try using call-process-shell-command with the destination argument set to 0.
From the documentation of call-process:
The argument destination says where to put the process output. Here are the possibilities:
…
0
Discard the output, and return nil immediately without waiting for the subprocess to finish.
In this case, the process is not truly synchronous, since it can run in parallel with Emacs; but you can think of it as synchronous in that Emacs is essentially finished with the subprocess as soon as this function returns.
MS-DOS doesn’t support asynchronous subprocesses, so this option doesn’t work there.
(From an answer by dalanicolai on https://emacs.stackexchange.com/questions/22363/possible-to-detach-a-child-process/65040#65040)

Related

Common lisp reading a gzipped stream line by line

I am currently dealing with a problem, where I have to read a zipped file line by line, and further on process each line and do something with it.
I managed to read from stdin using the following code:
(defun process ()
(princ (split-sequence:split-sequence #\Space (read-line))))
(defun main (args)
(process))
*this will be a command line tool
Where I ran it as:
cat file.txt | ./executable
this works fine, but it prints only the first line. I assume I must insert some form of loop in the first part, yet I am not sure how this is to be done.
Thank you for any help!
I solved this using:
(loop for line = (read-line) ; stream, no error, :eof value
until (eq line :eof)
do (princ line))

How to stop current execution process in ESS when C-c C-c is unresponsive?

I'm handling a datatable with a big amount of text in its fields and when, by mistake, I call a command that starts to print it causes R to freeze or to slowly print everything, I then have to kill emacs and resetup all my windows and buffers. This because during the printing process the command C-c C-c is unresponsive.
Do you knnow how to proceed to handle this without killing the whole working setup ?
You could kill just the ess process with something like,
(defun ess-abort ()
(interactive)
(kill-process (ess-get-process)))
(define-key ess-mode-map (kbd "C-c C-a") 'ess-abort)
(define-key inferior-ess-mode-map (kbd "C-c C-a") 'ess-abort)
eg, in R repl,
library(ggplot2)
toString(diamonds)
followed by C-c C-a. Haven't tried it on Windows however.

Emacs ESS: pipe output from R REPL into buffer

I want to have the ability to execute statements on R's REPL with the option to pipe it to a buffer so I can quickly refer back to it later.
To run a shell command and output to *shell command buffer* I can use M-! as per this question. What would the equivalent be for R's REPL without resorting to write.csv()?
You can use ess-command from ess-inf to redirect the output to another buffer. An example could look like the following,
(defun redirect-ess-output (command &optional buffer process)
(interactive (list (read-from-minibuffer "Command: ")))
(let ((buff (get-buffer-create (or buffer "*r-output*")))
;; 'ess-get-process' defaults to process local to current
;; buffer, so to call from anywhere default to "R"
(proc (ess-get-process (or process "R"))))
;; send a trailing newline to process
(unless (string-match-p "\n$" command)
(setq command (concat command "\n")))
(ess-command command buff 'sleep nil nil proc)
(with-current-buffer buff
;; process stuff
(pop-to-buffer buff))))

Sequentially Run Programs in Unix

I have several programs that need to be ran in a certain order (p1 then p2 then p3 then p4).
Normally I would simply make a simple script or type p1 && p2 && p3 && p4.
However, these programs to not exit correctly. I only know it is finished successfully when "Success" is printed. Currently, I SIGINT once I see "Success" or "Fail" and then manually run the next program if it's "Success".
Is there a simpler way to sequentially execute p1, p2, p3, p4 with less human intervention?
Edit: Currently using ksh, but I wouldn't mind knowing the other ones too.
In bash, you can pipe the command to grep looking for 'Success', then rely on grep's result code. The trick to that is wrapping the whole expression in curly braces to get an inline sub-shell. Like so:
$ cat foo.sh
#!/bin/bash
[ 0 -eq $(( $RANDOM %2 )) ] && echo 'Success' || echo 'Failure'
exit 0
$ { ./foo.sh | grep -q 'Success'; } && ls || df
The part inside the curly braces ({}) returns 0 if "Success" is in the output, otherwise 1, as if the foo.sh command had done so itself. More details on that technique.
I've not used ksh in a long while, but I suspect there is a similar construction.
I'm also new to linux programming, but I found something that might be helpful for you. Have you tried using the 'wait' command?
from this answer on stackexchange:
sleep 1 &
PID1=$!
sleep 2 &
PID2=$!
wait $PID1
echo PID1 has ended.
wait
echo All background processes have exited.
I haven't tested it myself, but it looks like what you described in your question.
all the answers so far would work fine if your programs would actually terminate.
here is a couple ideas you can use look through documentation for more details.
1st - option would be to modify your programs to have them terminate after printing the result message by returning a success code.
2nd - if not possible use forks.
write a main where you make a fork each time you want to execute a program.
in the child process use dup2 to have the process' output in a file of your choice.
in the main keep checking the content of said file until you get something and compare it with either success or failure.
-empty the file.
then you can make another fork and execute the next program.
repeat the same operation again.
bear in mind that execute is a command that replaces the code of the process it is executed in with the code of the file passed as a parameter so make the dup2 call first.
When your program returns Success or Fail and continues running, you should kill it as soon as the string passes.
Make a function like
function startp {
prog=$1
./${prog} | while read -r line; do
case "${line}" in
"Success")
echo OK
mykill $prog
exit 0
;;
"Fail")
echo NOK
mykill $prog
exit 1
;;
*) echo "${line}"
;;
esac
done
exit 2
}
You need to add a mykill function that looks for the px program and kills it (xargs is nice for it).
Call the function like
startp p1 && startp p2 && startp p3

Make tcsh wait until specific background job ends + alert me

What "nonblocking" command makes tcsh wait until a specific background
task completes and then "alerts" me by running a command of my choosing?
I want "wait %3 && xmessage job completed &" to wait until background
job [3] is finished and then xmessage me "job completed", but want
this command itself to return immediately, not "block" the terminal.
Obviously, my syntax above doesn't work. What does?
I've written a Perl program that can do this, but surely tcsh can do
it natively?
You may be able to do something like (untested):
while (! $?)
kill -s 0 $!
sleep 1
end
Or take a look at the notify command. I'm not sure if it would do what you want.

Categories

Resources