lib/util Rename samba_init_module_fns_run -> samba_module_init_fns_run
[kai/samba.git] / lib / util / select.c
1 /*
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    Samba select/poll implementation
5    Copyright (C) Andrew Tridgell 1992-1998
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include "system/select.h"
24 #include "lib/util/select.h"
25
26 /* This is here because it allows us to avoid a nasty race in signal handling.
27    We need to guarantee that when we get a signal we get out of a select immediately
28    but doing that involves a race condition. We can avoid the race by getting the
29    signal handler to write to a pipe that is in the select/poll list
30
31    This means all Samba signal handlers should call sys_select_signal().
32 */
33
34 static pid_t initialised;
35 static int select_pipe[2];
36 static volatile unsigned pipe_written, pipe_read;
37
38 /*******************************************************************
39  Call this from all Samba signal handlers if you want to avoid a
40  nasty signal race condition.
41 ********************************************************************/
42
43 void sys_select_signal(char c)
44 {
45         int saved_errno = errno;
46
47         if (!initialised) return;
48
49         if (pipe_written > pipe_read+256) return;
50
51         if (write(select_pipe[1], &c, 1) == 1) pipe_written++;
52
53         errno = saved_errno;
54 }
55
56 /*
57  * sys_poll expects pollfd's to be a talloc'ed array.
58  *
59  * It expects the talloc_array_length(fds) >= num_fds+1 to give space
60  * to the signal pipe.
61  */
62
63 int sys_poll(struct pollfd *fds, int num_fds, int timeout)
64 {
65         int ret;
66
67         if (talloc_array_length(fds) < num_fds+1) {
68                 errno = ENOSPC;
69                 return -1;
70         }
71
72         if (initialised != sys_getpid()) {
73                 if (pipe(select_pipe) == -1)
74                 {
75                         int saved_errno = errno;
76                         DEBUG(0, ("sys_poll: pipe failed (%s)\n",
77                                 strerror(errno)));
78                         errno = saved_errno;
79                         return -1;
80                 }
81
82                 /*
83                  * These next two lines seem to fix a bug with the Linux
84                  * 2.0.x kernel (and probably other UNIXes as well) where
85                  * the one byte read below can block even though the
86                  * select returned that there is data in the pipe and
87                  * the pipe_written variable was incremented. Thanks to
88                  * HP for finding this one. JRA.
89                  */
90
91                 if(set_blocking(select_pipe[0],0)==-1)
92                         smb_panic("select_pipe[0]: O_NONBLOCK failed");
93                 if(set_blocking(select_pipe[1],0)==-1)
94                         smb_panic("select_pipe[1]: O_NONBLOCK failed");
95
96                 initialised = sys_getpid();
97         }
98
99         ZERO_STRUCT(fds[num_fds]);
100         fds[num_fds].fd = select_pipe[0];
101         fds[num_fds].events = POLLIN|POLLHUP;
102
103         errno = 0;
104         ret = poll(fds, num_fds+1, timeout);
105
106         if ((ret >= 0) && (fds[num_fds].revents & (POLLIN|POLLHUP|POLLERR))) {
107                 char c;
108                 int saved_errno = errno;
109
110                 if (read(select_pipe[0], &c, 1) == 1) {
111                         pipe_read += 1;
112
113                         /* Mark Weaver <mark-clist@npsl.co.uk> pointed out a critical
114                            fix to ensure we don't lose signals. We must always
115                            return -1 when the select pipe is set, otherwise if another
116                            fd is also ready (so ret == 2) then we used to eat the
117                            byte in the pipe and lose the signal. JRA.
118                         */
119                         ret = -1;
120 #if 0
121                         /* JRA - we can use this to debug the signal messaging... */
122                         DEBUG(0,("select got %u signal\n", (unsigned int)c));
123 #endif
124                         errno = EINTR;
125                 } else {
126                         ret -= 1;
127                         errno = saved_errno;
128                 }
129         }
130
131         return ret;
132 }
133
134 int sys_poll_intr(struct pollfd *fds, int num_fds, int timeout)
135 {
136         int orig_timeout = timeout;
137         struct timespec start;
138         int ret;
139
140         clock_gettime_mono(&start);
141
142         while (true) {
143                 struct timespec now;
144                 int64_t elapsed;
145
146                 ret = poll(fds, num_fds, timeout);
147                 if (ret != -1) {
148                         break;
149                 }
150                 if (errno != EINTR) {
151                         break;
152                 }
153                 clock_gettime_mono(&now);
154                 elapsed = nsec_time_diff(&now, &start);
155                 timeout = (orig_timeout - elapsed) / 1000000;
156         };
157         return ret;
158 }