0

Is there a way to find out the pid of an emacs subprocess started with call-process?

I realize that the return value of start-process is precisely its pid but I would like to know the pid of a process created with call-process instead.

I know that, after a process has started, I can get information about it using the utility ps, but I'd like to avoid parsing the output of ps just to know the pid.

Ruy
  • 787
  • 4
  • 11
  • I don't see an easy way to do what you want: my impression is that `call-process` is used when you want to run something and either wait for it to finish (in which case you can check exit status) or let it go async and forget about it. It does not give you any handles to manipulate the process. You'll have to use some of the higher level process primitives for that. But it is only an impression, so maybe I'm missing something. – NickD Jun 07 '21 at 13:43
  • Dear Nick, thanks for weighing in! I fully agree with you regarding the intended use of `call-process` (especially with the parameter DESTINATION set to 0). The trouble I'm having is that the alternative, namely `start-process`, shuts down when emacs finishes as discussed in my previous question https://emacs.stackexchange.com/questions/65090/how-to-start-a-persistent-asynchronous-process-trough-emacs Should you be able to figure out a way to keep a process started by `start-process` running after emacs finishes (i.e. to answer my other question), it would fully solve my problem! – Ruy Jun 07 '21 at 17:08

1 Answers1

1

Here's a somewhat silly implementation of a function that does a call-process and returns its pid (sort-of):

(defun call-process-pid ()
  (let (l1 l2)
    (setq l1 (list-system-processes))
    (call-process "sleep" nil 0 nil "60")
    (setq l2 (list-system-processes))
    (cl-set-difference l2 l1)))

It's a somewhat cleaner way of doing a ps before and after to find out what process(es) got added.

The limitation is that between the first and second calls to list-system-processes, a bunch of processes may have been created, so the set difference will have more than one entry: AFAIK, there is no way to know which one is "your" process without looking at each one (e.g. with process-attributes to find out the command that was run). It may also happen that your command runs to completion before the second list-system-processes, in which case it will not appear at all - but that's probably OK for your intended use.

There are ways to daemonize a subprocess: that can be easily done from a C program (Stevens' "Advanced Programming in the Unix environment" has examples, but googling "daemonize Unix" should provide plenty). I'm not sure whether you can do the equivalent from within Emacs, but you don't have to: you can use nohup to prevent the program from responding to SIGHUP, so instead of (call-process "command" nil 0 nil args...), you can do (call-process "nohup" nil 0 nil "command" args...). I have not tested that it actually works, but I can't see any reason why it shouldn't. Assuming that it works, adapting this idea to your previous question should be straightforward.

NickD
  • 27,023
  • 3
  • 23
  • 42
  • Thanks very much Nick! It is an excellent answer and I think the draw-backs you mention are not likely to take place in the application I have in mind, at least not too often. I tested the `nohup` alternative with mixed results: some times it works, sometimes it does not. – Ruy Jun 07 '21 at 22:05
  • That's too bad. Any inkling about the difference? Are you running the *same* command repeatedly and that sometimes works, but other times not? Does your command produce any output? I assume it does not consume any input, correct? – NickD Jun 07 '21 at 22:16
  • I am running `emacs -Q --batch --eval '(start-process "Okular" nil "nohup" "okular" "main.pdf")'`. Whether or not it works is pretty random. Here is a sample "No No No No Yes No No No No Yes No Yes No No Yes No No Yes No Yes Yes No No No Yes". There is no output regardless of whether or not it works. – Ruy Jun 07 '21 at 23:12
  • `emacs -Q --batch --eval '(progn (start-process "Okular" nil "nohup" "okular" "main.pdf") (sit-for 1))'` seems to work every time. – Ruy Jun 07 '21 at 23:41
  • 1
    That's what I was going to suggest as a test: it might be that emacs exits and the process is killed before it even has a chance to start and set up the SIGHUP protection. So delaying the exit a bit helps, but although it's worked so far, it is not guaranteed to always work. Just making the delay bigger will increase the probability of success but it will never be 1. – NickD Jun 08 '21 at 01:03