/* $Id: ps_wait.c,v 1.3 90/11/30 16:22:15 spanachi Exp $ */

/*
 * Copyright (C) 1990 by Digital Equipment Corporation.
 * 
 * Author: Michael P. Altenhofen, CEC Karlsruhe e-mail:
 * Altenhofen@kampus.enet.dec.com
 * 
 * This file ist part of Shared X
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation without fee is hereby granted, but only for non-profit  use
 * and distribution,  and provided  that the copyright notice and this notice
 * is preserved on all copies.
 * 
 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */

/*****************************************************************
 * OS Depedent input routines:
 *
 *  WaitForSomething,  GetEvent
 *
 *****************************************************************/

#define PUBLIC extern

#define _USE_STRUCTS_
#define _USE_MASKS_
#define _XEVENTS_

#include "glob.h"

#include "utils.h"
#include "connection.h"
#include "io.h"

#undef PUBLIC

#include <X11/Xos.h>		/* for strings, fcntl, time */

#include <errno.h>
#include <signal.h>
#include <sys/types.h>

extern int errno;		/* Should be redundant! */



/*****************
 * WaitForSomething:
 *     Make the server suspend until there is
 *	1. data from clients or
 *	2. input events available or
 *	3. ddx notices something of interest (graphics
 *	   queue ready, etc.) or
 *	4. clients that have buffered replies/events are ready
 *
 *     If the time between INPUT events is
 *     greater than ScreenSaverTime, the display is turned off (or
 *     saved, depending on the hardware).  So, WaitForSomething()
 *     has to handle this also (that's why the select() has a timeout.
 *     For more info on ClientsWithInput, see ReadRequestFromClient().
 *     pClientsReady is a mask, the bits set are
 *     indices into the o.s. depedent table of available clients.
 *     (In this case, there is no table -- the index is the socket
 *     file descriptor.)
 *****************/

#if (mskcnt>4)
 /* This is a macro if mskcnt <= 4 */
ANYSET (src)
  long *src;
{
  int i;

  for (i = 0; i < mskcnt; i++)
    if (src[i])
      return (TRUE);
  return (FALSE);
}

#endif

WaitForSomething (pClientsReady, nready, pNewClients, nnew)
  ClientPtr *pClientsReady;
  int *nready;
  ClientPtr *pNewClients;
  int *nnew;
{
  int i;
  struct timeval waittime, *wt;
  long timeout;
  fd_set clientsReadable;
  fd_set clientsWritable;
  long curclient;
  int selecterr;

#ifdef	hpux
  long ready_inputs;		/* to tell HIL drivers about input */
#endif	/* hpux */

  *nready = 0;
  *nnew = 0;
  waittime.tv_sec = 1.0;
  waittime.tv_usec = 0.0;
  isItTimeToYield = 1;

  CLEARBITS (BITS (clientsReadable));
  if (!(ANYSET (BITS (ClientsWithInput)))) {

    /*
     * We need a while loop here to handle crashed connections and the screen
     * saver timeout
     */
    while (1) {
      wt = &waittime;

      COPYBITS (BITS (AllSockets), BITS (LastSelectMask));
      if (NewOutputPending)
	FlushAllOutput ();

      if (AnyClientsWriteBlocked) {
	COPYBITS (BITS (ClientsWriteBlocked), BITS (clientsWritable));
	i = select (MAXSOCKS, &LastSelectMask, &clientsWritable,
		    (int *) NULL, wt);
      }
      else
	i = select (MAXSOCKS, &LastSelectMask,
		    (int *) NULL, (int *) NULL, wt);
      selecterr = errno;

      if (i <= 0) {		/* An error or timeout occurred */
	CLEARBITS (BITS (clientsWritable));
	if (i < 0) {
#ifdef DEBUG
	  fprintf (stderr, "selecterr = %d\n", selecterr);
#endif
	  if (selecterr == EBADF) {	/* Some client disconnected */
	    CheckConnections ();
	    if (!ANYSET (BITS (AllClients)))
	      return;
	  }
	  else if (selecterr != EINTR)
	    ErrorF ("WaitForSomething(): select: errno=%d\n", selecterr);
	}
      }
      else {
	if (AnyClientsWriteBlocked && ANYSET (BITS (clientsWritable))) {
	  NewOutputPending = TRUE;
	  ORBITS (BITS (OutputPending),
		  BITS (clientsWritable),
		  BITS (OutputPending));
	  UNSETBITS (BITS (ClientsWriteBlocked),
		     BITS (clientsWritable));
	  if (!ANYSET (BITS (ClientsWriteBlocked)))
	    AnyClientsWriteBlocked = FALSE;
	}

#ifdef	hpux
	ready_inputs = BITS (LastSelectMask)[0];

	if (ready_inputs > 0)
	  store_inputs (ready_inputs);
	/* call the HIL driver to gather inputs. 	 */
#endif	/* hpux */

	MASKANDSETBITS (BITS (ReadyServers),
			BITS (LastSelectMask), BITS (AllServers));
	MASKANDSETBITS (BITS (clientsReadable),
			BITS (LastSelectMask), BITS (AllClients));
	if (BITS (LastSelectMask)[0] & WellKnownConnections)
	  EstablishNewConnections (pNewClients, nnew);
	if (*nnew || BITS (LastSelectMask)[0]
	    || (ANYSET (BITS (clientsReadable))))
	  break;
      }
    }
  }
  else {
    COPYBITS (BITS (ClientsWithInput), BITS (clientsReadable));
  }

  if (ANYSET (BITS (clientsReadable))) {
    for (i = 0; i < mskcnt; i++) {
      while (BITS (clientsReadable)[i]) {
	curclient = ffs (BITS (clientsReadable)[i]) - 1;
	pClientsReady[(*nready)++] =
	  Connections[curclient + (32 * i)];
	BITS (clientsReadable)[i] &= ~(1 << curclient);
      }
    }
  }
}
