skalibs

Mirror/fork of https://skarnet.org/software/skalibs/
git clone https://ccx.te2000.cz/git/skalibs
Log | Files | Refs | README | LICENSE

safewrappers.html (4003B)


      1 <html>
      2   <head>
      3     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      4     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
      5     <meta http-equiv="Content-Language" content="en" />
      6     <title>skalibs: safe wrappers</title>
      7     <meta name="Description" content="skalibs: safe wrappers" />
      8     <meta name="Keywords" content="skalibs c unix safe wrappers safewrappers library libstddjb" />
      9     <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
     10   </head>
     11 <body>
     12 
     13 <p>
     14 <a href="index.html">libstddjb</a><br />
     15 <a href="../libskarnet.html">libskarnet</a><br />
     16 <a href="../index.html">skalibs</a><br />
     17 <a href="//skarnet.org/software/">Software</a><br />
     18 <a href="//skarnet.org/">skarnet.org</a>
     19 </p>
     20 
     21 <h1> Safe wrappers </h1>
     22 
     23 <p>
     24  Lots of functions in <tt>libstddjb</tt>, declared for instance in
     25 <a href="allreadwrite.html">allreadwrite.h</a> or
     26 <a href="djbunix.html">djbunix.h</a>, are just "safe wrappers"
     27 around corresponding system functions. For instance,
     28 <tt>fd_read()</tt> is a safe wrapper around the system <tt>read()</tt>
     29 function.
     30 </p>
     31 
     32 <h2> The problem </h2>
     33 
     34 <p>
     35  Quite a lot of system calls are defined by
     36 <a href="https://www.opengroup.org/onlinepubs/9699919799/nfindex.html">The
     37 Open Group Base Specifications</a> as interruptible: when the process is in
     38 the middle of such a system call and receives a signal that it does not
     39 ignore, the system call immediately returns -1 EINTR (after the signal
     40 handler, if any, has been executed).
     41 </p>
     42 
     43 <p>
     44  Most of the time, this is not an issue: unignored signals usually kill
     45 the process anyway. Or stop it - and when it resumes, system calls are
     46 simply restarted, not interrupted. EINTR can only happen when a signal
     47 handler has been installed, and a signal is actually caught by the
     48 signal handler during an interruptible system call. And to avoid EINTR,
     49 users can use the SA_RESTART flag when installing the signal handler with
     50 <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaction.html">sigaction()</a>.
     51 </p>
     52 
     53 <p>
     54  However, there is a common case where using SA_RESTART is a bad idea:
     55 when writing an asynchronous event loop.
     56 </p>
     57 
     58 <p>
     59  An asynchronous event loop is organized around a
     60 <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html">select()</a> or
     61 <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html">poll()</a>
     62 system call that is the only blocking operation in the whole loop. That call takes a
     63 timeout as an argument. If a signal handler is installed with SA_RESTART and a
     64 signal arrives in the middle of the select/poll call - which happens often
     65 since it is blocking - then the select/poll is restarted with the same arguments,
     66 including the timeout. This is not good: time has elapsed, the timeout should be
     67 recomputed. Some versions of select update the values in the struct timeval even
     68 when select() is interrupted, but it is not portable, and not applicable to poll().
     69 So it is necessary, in this case, to have select/poll return -1 EINTR when a
     70 signal is caught. And that means SA_RESTART should not be used.
     71 </p>
     72 
     73 <p>
     74  Which also means that other system calls performed when the signal handler has
     75 been installed, for instance in the body of the loop, will <em>not</em> be
     76 protected, and can return -1 EINTR if a signal is caught at the wrong time.
     77 </p>
     78 
     79 <h2> The solution </h2>
     80 
     81 <p>
     82  So, in order to be perfectly reliable, when a program has caught a signal
     83 without SA_RESTART and makes an interruptible system call, it must check whether
     84 the return value is -1 EINTR, and restart the system call if it is the case.
     85 This is annoying to write; so, skalibs provides small wrappers around
     86 interruptible system calls, so that programmers can just call those safe wrappers
     87 and never bother with this again.
     88 </p>
     89 
     90 <p>
     91  The performance loss from having a wrapper layer is totally negligible
     92 compared to the cost of using a system call in the first place.
     93 </p>
     94 
     95 </body>
     96 </html>