about summary refs log tree commit diff
path: root/doc/libstddjb/safewrappers.html
blob: 2cacb4abe61a03dd4b28ef0aba56170953d71918 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta http-equiv="Content-Language" content="en" />
    <title>skalibs: safe wrappers</title>
    <meta name="Description" content="skalibs: safe wrappers" />
    <meta name="Keywords" content="skalibs c unix safe wrappers safewrappers library libstddjb" />
    <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
  </head>
<body>

<p>
<a href="index.html">libstddjb</a><br />
<a href="../libskarnet.html">libskarnet</a><br />
<a href="../index.html">skalibs</a><br />
<a href="//skarnet.org/software/">Software</a><br />
<a href="//skarnet.org/">skarnet.org</a>
</p>

<h1> Safe wrappers </h1>

<p>
 Lots of functions in <tt>libstddjb</tt>, declared for instance in
<a href="allreadwrite.html">allreadwrite.h</a> or
<a href="djbunix.html">djbunix.h</a>, are just "safe wrappers"
around corresponding system functions. For instance,
<tt>fd_read()</tt> is a safe wrapper around the system <tt>read()</tt>
function.
</p>

<h2> The problem </h2>

<p>
 Quite a lot of system calls are defined by
<a href="https://www.opengroup.org/onlinepubs/9699919799/nfindex.html">The
Open Group Base Specifications</a> as interruptible: when the process is in
the middle of such a system call and receives a signal that it does not
ignore, the system call immediately returns -1 EINTR (after the signal
handler, if any, has been executed).
</p>

<p>
 Most of the time, this is not an issue: unignored signals usually kill
the process anyway. Or stop it - and when it resumes, system calls are
simply restarted, not interrupted. EINTR can only happen when a signal
handler has been installed, and a signal is actually caught by the
signal handler during an interruptible system call. And to avoid EINTR,
users can use the SA_RESTART flag when installing the signal handler with
<a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaction.html">sigaction()</a>.
</p>

<p>
 However, there is a common case where using SA_RESTART is a bad idea:
when writing an asynchronous event loop.
</p>

<p>
 An asynchronous event loop is organized around a
<a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html">select()</a> or
<a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html">poll()</a>
system call that is the only blocking operation in the whole loop. That call takes a
timeout as an argument. If a signal handler is installed with SA_RESTART and a
signal arrives in the middle of the select/poll call - which happens often
since it is blocking - then the select/poll is restarted with the same arguments,
including the timeout. This is not good: time has elapsed, the timeout should be
recomputed. Some versions of select update the values in the struct timeval even
when select() is interrupted, but it is not portable, and not applicable to poll().
So it is necessary, in this case, to have select/poll return -1 EINTR when a
signal is caught. And that means SA_RESTART should not be used.
</p>

<p>
 Which also means that other system calls performed when the signal handler has
been installed, for instance in the body of the loop, will <em>not</em> be
protected, and can return -1 EINTR if a signal is caught at the wrong time.
</p>

<h2> The solution </h2>

<p>
 So, in order to be perfectly reliable, when a program has caught a signal
without SA_RESTART and makes an interruptible system call, it must check whether
the return value is -1 EINTR, and restart the system call if it is the case.
This is annoying to write; so, skalibs provides small wrappers around
interruptible system calls, so that programmers can just call those safe wrappers
and never bother with this again.
</p>

<p>
 The performance loss from having a wrapper layer is totally negligible
compared to the cost of using a system call in the first place.
</p>

</body>
</html>