diff options
Diffstat (limited to 'source3/lib')
-rw-r--r-- | source3/lib/select.c | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/source3/lib/select.c b/source3/lib/select.c new file mode 100644 index 0000000000..cd77d1209f --- /dev/null +++ b/source3/lib/select.c @@ -0,0 +1,107 @@ +/* + Unix SMB/Netbios implementation. + Version 3.0 + Samba select/poll implementation + Copyright (C) Andrew Tridgell 1992-1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* this is here because it allows us to avoid a nasty race in signal handling. + We need to guarantee that when we get a signal we get out of a select immediately + but doing that involves a race condition. We can avoid the race by getting the + signal handler to write to a pipe that is in the select/poll list + + this means all Samba signal handlers should call sys_select_signal() +*/ +static int initialised; +static int select_pipe[2]; +static unsigned pipe_written, pipe_read; + + +/******************************************************************* +call this from all Samba signal handlers if you want to avoid a +nasty signal race condition +********************************************************************/ +void sys_select_signal(void) +{ + char c = 1; + if (!initialised) return; + + if (pipe_written > pipe_read+256) return; + + if (write(select_pipe[1], &c, 1) == 1) pipe_written++; +} + +/******************************************************************* +like select() but avoids the signal race using a pipe +it also guuarantees that fds on return only ever contains bits set +for file descriptors that were readable +********************************************************************/ +int sys_select(int maxfd, fd_set *fds,struct timeval *tval) +{ + int ret; + + if (!initialised) { + initialised = 1; + pipe(select_pipe); + } + + maxfd = MAX(select_pipe[0], maxfd); + FD_SET(select_pipe[0], fds); + errno = 0; + ret = select(maxfd,fds,NULL,NULL,tval); + + if (ret <= 0) { + FD_ZERO(fds); + } + + if (FD_ISSET(select_pipe[0], fds)) { + FD_CLR(select_pipe[0], fds); + ret--; + if (ret == 0) { + ret = -1; + errno = EINTR; + } + } + + while (pipe_written != pipe_read) { + char c; + if (read(select_pipe[0], &c, 1) == 1) pipe_read++; + } + + return ret; +} + +/******************************************************************* +similar to sys_select() but catch EINTR and continue +this is what sys_select() used to do in Samba +********************************************************************/ +int sys_select_intr(int maxfd, fd_set *fds,struct timeval *tval) +{ + int ret; + fd_set fds2; + + do { + fds2 = *fds; + ret = sys_select(maxfd, &fds2, tval); + } while (ret == -1 && errno == EINTR); + + *fds = fds2; + + return ret; +} |