Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Popen.poll always returns None #46727

Closed
jjcogliati mannequin opened this issue Mar 24, 2008 · 8 comments
Closed

Popen.poll always returns None #46727

jjcogliati mannequin opened this issue Mar 24, 2008 · 8 comments
Labels
type-bug An unexpected behavior, bug, or error

Comments

@jjcogliati
Copy link
Mannequin

jjcogliati mannequin commented Mar 24, 2008

BPO 2475
Nosy @terryjreedy
Files
  • unnamed
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2010-06-19.03:21:17.666>
    created_at = <Date 2008-03-24.20:59:08.849>
    labels = ['type-bug']
    title = 'Popen.poll always returns None'
    updated_at = <Date 2010-08-06.19:52:01.011>
    user = 'https://bugs.python.org/jjcogliati'

    bugs.python.org fields:

    activity = <Date 2010-08-06.19:52:01.011>
    actor = 'dandrzejewski'
    assignee = 'none'
    closed = True
    closed_date = <Date 2010-06-19.03:21:17.666>
    closer = 'terry.reedy'
    components = []
    creation = <Date 2008-03-24.20:59:08.849>
    creator = 'jjcogliati'
    dependencies = []
    files = ['17719']
    hgrepos = []
    issue_num = 2475
    keywords = []
    message_count = 7.0
    messages = ['64439', '64901', '64911', '68228', '70347', '107967', '108160']
    nosy_count = 6.0
    nosy_names = ['terry.reedy', 'roudkerk', 'jjcogliati', 'lisanke', 'reiko', 'dandrzejewski']
    pr_nums = []
    priority = 'normal'
    resolution = 'out of date'
    stage = None
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue2475'
    versions = ['Python 2.5']

    @jjcogliati
    Copy link
    Mannequin Author

    jjcogliati mannequin commented Mar 24, 2008

    I was trying to use subprocess to run multiple processes, and then wait
    until one was finished. I was using poll() to do this and created the
    following test case:
    #BEGIN
    import subprocess,os

    procs = [subprocess.Popen(["sleep",str(x)]) for x in range(1,11)]
    
    while len(procs) > 0:
        os.wait()
        print [(p.pid,p.poll()) for p in procs]
        procs = [p for p in procs if p.poll() == None]
    #END

    I would have expected that as this program was run, it would remove the
    processes that finished from the procs list, but instead, they stay in
    it and I got the following output:

    #Output
    [(7426, None), (7427, None), (7428, None), (7429, None), (7430, None),
    (7431, None), (7432, None), (7433, None), (7434, None), (7435, None)]
    #above line repeats 8 more times
    [(7426, None), (7427, None), (7428, None), (7429, None), (7430, None),
    (7431, None), (7432, None), (7433, None), (7434, None), (7435, None)]
    Traceback (most recent call last):
      File "./test_poll.py", line 9, in <module>
        os.wait()
    OSError: [Errno 10] No child processes
    #End output

    Basically, even for finished processes, poll returns None.

    Version of python used:
    Python 2.5.1 (r251:54863, Oct 30 2007, 13:45:26)
    [GCC 4.1.2 20070925 (Red Hat 4.1.2-33)] on linux2

    Relevant documentation in Library reference manual 17.1.2
    poll( ) ... Returns returncode attribute.
    ... A None value indicates that the process hasn't terminated yet.

    @jjcogliati jjcogliati mannequin added the type-bug An unexpected behavior, bug, or error label Mar 24, 2008
    @roudkerk
    Copy link
    Mannequin

    roudkerk mannequin commented Apr 3, 2008

    The problem is that os.wait() does not play nicely with subprocess.py.
    Popen.poll() and Popen.wait() use os.waitpid(pid, ...) which will
    raise OSError if pid has already been reported by os.wait().
    Popen.poll() swallows OSError and by default returns None.

    You can (sort of) fix your program by using
    "p.popen(_deadstate='dead')" in place of "p.popen()". This will make
    poll() return 'dead' instead of None if OSError gets caught, but this
    is undocumented.

    Maybe a subprocess.wait() function could be added which would return a
    tuple

    (pid, exitcode, popen_object)
    

    where popen_object is None if the process is "foreign" (i.e. it was
    not created by the subprocess module).

    It would not be hard to implement this on unix if you don't care about
    thread safety. (On unix Popen.wait() is not thread-safe either, so
    maybe thread safety does not matter.)

    To implement something similar on windows you would probably need to
    use WaitForMultipleObjects() to check whether any process handles are
    signalled, but that would involve patching _subprocess.c or using
    ctypes or pywin32.

    @jjcogliati
    Copy link
    Mannequin Author

    jjcogliati mannequin commented Apr 4, 2008

    Hm. Well, after filing the bug, I created a thread for each subprocess,
    and had that thread do an wait on the process, and that worked fine.
    So, I guess at minimum it sounds like the documentation for poll could
    be improved to mention that it will not catch the state if something
    else does. I think a better fix would be for poll to return some kind
    of UnknownError instead of None if the process was finished, but python
    did not catch it for some reason (like using os.wait() :)

    @lisanke
    Copy link
    Mannequin

    lisanke mannequin commented Jun 15, 2008

    Isn't this a critical problem. The .poll() function serves as a means to
    check the status of the process started. When it continues to report
    'None' to a process which has already terminated, it creates a false
    positive of a hung process. Dealing with recovery from an actual hung
    process is difficult enough. Having to deal with a bad detection that
    the process ran to completion on top of this, makes the use of
    subprocess difficult.

    Maybe I'm miss applying the .poll() function. I'm trying to detect that
    a process has hung, prior to calling .stdout.readlines(). The
    readlines() will hang my python script if the process is hung. Is there
    another way I should be doing this?

    Thanks,

    Mike

    @reiko
    Copy link
    Mannequin

    reiko mannequin commented Jul 28, 2008

    I have also run into this problem. If you only use p.poll() and never
    p.wait(), returncode will always remain None.

    roudkerk's workaround doesn't seem to work with the new Popen objects,
    at least in python 2.4. ("unexpected keyword argument '_deadstate'")
    Does anyone have a workaround for subprocess.Popen? Do I have to switch
    to the deprecated popen function(s)?

    @terryjreedy
    Copy link
    Member

    Should this be closed or is this still a problem in 2.7 (release candidate out now, final soon) or 3.1?

    @lisanke
    Copy link
    Mannequin

    lisanke mannequin commented Jun 19, 2010

    Terry,

    I had long since coded around the problem. At this point, I no longer have
    the test environment to cause the intermittent conditions of the process
    hang. I could code something up, but; your question is the first response to
    this bug report since "reiko <j.k.langridge@gmail.com>" on 7/28/2008. I
    suggest it can be closed, and would be reopened when encountered again. I
    appears nobody is working in that area of code.

    On Wed, Jun 16, 2010 at 8:13 PM, Terry J. Reedy <report@bugs.python.org>wrote:

    Terry J. Reedy <tjreedy@udel.edu> added the comment:

    Should this be closed or is this still a problem in 2.7 (release candidate
    out now, final soon) or 3.1?

    ----------
    nosy: +tjreedy


    Python tracker <report@bugs.python.org>
    <http://bugs.python.org/issue2475\>


    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    @norswap
    Copy link

    norswap commented Jan 12, 2024

    This issue is still alive and well for me.

    I'm running Python 3.10.13 on Apple Silicon Mac.

    I'm sending Popen.terminate() to a subprocess, and I want to ensure that it does terminate within a certain delay, otherwise I send it Popen.kill(). To check if the process is terminated, I use Popen.poll() — which always returns None, even when the process is not actually terminated (in some case, it doesn't even terminate later).

    A workaround that works: using Popen._internal_poll(_deadstate="dead") — as when the thread is dead it will return "dead" instead of None.

    A potential complication is that I'm running all of this from a signal handler or an atexit handler. I want to make sure that all sub-processes have exited when the main process exits.

    I tried using Popen.wait(0.001) right before the poll call, given the implications of some messages in this thread, however this caused the process to terminate right there and then without any diagnostic whatsoever as to what was happening.

    Can I suggest reopening this and actually fixing the behaviour of poll? Is seems fundamentally broken if it does not actually return the exit code of a completed subprocess.

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    2 participants