This is select.c in view mode; [Download] [Up]
#include <stdio.h>
#include <errno.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include "pthread_socket.h"
#include "pthread_io_delay.h"
const struct timespec delay_interval = { 0, 100000 };
int
syscall_select( int nd,
fd_set * in,
fd_set * out,
fd_set * ex,
struct timeval * tv);
#define MAKE_TIMEVAL(t,ms) \
{ \
(t)->tv_sec = (ms) / 1000000; \
(t)->tv_usec = (ms) % 1000000; \
}
#define MICROSECONDS(t) ((t)->tv_sec * 1000000 + (t)->tv_usec)
#define TV_CLEAR(t) \
{ \
(t)->tv_sec = 0; (t)->tv_usec = 0; \
}
static long
diff_timevals( const struct timeval *t1, const struct timeval *t2 )
{
return( MICROSECONDS(t1) - MICROSECONDS(t2) );
}
static int
timeout_expired( struct timeval *xt )
{
int expired = FALSE;
struct timeval curr, *t_ptr;
if( xt == NULL || xt->tv_sec == -1 )
return( FALSE );
gettimeofday( &curr, NULL );
t_ptr = &curr;
if( MICROSECONDS(t_ptr) > MICROSECONDS(xt) )
expired = TRUE;
return( expired );
}
static void
update_timeout_interval( const struct timeval *start, struct timeval *interval )
{
struct timeval current;
long elapsed_usec, interval_usec;
if( interval == NULL )
return;
gettimeofday( ¤t, NULL );
elapsed_usec = diff_timevals( ¤t, start );
interval_usec = MICROSECONDS( interval );
if( elapsed_usec >= interval_usec )
{
interval->tv_sec = 0;
interval->tv_usec = 0;
}
else
MAKE_TIMEVAL(interval, (interval_usec - elapsed_usec));
}
static void
get_expiration_time( struct timeval *xt,
struct timeval *st,
const struct timeval *it )
{
unsigned long usecs;
if( it == NULL )
return; /* expiration_time = {-1, -1} */
gettimeofday( st, NULL );
usecs = MICROSECONDS(st) + MICROSECONDS(it);
xt->tv_sec = usecs / 1000000;
xt->tv_usec = usecs % 1000000;
}
/*--------------------------------------------------------------------------
* @@ S E L E C T
*-------------------------------------------------------------------------*/
int
select( int nfds,
fd_set *readfds,
fd_set *writefds,
fd_set *exceptfds,
struct timeval *timeout_interval )
{
int result = 0;
struct timeval expiration_time = {-1, -1};
struct timeval no_wait = {0, 0};
struct timeval start;
long id;
/*
* If the caller wants a zero timeout interval, return after
* one call to select. Evidently, the caller is setting up
* her own polling mechanism.
*/
if( timeout_interval != NULL && MICROSECONDS( timeout_interval ) == 0 )
return( syscall_select( nfds, readfds, writefds, exceptfds, &no_wait ));
get_expiration_time( &expiration_time, &start, timeout_interval );
id = pthread_getsequence_np( pthread_self());
while( (result = syscall_select( nfds,
readfds,
writefds,
exceptfds,
&no_wait )) <= 0 )
{
if( result < OK )
break;
pthread_delay_np( &delay_interval );
if( timeout_expired( &expiration_time ))
break;
}
/*
* Update the timeout interval because that's what Linux does.
* @@ Not all systems do this @@
*/
update_timeout_interval( &start, timeout_interval );
return( result );
}
/*
* syscall_select() is a wrapper around the select() system call. Note
* that this service returns -1 on error with errno set appropriately.
* Because errno gets set in this call, we have to surround it with
* a lock.
*/
int
syscall_select( int nd,
fd_set * in,
fd_set * out,
fd_set * ex,
struct timeval * tv)
{
long __res;
#if defined(__PIC__) || defined (__pic__)
__asm__ volatile ("pushl %%ebx\n\t"
"movl %%ecx,%%ebx\n\t"
"int $0x80\n\t"
"popl %%ebx"
: "=a" (__res)
: "0" (SYS_select),"c" ((long) &nd));
#else
__asm__ volatile ("int $0x80"
: "=a" (__res)
: "0" (SYS_select),"b" ((long) &nd));
#endif
if (__res >= 0)
return (int) __res;
pthread_lock_global_np();
errno = -__res; /* Make errno a positive number */
pthread_set_errno_np( errno );
pthread_unlock_global_np();
return( -1 );
}
#include <gnu-stabs.h>
#ifdef weak_alias
weak_alias (__select, select);
#endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.