Automatically restarting system calls?

Discussion in 'Python' started by Dan Stromberg, Jun 13, 2008.

  1. I wrote a script(1) replacement in python (http://stromberg.dnsalias.org/
    ~dstromberg/pypty/), but I'm encountering a problem in it.

    I think I know the solution to the problem, but I'd've thought python was
    high level enough that this solution isn't required, so I wanted to
    inquire about it here.

    Specifically, the program has a signal handler for window size changes.
    And if the window is resized during an os.write() (for example), I get a
    python exception about needing to restart the system call.

    In C, I know you're supposed to wrap your system calls with while loops
    until you don't get an ERESTART, but does one really need to wrap all of
    one's os.write()'s (for example) with such while loops in python?

    Thanks!
     
    Dan Stromberg, Jun 13, 2008
    #1
    1. Advertising

  2. On Jun 13, 10:41 am, Dan Stromberg <> wrote:
    > I wrote a script(1) replacement in python (http://stromberg.dnsalias.org/
    > ~dstromberg/pypty/), but I'm encountering a problem in it.
    >
    > I think I know the solution to the problem, but I'd've thought python was
    > high level enough that this solution isn't required, so I wanted to
    > inquire about it here.
    >
    > Specifically, the program has a signal handler for window size changes.
    > And if the window is resized during an os.write() (for example), I get a
    > python exception about needing to restart the system call.
    >
    > In C, I know you're supposed to wrap your system calls with while loops
    > until you don't get an ERESTART, but does one really need to wrap all of
    > one's os.write()'s (for example) with such while loops in python?


    Unfortunately, signals are sometimes used to intentionally interrupt
    system calls, so we can't always loop on ERESTART.

    However, os.write() is a low level API. Maybe file.write() or
    socket.send() would be a little more robust?
     
    Rhamphoryncus, Jun 14, 2008
    #2
    1. Advertising

  3. On Sat, 14 Jun 2008 10:04:15 -0700, Rhamphoryncus wrote:

    > On Jun 13, 10:41 am, Dan Stromberg <> wrote:
    >> I wrote a script(1) replacement in python
    >> (http://stromberg.dnsalias.org/ ~dstromberg/pypty/), but I'm
    >> encountering a problem in it.
    >>
    >> I think I know the solution to the problem, but I'd've thought python
    >> was high level enough that this solution isn't required, so I wanted to
    >> inquire about it here.
    >>
    >> Specifically, the program has a signal handler for window size changes.
    >> And if the window is resized during an os.write() (for example), I get
    >> a python exception about needing to restart the system call.
    >>
    >> In C, I know you're supposed to wrap your system calls with while loops
    >> until you don't get an ERESTART, but does one really need to wrap all
    >> of one's os.write()'s (for example) with such while loops in python?

    >
    > Unfortunately, signals are sometimes used to intentionally interrupt
    > system calls, so we can't always loop on ERESTART.
    >
    > However, os.write() is a low level API. Maybe file.write() or
    > socket.send() would be a little more robust?


    Hmmm... How about an option with a default value of True or False, that
    would control such looping?

    BTW, it seems I'm getting EINTR, not ERESTART.

    I perhaps could use file.write(), but I'm not confident that's the case,
    because I'm using select.select(), and I'm getting EINTR's not just in
    os.write() but also select.select() and tty.setraw(), so far.

    The worst part is, I don't really know which python functions require
    such loops and which don't, or even what those exceptions will look like
    - that is, until I see a real world example. So as the errors come up in
    real life, I'm wrapping my functions with:

    def maybe_restarted_syscall(fn, loop_exc, loop_errnos):
    while 1:
    try:
    result = fn()
    except loop_exc, (errno, error_string):
    if errno in loop_errnos:
    continue
    else:
    sys.stderr.write('%s: %s\n' % (sys.argv[0], error_string))
    raise
    else:
    break
    return result

    ....and calling it like (for example) :

    maybe_restarted_syscall(lambda : select.select([stdin, fd], [], []),
    select.error, [ errno.EINTR ])

    Is there some way of being a little more proactive with these errors?

    Thanks!
     
    Dan Stromberg, Jun 15, 2008
    #3
  4. On Jun 15, 1:06 pm, Dan Stromberg <> wrote:
    > On Sat, 14 Jun 2008 10:04:15 -0700, Rhamphoryncus wrote:
    > > On Jun 13, 10:41 am, Dan Stromberg <> wrote:
    > >> I wrote a script(1) replacement in python
    > >> (http://stromberg.dnsalias.org/~dstromberg/pypty/), but I'm
    > >> encountering a problem in it.

    >
    > >> I think I know the solution to the problem, but I'd've thought python
    > >> was high level enough that this solution isn't required, so I wanted to
    > >> inquire about it here.

    >
    > >> Specifically, the program has a signal handler for window size changes.
    > >> And if the window is resized during an os.write() (for example), I get
    > >> a python exception about needing to restart the system call.

    >
    > >> In C, I know you're supposed to wrap your system calls with while loops
    > >> until you don't get an ERESTART, but does one really need to wrap all
    > >> of one's os.write()'s (for example) with such while loops in python?

    >
    > > Unfortunately, signals are sometimes used to intentionally interrupt
    > > system calls, so we can't always loop on ERESTART.

    >
    > > However, os.write() is a low level API. Maybe file.write() or
    > > socket.send() would be a little more robust?

    >
    > Hmmm... How about an option with a default value of True or False, that
    > would control such looping?
    >
    > BTW, it seems I'm getting EINTR, not ERESTART.
    >
    > I perhaps could use file.write(), but I'm not confident that's the case,
    > because I'm using select.select(), and I'm getting EINTR's not just in
    > os.write() but also select.select() and tty.setraw(), so far.
    >
    > The worst part is, I don't really know which python functions require
    > such loops and which don't, or even what those exceptions will look like
    > - that is, until I see a real world example. So as the errors come up in
    > real life, I'm wrapping my functions with:
    >
    > def maybe_restarted_syscall(fn, loop_exc, loop_errnos):
    > while 1:
    > try:
    > result = fn()
    > except loop_exc, (errno, error_string):
    > if errno in loop_errnos:
    > continue
    > else:
    > sys.stderr.write('%s: %s\n' % (sys.argv[0], error_string))
    > raise
    > else:
    > break
    > return result
    >
    > ...and calling it like (for example) :
    >
    > maybe_restarted_syscall(lambda : select.select([stdin, fd], [], []),
    > select.error, [ errno.EINTR ])
    >
    > Is there some way of being a little more proactive with these errors?


    I can't think of anything. The best way to handle signals is to avoid
    them whenever possible - which probably can't work in your case.

    You might find a way to get SA_RESTART applied, but it won't work
    right for you. Python splits signal handlers into a top half and a
    bottom half - the bottom is in C, it's the real signal handler, and
    top is in python. To keep things sane for the top half, it delays
    until the interpreter is in a sane state (such as between bytecodes).
    If you used SA_RESTART the bottom half would still work, but the top
    would be delayed indefinitely until something else woke up the
    interpreter. In other words, your window likely won't redraw until
    the user types something or you print something.
     
    Rhamphoryncus, Jun 15, 2008
    #4
  5. Rhamphoryncus <> writes:

    > You might find a way to get SA_RESTART applied, but it won't work
    > right for you. Python splits signal handlers into a top half and a
    > bottom half - the bottom is in C, it's the real signal handler, and
    > top is in python. To keep things sane for the top half, it delays
    > until the interpreter is in a sane state (such as between
    > bytecodes). If you used SA_RESTART the bottom half would still
    > work, but the top would be delayed indefinitely until something else
    > woke up the interpreter. In other words, your window likely won't
    > redraw until the user types something or you print something.


    One possible way to handle this is by implementing a small signal
    handler in C. This signal handler can set the signal using
    SA_RESTART, getting rid of EINTR, at least for popular syscalls. In
    the signal handler it can simply write a byte into a pipe, the other
    end of which is monitored by the select() event loop. Python,
    presumably sleeping in select(), or about to do that, will immediately
    notice the "signal" by the pipe becoming readable.
     
    Hrvoje Niksic, Jun 16, 2008
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Hari Koduru
    Replies:
    3
    Views:
    1,395
    Natty Gur
    Jan 15, 2004
  2. Joerg Schoen
    Replies:
    0
    Views:
    465
    Joerg Schoen
    Jun 28, 2004
  3. markus
    Replies:
    22
    Views:
    689
    Dances With Crows
    Sep 22, 2004
  4. Adam Atlas
    Replies:
    1
    Views:
    367
    Matimus
    Oct 11, 2007
  5. Richard Tobin
    Replies:
    24
    Views:
    826
Loading...

Share This Page