root/source3/lib/select.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sys_select_signal
  2. sys_select
  3. sys_select_intr

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

/* [<][>][^][v][top][bottom][index][help] */