ftp.nice.ch/Attic/openStep/implementation/gnustep/sources/alpha-snapshots/pthreads.0.9.2.tgz#/pthreads-0.9.2/socklib/select.c

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( &current, NULL );
   elapsed_usec = diff_timevals( &current, 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.