extending uiop/run-program

Faré fahree at gmail.com
Mon Aug 15 13:07:43 UTC 2016

>   https://gitlab.common-lisp.net/epipping/asdf/commit/ffd8d8564bdc6551f2b682e7683bf16d6d459161
> (to be squashed into an earlier commit) that I’m rather happy with.
Uh, your comment suggests that on lispworks6, your destructuring-bind is wrong.
Note that I'm OK with declaring we don't support lispworks6 anymore,
but that must be made explicit. Also, ask Robert what he thinks about it.

>> * Also, is #+lispworks7 future-proof? Is there a feature for 7-or-later?
> I don’t think so, no. It seems that each version has a feature corresponding to its own version but not others. We could maybe provide our own, though. We cannot know what versioning scheme they’ll use in the future but it shouldn’t be too difficult to find out what features lispworks has defined in the past. So a
>   (lispworks7-or-greater-p)
> could probably be implemented as
>   (not (or #+(or lispworks4 lispworks5 lispworks6) t))
> or something along those lines.
Yuck. I'd rather query SYSTEM::*MAJOR-VERSION-NUMBER* in a #..

> (A) The first is with the :overwrite default for :if-output-exists. [...]
> So since all [implementations] appear to support the behaviour of :supersede (even though not necessarily by that name) and not all of them support :overwrite, it might make sense to change the default from :overwrite to :supersede and then (like other normaliser functions) have a translator that turns :supersede into :overwrite for CLISP. This would unfortunately also affect the (exported) run-program function. On the plus side, it would only change behaviour that previously could not be relied upon anyway.
Yes, that would be the Right Thing(tm).
The entire purpose of UIOP is to provide some portable abstractions
with stable semantics abstracting over implementation specifics,
rather than functions the meaning of which is actually not portable.
See my ASDF3 essay on this topic.

> (B) Process termination
> Even though it’s possible to kill a process on nearly ever platform somehow (not on CLISP, except for processes spawned through ext::launch) there are multiple tiers of support for that: From native to external: If you have a process in MKCL, you can terminate it through its process object, on unix or windows. That’s the ideal situation.
If it helps with CLISP, maybe ext::launch should be the default on CLISP.
I admit I don't care too much about CLISP, that hasn't been actively
maintained for years.
(It still ships with ASDF 2.33, for John McCarthy's sake.)

> The worst-possible situation that can still be handled if needed is when all you have is the PID: you end up calling `taskkill` on windows, through cmd.exe, or `kill` on unix, through the shell. I only recently started thinking about potential issues that this might involve other than performance, not only in this extreme case but also in cases that lie half-way between the MKCL situation and the worst-possible scenario, e.g. SBCL’s.
> If you obtain the PID of an arbitrary external process and then try to kill it through that PID at a later point in time, the process may no longer be running. It may not even exist anymore. Worse yet, its PID may have been recycled by the system and assigned to a newly spawned process that you end up killing by accident!
Note that on Unix, the race condition between killing a process
and the process dying then its PID being recycled is inherent,
whatever abstraction MKCL may try to provide that SBCL doesn't.
The only mitigating behavior would be for the kernel to insert a pause
before a PID could be used, and hope that programs never try kill a PID
more than that pause duration after having checked the process was alive
(and even then, if the process is kill -STOP'ped between the check and the kill,
there's nothing that can prevent the race condition).
Of course, 16-bit PIDs make the situation particularly tight on Unix

> ((B') I’m not sure what the best way to handle this requirement of reaping is. %wait-process-result currently calls both functions, so it would be possible to require that asynchronously spawned processes are waited on at some point, mirroring to some extent the requirement that every C program that calls fork() should call wait() at some point. So the name would be rather appropriate even.)
Yes, it is fair to require that asynchronous UIOP:RUN-PROGRAM users
should always call wait-process (or whatever you call the API
function) and not rely on the implementation doing it for them.

—♯ƒ • François-René ÐVB Rideau •Reflection&Cybernethics• http://fare.tunes.org
Solipsism is a lonely place. Psychopaths crave love, but can't get no
satisfaction: even elected by millions, it's still non-people voting for them.

More information about the asdf-devel mailing list