source: branches/samba-3.3.x/source/lib/select.c@ 939

Last change on this file since 939 was 699, checked in by Silvan Scherrer, 13 years ago

Samba Server 3.3: made it high-mem aware

File size: 6.0 KB
Line 
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
23/* This is here because it allows us to avoid a nasty race in signal handling.
24 We need to guarantee that when we get a signal we get out of a select immediately
25 but doing that involves a race condition. We can avoid the race by getting the
26 signal handler to write to a pipe that is in the select/poll list
27
28 This means all Samba signal handlers should call sys_select_signal().
29*/
30#ifdef __OS2__
31#define pipe(A) os2_pipe(A)
32#endif
33
34static pid_t initialised;
35static int select_pipe[2];
36static 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
43void sys_select_signal(char c)
44{
45 if (!initialised) return;
46
47 if (pipe_written > pipe_read+256) return;
48
49 if (write(select_pipe[1], &c, 1) == 1) pipe_written++;
50}
51
52/*******************************************************************
53 Like select() but avoids the signal race using a pipe
54 it also guuarantees that fds on return only ever contains bits set
55 for file descriptors that were readable.
56********************************************************************/
57
58int sys_select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval)
59{
60 int ret, saved_errno;
61 fd_set *readfds2, readfds_buf;
62
63 if (initialised != sys_getpid()) {
64 if (pipe(select_pipe) == -1)
65 smb_panic("Could not create select pipe");
66
67 if (select_pipe[0] < 0 || select_pipe[0] >= FD_SETSIZE) {
68 errno = EBADF;
69 return -1;
70 }
71
72 /*
73 * These next two lines seem to fix a bug with the Linux
74 * 2.0.x kernel (and probably other UNIXes as well) where
75 * the one byte read below can block even though the
76 * select returned that there is data in the pipe and
77 * the pipe_written variable was incremented. Thanks to
78 * HP for finding this one. JRA.
79 */
80
81 if(set_blocking(select_pipe[0],0)==-1)
82 smb_panic("select_pipe[0]: O_NONBLOCK failed");
83 if(set_blocking(select_pipe[1],0)==-1)
84 smb_panic("select_pipe[1]: O_NONBLOCK failed");
85
86 initialised = sys_getpid();
87 }
88
89 maxfd = MAX(select_pipe[0]+1, maxfd);
90
91 /* If readfds is NULL we need to provide our own set. */
92 if (readfds) {
93 readfds2 = readfds;
94 } else {
95 readfds2 = &readfds_buf;
96 FD_ZERO(readfds2);
97 }
98
99 FD_SET(select_pipe[0], readfds2);
100
101 errno = 0;
102 ret = select(maxfd,readfds2,writefds,errorfds,tval);
103
104 if (ret <= 0) {
105 FD_ZERO(readfds2);
106 if (writefds)
107 FD_ZERO(writefds);
108 if (errorfds)
109 FD_ZERO(errorfds);
110 } else if (FD_ISSET(select_pipe[0], readfds2)) {
111 char c;
112 saved_errno = errno;
113 if (read(select_pipe[0], &c, 1) == 1) {
114 pipe_read++;
115 /* Mark Weaver <mark-clist@npsl.co.uk> pointed out a critical
116 fix to ensure we don't lose signals. We must always
117 return -1 when the select pipe is set, otherwise if another
118 fd is also ready (so ret == 2) then we used to eat the
119 byte in the pipe and lose the signal. JRA.
120 */
121 ret = -1;
122#if 0
123 /* JRA - we can use this to debug the signal messaging... */
124 DEBUG(0,("select got %u signal\n", (unsigned int)c));
125#endif
126 errno = EINTR;
127 } else {
128 FD_CLR(select_pipe[0], readfds2);
129 ret--;
130 errno = saved_errno;
131 }
132 }
133
134 return ret;
135}
136
137/*******************************************************************
138 Similar to sys_select() but catch EINTR and continue.
139 This is what sys_select() used to do in Samba.
140********************************************************************/
141
142int sys_select_intr(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval)
143{
144 int ret;
145 fd_set *readfds2, readfds_buf, *writefds2, writefds_buf, *errorfds2, errorfds_buf;
146 struct timeval tval2, *ptval, end_time;
147
148 readfds2 = (readfds ? &readfds_buf : NULL);
149 writefds2 = (writefds ? &writefds_buf : NULL);
150 errorfds2 = (errorfds ? &errorfds_buf : NULL);
151 if (tval) {
152 GetTimeOfDay(&end_time);
153 end_time.tv_sec += tval->tv_sec;
154 end_time.tv_usec += tval->tv_usec;
155 end_time.tv_sec += end_time.tv_usec / 1000000;
156 end_time.tv_usec %= 1000000;
157 errno = 0;
158 tval2 = *tval;
159 ptval = &tval2;
160 } else {
161 ptval = NULL;
162 }
163
164 do {
165 if (readfds)
166 readfds_buf = *readfds;
167 if (writefds)
168 writefds_buf = *writefds;
169 if (errorfds)
170 errorfds_buf = *errorfds;
171 if (ptval && (errno == EINTR)) {
172 struct timeval now_time;
173 SMB_BIG_INT tdif;
174
175 GetTimeOfDay(&now_time);
176 tdif = usec_time_diff(&end_time, &now_time);
177 if (tdif <= 0) {
178 ret = 0; /* time expired. */
179 break;
180 }
181 ptval->tv_sec = tdif / 1000000;
182 ptval->tv_usec = tdif % 1000000;
183 }
184
185 /* We must use select and not sys_select here. If we use
186 sys_select we'd lose the fact a signal occurred when sys_select
187 read a byte from the pipe. Fix from Mark Weaver
188 <mark-clist@npsl.co.uk>
189 */
190 ret = select(maxfd, readfds2, writefds2, errorfds2, ptval);
191//printf("select2 called, ret = %d\n");
192 } while (ret == -1 && errno == EINTR);
193
194 if (readfds)
195 *readfds = readfds_buf;
196 if (writefds)
197 *writefds = writefds_buf;
198 if (errorfds)
199 *errorfds = errorfds_buf;
200
201 return ret;
202}
Note: See TracBrowser for help on using the repository browser.