### Navigation

- index
- modules |
- next |
- previous |
- C/C++ Library Interfaces »

# Interface to the `pselect()` system call

Interface to the `pselect()` system call

This module defines a class `PSelecter` which can be used to call the system call `pselect()` and which can also be used in a `with` statement to block given signals until `PSelecter.pselect()` is called.

AUTHORS:

- Jeroen Demeyer (2013-02-07): initial version (trac ticket #14079)

## Waiting for subprocesses

One possible use is to wait with a timeout until any child process exits, as opposed to `os.wait()` which doesn’t have a timeout or `multiprocessing.Process.join()` which waits for one specific process.

Since `SIGCHLD` is ignored by default, we first need to install a signal handler for `SIGCHLD`. It doesn’t matter what it does, as long as the signal isn’t ignored:

    sage: import signal
    sage: def dummy_handler(sig, frame):
    ....:     pass
    ....:
    sage: _ = signal.signal(signal.SIGCHLD, dummy_handler)

We wait for a child created using the `subprocess` module:

    sage: from sage.ext.pselect import PSelecter
    sage: from subprocess import *
    sage: with PSelecter([signal.SIGCHLD]) as sel:
    ....:     p = Popen(["sleep", "1"])
    ....:     _ = sel.sleep()
    ....:
    sage: p.poll()  # p should be finished
    0

Now using the `multiprocessing` module:

    sage: from sage.ext.pselect import PSelecter
    sage: from multiprocessing import *
    sage: import time
    sage: with PSelecter([signal.SIGCHLD]) as sel:
    ....:     p = Process(target=time.sleep, args=(1,))
    ....:     p.start()
    ....:     _ = sel.sleep()
    ....:     p.is_alive()  # p should be finished
    ....:
    False

class `sage.ext.pselect.``PSelecter`

  Bases: `object`

  This class gives an interface to the `pselect` system call.

  It can be used in a `with` statement to block given signals such that they can only occur during the `pselect()` or `sleep()` calls.

  As an example, we block the `SIGHUP` and `SIGALRM` signals and then raise a `SIGALRM` signal. The interrupt will only be seen during the `sleep()` call:

      sage: from sage.ext.pselect import PSelecter
      sage: import signal, time
      sage: with PSelecter([signal.SIGHUP, signal.SIGALRM]) as sel:
      ....:     os.kill(os.getpid(), signal.SIGALRM)
      ....:     time.sleep(0.5)  # Simply sleep, no interrupt detected
      ....:     try:
      ....:         _ = sel.sleep(1)  # Interrupt seen here
      ....:     except AlarmInterrupt:
      ....:         print("Interrupt OK")
      ....:
      Interrupt OK

  Warning

  If `SIGCHLD` is blocked inside the `with` block, then you should not use `Popen().wait()` or `Process().join()` because those might block, even if the process has actually exited. Use non-blocking alternatives such as `Popen.poll()` or `multiprocessing.active_children()` instead.

  `pselect`(rlist=[], wlist=[], xlist=[], timeout=None)

    Wait until one of the given files is ready, or a signal has been received, or until `timeout` seconds have past.

    INPUT:

    - `rlist` – (default: `[]`) a list of files to wait for reading.
    - `wlist` – (default: `[]`) a list of files to wait for writing.
    - `xlist` – (default: `[]`) a list of files to wait for exceptions.
    - `timeout` – (default: `None`) a timeout in seconds, where `None` stands for no timeout.

    OUTPUT: A 4-tuple `(rready, wready, xready, tmout)` where the first three are lists of file descriptors which are ready, that is a subset of `(rlist, wlist, xlist)`. The fourth is a boolean which is `True` if and only if the command timed out. If `pselect` was interrupted by a signal, the output is `([], [], [], False)`.

    See also

    Use the `sleep()` method instead if you don’t care about file descriptors.

    EXAMPLES:

    The file `/dev/null` should always be available for reading and writing:

        sage: from sage.ext.pselect import PSelecter
        sage: f = open(os.devnull, "r+")
        sage: sel = PSelecter()
        sage: sel.pselect(rlist=[f])
        ([<open file '/dev/null', mode 'r+' at ...>], [], [], False)
        sage: sel.pselect(wlist=[f])
        ([], [<open file '/dev/null', mode 'r+' at ...>], [], False)

    A list of various files, all of them should be ready for reading. Also create a pipe, which should be ready for writing, but not reading (since nothing has been written):

        sage: f = open(os.devnull, "r")
        sage: g = open(os.path.join(SAGE_LOCAL, 'bin', 'python'), "r")
        sage: (pr, pw) = os.pipe()
        sage: r, w, x, t = PSelecter().pselect([f,g,pr,pw], [pw], [pr,pw])
        sage: len(r), len(w), len(x), t
        (2, 1, 0, False)

    Checking for exceptions on the pipe should simply time out:

        sage: sel.pselect(xlist=[pr,pw], timeout=0.2)
        ([], [], [], True)

    TESTS:

    It is legal (but silly) to list the same file multiple times:

        sage: r, w, x, t = PSelecter().pselect([f,g,f,f,g])
        sage: len(r)
        5

    Invalid input:

        sage: PSelecter().pselect([None])
        Traceback (most recent call last):
        ...
        TypeError: an integer is required

    Open a file and close it, but save the (invalid) file descriptor:

        sage: f = open(os.devnull, "r")
        sage: n = f.fileno()
        sage: f.close()
        sage: PSelecter().pselect([n])
        Traceback (most recent call last):
        ...
        IOError: ...

  `sleep`(timeout=None)

    Wait until a signal has been received, or until `timeout` seconds have past.

    This is implemented as a special case of `pselect()` with empty lists of file descriptors.

    INPUT:

    - `timeout` – (default: `None`) a timeout in seconds, where `None` stands for no timeout.

    OUTPUT: A boolean which is `True` if the call timed out, False if it was interrupted.

    EXAMPLES:

    A simple wait with timeout:

        sage: from sage.ext.pselect import PSelecter
        sage: sel = PSelecter()
        sage: sel.sleep(timeout=0.1)
        True

    0 or negative time-outs are allowed, `sleep` should then return immediately:

        sage: sel.sleep(timeout=0)
        True
        sage: sel.sleep(timeout=-123.45)
        True

`sage.ext.pselect.``get_fileno`(f)

  Return the file descriptor of `f`.

  INPUT:

  - `f` – an object with a `.fileno` method or an integer, which is a file descriptor.

  OUTPUT: A C `long` representing the file descriptor.

  EXAMPLES:

      sage: from sage.ext.pselect import get_fileno
      sage: get_fileno(open(os.devnull))  # random
      5
      sage: get_fileno(42)
      42
      sage: get_fileno(None)
      Traceback (most recent call last):
      ...
      TypeError: an integer is required
      sage: get_fileno(-1)
      Traceback (most recent call last):
      ...
      ValueError: Invalid file descriptor
      sage: get_fileno(2^30)
      Traceback (most recent call last):
      ...
      ValueError: Invalid file descriptor

### Navigation

- index
- modules |
- next |
- previous |
- C/C++ Library Interfaces »