> On 15 Aug 2016, at 15:07, Faré <fah...@gmail.com> wrote: > >> >> 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.
Oh, the comment may be doing more harm than good then. The code is actually correct. It’s just that in the if-branch, lispworks 6 will return (io,err,pid), and in the else-branch (pid), whereas lispworks7 will return (io,err,pid) in both branches. > 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. I don’t think this will be necessary. I haven’t been able to test with lispworks 5 but lispworks 6 works pretty well. >>> * 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 #.. I didn’t know about that variable. The resulting code would be nicer but it’s still a private symbol which might disappear in the future. Personally, I’d prefer to go with the uglier but more official version. >> (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.) It appears there are some attempts to breathe new life into CLISP, though. See e.g. https://sourceforge.net/u/musteresel/clisp/ >> 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. Yes, but we’re not dealing with this general problem as I tried to outline in the paragraph after that (quoting myself): Fortunately, I am not trying to solve this general problem but the simpler problem of killing a process spawned through run-program, which will necessarily be a child process. Such a process will signal its parent with SIGCHLD when it terminates and stick around as a zombie until it is waited for. So the issue is solvable here, no? > 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. Okay, great. Elias