summaryrefslogtreecommitdiff
path: root/src/io_sleep.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/io_sleep.c')
-rw-r--r--src/io_sleep.c317
1 files changed, 317 insertions, 0 deletions
diff --git a/src/io_sleep.c b/src/io_sleep.c
new file mode 100644
index 0000000..26aad82
--- /dev/null
+++ b/src/io_sleep.c
@@ -0,0 +1,317 @@
+/*
+Copyright (C) 2009 Andrey Nazarov
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "com_local.h"
+#include "sys_public.h"
+#include "io_sleep.h"
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winsock2.h>
+#else
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+static ioentry_t entries[FD_SETSIZE];
+static int numfds;
+
+ioentry_t *IO_Add( int fd ) {
+ ioentry_t *e;
+#ifdef _WIN32
+ int i;
+
+ for( i = 0, e = entries; i < numfds; i++, e++ ) {
+ if( !e->inuse ) {
+ break;
+ }
+ }
+
+ if( i == numfds ) {
+ if( ++numfds > FD_SETSIZE ) {
+ Com_Error( ERR_FATAL, "%s: no more space for fd: %d", __func__, fd );
+ }
+ }
+
+ e->fd = fd;
+#else
+
+#define CHECK_FD \
+ if( fd < 0 || fd >= FD_SETSIZE ) { \
+ Com_Error( ERR_FATAL, "%s: fd out of range: %d", __func__, fd ); \
+ }
+
+ CHECK_FD
+
+ if( fd >= numfds ) {
+ numfds = fd + 1;
+ }
+
+ e = &entries[fd];
+#endif
+ e->inuse = qtrue;
+ return e;
+}
+
+void IO_Remove( int fd ) {
+ ioentry_t *e;
+ int i;
+
+ e = IO_Get( fd );
+ memset( e, 0, sizeof( *e ) );
+
+ for( i = numfds - 1; i >= 0; i-- ) {
+ e = &entries[i];
+ if( e->inuse ) {
+ break;
+ }
+ }
+
+ numfds = i + 1;
+}
+
+ioentry_t *IO_Get( int fd ) {
+ ioentry_t *e;
+#ifdef _WIN32
+ int i;
+
+ for( i = 0, e = entries; i < numfds; i++, e++ ) {
+ if( !e->inuse ) {
+ continue;
+ }
+ if( e->fd == fd ) {
+ return e;
+ }
+ }
+
+ Com_Error( ERR_FATAL, "%s: fd not found: %d", __func__, fd );
+#else
+ CHECK_FD
+
+ e = &entries[fd];
+ return e;
+#endif
+}
+
+//void IO_Mask( int fd ) {
+//}
+
+/*
+====================
+IO_Sleep
+
+Sleeps msec or until some file descriptor is ready
+====================
+*/
+int IO_Sleep( int msec ) {
+ struct timeval timeout;
+ fd_set rfd, wfd;
+#ifdef _WIN32
+ fd_set efd;
+#endif
+ ioentry_t *e;
+ int i, ret;
+
+ if( !numfds ) {
+ // don't bother with select()
+ Sys_Sleep( msec );
+ return 0;
+ }
+
+ FD_ZERO( &rfd );
+ FD_ZERO( &wfd );
+#ifdef _WIN32
+ FD_ZERO( &efd );
+#endif
+
+#ifdef _WIN32
+#define FD e->fd
+#else
+#define FD i
+#endif
+
+ for( i = 0, e = entries; i < numfds; i++, e++ ) {
+ if( !e->inuse ) {
+ continue;
+ }
+ e->canread = qfalse;
+ if( e->wantread ) {
+ FD_SET( FD, &rfd );
+ }
+ e->canwrite = qfalse;
+ if( e->wantwrite ) {
+ FD_SET( FD, &wfd );
+ }
+#ifdef _WIN32
+ e->canexcept = qfalse;
+ if( e->wantexcept ) {
+ FD_SET( FD, &efd );
+ }
+#endif
+ }
+
+ timeout.tv_sec = msec / 1000;
+ timeout.tv_usec = ( msec % 1000 ) * 1000;
+
+ ret = select( numfds, &rfd, &wfd,
+#ifdef _WIN32
+ &efd,
+#else
+ NULL,
+#endif
+ &timeout );
+ if( ret == -1 ) {
+ Com_EPrintf( "%s: %s\n", __func__, strerror( errno ) );
+ return ret;
+ }
+
+ if( !ret ) {
+ return ret;
+ }
+
+ for( i = 0; i < numfds; i++ ) {
+ e = &entries[i];
+ if( !e->inuse ) {
+ continue;
+ }
+ if( e->wantread && FD_ISSET( FD, &rfd ) ) {
+ e->canread = qtrue;
+ }
+ if( e->wantwrite && FD_ISSET( FD, &wfd ) ) {
+ e->canwrite = qtrue;
+ }
+#ifdef _WIN32
+ if( e->wantexcept && FD_ISSET( FD, &efd ) ) {
+ e->canexcept = qtrue;
+ }
+#endif
+ }
+
+ return ret;
+}
+
+#if USE_AC_SERVER
+
+/*
+====================
+IO_Sleep
+
+Sleeps msec or until some file descriptor from a given subset is ready
+====================
+*/
+int IO_Sleepv( int msec, ... ) {
+ va_list argptr;
+ struct timeval timeout;
+ fd_set rfd, wfd;
+#ifdef _WIN32
+ fd_set efd;
+#endif
+ ioentry_t *e;
+ int i, ret;
+
+ if( !numfds ) {
+ // don't bother with select()
+ Sys_Sleep( msec );
+ return 0;
+ }
+
+ FD_ZERO( &rfd );
+ FD_ZERO( &wfd );
+#ifdef _WIN32
+ FD_ZERO( &efd );
+#endif
+
+ va_start( argptr, msec );
+ while( 1 ) {
+ i = va_arg( argptr, int );
+ if( i == -1 ) {
+ break;
+ }
+ e = &entries[i];
+ if( !e->inuse ) {
+ continue;
+ }
+ e->canread = qfalse;
+ if( e->wantread ) {
+ FD_SET( FD, &rfd );
+ }
+ e->canwrite = qfalse;
+ if( e->wantwrite ) {
+ FD_SET( FD, &wfd );
+ }
+#ifdef _WIN32
+ e->canexcept = qfalse;
+ if( e->wantexcept ) {
+ FD_SET( FD, &efd );
+ }
+#endif
+ }
+ va_end( argptr );
+
+ timeout.tv_sec = msec / 1000;
+ timeout.tv_usec = ( msec % 1000 ) * 1000;
+
+ ret = select( numfds, &rfd, &wfd,
+#ifdef _WIN32
+ &efd,
+#else
+ NULL,
+#endif
+ &timeout );
+ if( ret == -1 ) {
+ Com_EPrintf( "%s: %s\n", __func__, strerror( errno ) );
+ return ret;
+ }
+
+ if( !ret ) {
+ return ret;
+ }
+
+ va_start( argptr, msec );
+ while( 1 ) {
+ i = va_arg( argptr, int );
+ if( i == -1 ) {
+ break;
+ }
+ e = &entries[i];
+ if( !e->inuse ) {
+ continue;
+ }
+ if( e->wantread && FD_ISSET( FD, &rfd ) ) {
+ e->canread = qtrue;
+ }
+ if( e->wantwrite && FD_ISSET( FD, &wfd ) ) {
+ e->canwrite = qtrue;
+ }
+#ifdef _WIN32
+ if( e->wantexcept && FD_ISSET( FD, &efd ) ) {
+ e->canexcept = qtrue;
+ }
+#endif
+ }
+ va_end( argptr );
+
+ return ret;
+}
+
+#endif // USE_AC_SERVER
+