xonsh/news/waitpid_returncode.rst

24 lines
219 B
ReStructuredText
Raw Normal View History

Fixed populating the return code for interrupted process. (#5380) ### Motivation There is annoying behavior when you run command in the loop and can't interrupt e.g. [this report](https://github.com/xonsh/xonsh/discussions/5371) and a bit #5342. After diving into this I see the issue around return code. ### The essence Basically ``p = subprocess.Popen()`` populates ``p.returncode`` after ``p.wait()``, ``p.poll()`` or ``p.communicate()`` ([doc](https://docs.python.org/3/library/os.html#os.waitpid)). But if you're using `os.waitpid()` BEFORE these functions you're capturing return code from a signal subsystem and ``p.returncode`` will be ``0`` like success but it's not success. So after ``os.waitid`` call you need to set return code manually ``p.returncode = -os.WTERMSIG(status)`` like in Popen. Example: ```xsh python # python interactive import os, signal, subprocess as sp p = sp.Popen(['sleep', '100']) p.pid # 123 p.wait() # Ctrl+C or `kill -SIGINT 123` from another terminal p.returncode # -2 # BUT: p = sp.Popen(['sleep', '100']) p.pid # 123 pid, status = os.waitpid(p.pid, os.WUNTRACED) # status=2 # From another terminal: kill -SIGINT 123 p.wait() # 0 p.returncode # 0 ``` ```xsh from xonsh.tools import describe_waitpid_status describe_waitpid_status(2) # WIFEXITED - False - Return True if the process returning status exited via the exit() system call. # WEXITSTATUS - 0 - Return the process return code from status. # WIFSIGNALED - True - Return True if the process returning status was terminated by a signal. # WTERMSIG - 2 - Return the signal that terminated the process that provided the status value. # WIFSTOPPED - False - Return True if the process returning status was stopped. # WSTOPSIG - 0 - Return the signal that stopped the process that provided the status value. ``` See also: [Helpful things for knight](https://github.com/xonsh/xonsh/pull/5361#issuecomment-2078826181). ### Before ```xsh $RAISE_SUBPROC_ERROR = True sleep 100 # Ctrl+C _.rtn # 0 # It's wrong and RAISE_SUBPROC_ERROR ignored. for i in range(5): print(i) sleep 5 # 0 # Ctrl+C # Can't interrupt # 1 # 2 ``` ### After ```xsh sleep 100 # Ctrl+C _.rtn # -2 # Like in default Popen $RAISE_SUBPROC_ERROR = True for i in range(5): print(i) sleep 5 # 0 # Ctrl+C # subprocess.CalledProcessError ``` ### Notes * We need to refactor `xonsh.jobs`. It's pretty uncomfortable work with module. * The logic is blurry between Specs, Pipelines and Jobs. We need to bring more clear functions. * The `captured` variable looks like "just the way of capturing (stdout, object)" but in fact it affects all logic very much. We need to create table where we can see the logic difference for every type of capturing. E.g. in `captured=stdout` mode we use `xonsh.jobs` to monitor the command but in `captured=object` we avoid this and some logic from `xonsh.jobs` applied in `stdout` mode but missed in `object` mode. We need clear map. ## For community ⬇️ **Please click the 👍 reaction instead of leaving a `+1` or 👍 comment** --------- Co-authored-by: a <1@1.1> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-05-02 22:10:53 +02:00
**Added:**
* <news item>
**Changed:**
* <news item>
**Deprecated:**
* <news item>
**Removed:**
* <news item>
**Fixed:**
* Fixed populating the return code for interrupted process.
**Security:**
* <news item>