Ejemplo n.º 1
0
/*
 * Copyright (C) 1997 Massachusetts Institute of Technology 
 *
 * This software is being provided by the copyright holders under the
 * following license. By obtaining, using and/or copying this software,
 * you agree that you have read, understood, and will comply with the
 * following terms and conditions:
 *
 * Permission to use, copy, modify, distribute, and sell this software
 * and its documentation for any purpose and without fee or royalty is
 * hereby granted, provided that the full text of this NOTICE appears on
 * ALL copies of the software and documentation or portions thereof,
 * including modifications, that you make.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO
 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE,
 * BUT NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR
 * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
 * THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
 * THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT
 * HOLDERS WILL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE OR
 * DOCUMENTATION.
 *
 * The name and trademarks of copyright holders may NOT be used in
 * advertising or publicity pertaining to the software without specific,
 * written prior permission. Title to copyright in this software and any
 * associated documentation will at all times remain with copyright
 * holders. See the file AUTHORS which should have accompanied this software
 * for a list of all copyright holders.
 *
 * This file may be derived from previously copyrighted software. This
 * copyright applies only to those changes made by the copyright
 * holders listed in the AUTHORS file. The rest of this file is covered by
 * the copyright notices, if any, listed below.
 */

#include <exos/callcount.h>
#include <exos/uwk.h>
#include <xok/sysinfo.h>
#include <errno.h>
#include <sys/time.h>

#define DID_TIMEOUT 1
#define DID_SIGNAL 2
#define WK_SELECT_SZ 1024
#undef RATE
#define RATE (__sysinfo.si_rate*1000) /* nanoseconds per tick */
int
nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
{
  struct wk_term t[WK_SELECT_SZ];
  int next;
  unsigned long long absolute_ticks = 0;  

  OSCALLENTER(OSCALL_nanosleep);
  if (rqtp->tv_nsec < 0 || rqtp->tv_nsec >= 1000000000) {
    errno = EINVAL;
    OSCALLEXIT(OSCALL_nanosleep);
    return -1;
  }

  absolute_ticks = ((1000000000/RATE) * rqtp->tv_sec) +
    (rqtp->tv_nsec + RATE - 1)/RATE + __sysinfo.si_system_ticks;

  next = 0;
  next = wk_mktag(next, t, DID_TIMEOUT);
  next += wk_mksleep_pred(&t[next], absolute_ticks);
  next = wk_mkop(next, t, WK_OR);
  next = wk_mktag(next, t, DID_SIGNAL);
  next += wk_mksig_pred(&t[next]);
  wk_waitfor_pred(t, next);

  if (rmtp) {
    unsigned long long curticks = __sysinfo.si_system_ticks;
    if (curticks > absolute_ticks) curticks = absolute_ticks;
    rmtp->tv_sec = ((absolute_ticks - curticks)*RATE)/1000000000;
    rmtp->tv_nsec = ((absolute_ticks - curticks)*RATE) % 1000000000;
  }

  if (UAREA.u_pred_tag == DID_TIMEOUT) {
    OSCALLEXIT(OSCALL_nanosleep);
    return 0;
  }
  /* it is ok to return EINTR even if we are interrupted by a restartable signal */
  errno = EINTR;
  OSCALLEXIT(OSCALL_nanosleep);
  return -1;
}
Ejemplo n.º 2
0
/* read select for a single filp with timeout.  More efficient than
   using general select */
int
__select_single_filp(struct file *filp, struct timeval *timeout)
{
  unsigned long long wait_ticks = 0;  
  unsigned long long wait_until = 0;  
  unsigned int begin_ticks = 0;  

#define WK_SELECT_SZ 1024
  struct wk_term t[WK_SELECT_SZ];  
  int next;
#define DID_FDREADY 1		
#define DID_TIMEOUT 2
#define DID_SIGNAL 3
  assert(RATE);
  assert(filp->op_type == UDP_SOCKET_TYPE);
  /* Our basic algorithm is poll the fd's once. If any fd's are found
     ready return. Otherwise sleep until one of them might be ready
     and repeat the process. In practice we don't expect to go
     through this loop more than once, but theoretically we could
     wakeup for some reason other than haveing fd's ready. Am I just
     being paranoid? */

  /* Note: we can _definitely_ go thru this loop more than once, because
     in some cases (e.g., TCP), we can only sleep on an "indication" that
     select might pass (e.g., a packet arrived).  We have to then call
     select to find out if it does in fact make the socket ready, and rebuild
     the sleep predicate otherwise. */

    /* do a poll on the fd's. We want to make sure that we do this
       before sleeping so on the first time through the do loop we
       avoid descheduling and having to wait till we're re-scheduled
       before noticing that there're fd's ready. */

  for(;;) {
    if (DOOP (filp, select, (filp, SELECT_READ))) {
      //kprintf("& %d",(int)__sysinfo.si_system_ticks);
      return 1;
    }
    
    /* if the user is just polling, handle that now before going through
     all the work to construct a predicate */
    
    if (timeout) {
      wait_ticks = ((1000000/RATE) * timeout->tv_sec) + timeout->tv_usec/RATE;
      if (!wait_ticks) {
//	kprintf("%");

	return 0;
      }
    }
    
    /* now construct a wakeup-predicate that will wake us when something
       interesting happens on these fd's. We call each fd's select_pred
       operation which returns a clause of the final predicate. All
       clauses are combined into one large predicate that we'll sleep on. */
    
    next = 0;
    next = wk_mktag (next, t, DID_FDREADY);
    
    next += DOOP (filp,select_pred,(filp,SELECT_READ,&t[next]));
    
    /* slap on a final term to wake us when the timeout occurrs, if there
       is one */

    begin_ticks = (int)__sysinfo.si_system_ticks;
    wait_until = wait_ticks + __sysinfo.si_system_ticks;
    if (timeout) {
      next = wk_mkop (next, t, WK_OR);
      next = wk_mktag (next, t, DID_TIMEOUT);
      next += wk_mksleep_pred (&t[next], wait_until);
    }

	/* we need to wakup if a signal comes in */
    next = wk_mkop (next, t, WK_OR);
    next = wk_mktag (next, t, DID_SIGNAL);
    next += wk_mksig_pred (&t[next]);

	/* wait for predicate to evaluate to true */
    wk_waitfor_pred (t, next);
    
    /* u_pred_tag is set to the piece of the predicate that caused
       us to wake up */
    
    if (UAREA.u_pred_tag == DID_TIMEOUT) {
//#if 0
      kprintf("timeout wt %d rate %d\n",
	      (int)wait_ticks,(unsigned int)(RATE));
      kprintf("Timeout sec: %ld usec: %ld\n",timeout->tv_sec,timeout->tv_usec);
      kprintf("begin ticks: %d sleep until ticks: %d si_system_ticks: %d\n",
	      begin_ticks,(int)wait_until,(int)__sysinfo.si_system_ticks);
//#endif
      return 0;
    }

  } 
}
Ejemplo n.º 3
0
int
select(int width, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
	   struct timeval *timeout)
{
  unsigned int wait_ticks = 0;  
  int fd;
#define WK_SELECT_SZ 1024
  struct wk_term t[WK_SELECT_SZ];  
  int next;
  int total = 0;
  fd_set newreadfds, newwritefds, newexceptfds;
#define DID_FDREADY 1		
#define DID_TIMEOUT 2
#define DID_SIGNAL 3
  struct file *filp;
  int had_prev_term;

  OSCALLENTER(OSCALL_select);
  width = MIN (width+1, NR_OPEN);

  /* make sure that all fd's set to be polled are valid fd's */

  for (fd = 0; fd < width; fd++) {
    if ((readfds && FD_ISSET (fd, readfds)) || 
	(writefds && FD_ISSET (fd, writefds)) ||
	(exceptfds && FD_ISSET (fd, exceptfds))) {
      CHECKFD(fd, OSCALL_select);
      assert (CHECKOP (__current->fd[fd], select));
      assert (CHECKOP (__current->fd[fd], select_pred));
    }
  }

  FD_ZERO(&newreadfds);
  FD_ZERO(&newwritefds);
  FD_ZERO(&newexceptfds);

  /* Our basic algorithm is poll the fd's once. If any fd's are found
     ready return. Otherwise sleep until one of them might be ready
     and repeat the process. In practice we don't expect to go
     through this loop more than once, but theoretically we could
     wakeup for some reason other than haveing fd's ready. Am I just
     being paranoid? */

  /* Note: we can _definitely_ go thru this loop more than once, because
     in some cases (e.g., TCP), we can only sleep on an "indication" that
     select might pass (e.g., a packet arrived).  We have to then call
     select to find out if it does in fact make the socket ready, and rebuild
     the sleep predicate otherwise. */

  do {

    had_prev_term = 0;

    /* do a poll on the fd's. We want to make sure that we do this
       before sleeping so on the first time through the do loop we
       avoid descheduling and having to wait till we're re-scheduled
       before noticing that there're fd's ready. */

    for (fd = 0; fd < width; fd++) {
      if (readfds && FD_ISSET (fd, readfds))
	if (DOOP (__current->fd[fd], select, (__current->fd[fd], SELECT_READ))) {
	  total++;
	  FD_SET (fd, &newreadfds);
	}
      if (writefds && FD_ISSET (fd, writefds))
	if (DOOP (__current->fd[fd], select, (__current->fd[fd], SELECT_WRITE))) {
	  total++;
	  FD_SET (fd, &newwritefds);
	}	
      if (SELECT_EXCEPT_CONDITIONS && exceptfds && FD_ISSET (fd, exceptfds))
	if (DOOP (__current->fd[fd], select, (__current->fd[fd], SELECT_EXCEPT))) {
	  total++;
	  FD_SET (fd, &newexceptfds);
	}	
    }

    /* ok, we found some fd's that we need to report. Replace the
       fdsets the user passed in with fdsets containing which
       fd's are ready and return the total number of fd's ready. */

    if (total) {
      if (readfds)
	copyfds (readfds, &newreadfds, width);
      if (writefds)
	copyfds (writefds, &newwritefds, width);
      if (exceptfds)
	copyfds (exceptfds, &newexceptfds, width);
      /* XXX */
      OSCALLEXIT(OSCALL_select);
      return total;
    }

    /* if the user is just polling, handle that now before going through
       all the work to construct a predicate */

    if (timeout) {
      wait_ticks = ((1000000/RATE) * timeout->tv_sec) +
	(timeout->tv_usec + RATE - 1)/RATE;
      if (!wait_ticks)
	{
	  if (readfds) FD_ZERO(readfds);
	  if (writefds) FD_ZERO(writefds);
	  if (exceptfds) FD_ZERO(exceptfds);
	  OSCALLEXIT(OSCALL_select);
	  return 0;
	}
    }

    /* now construct a wakeup-predicate that will wake us when something
       interesting happens on these fd's. We call each fd's select_pred
       operation which returns a clause of the final predicate. All
       clauses are combined into one large predicate that we'll sleep on. */

    next = 0;
    had_prev_term = 0;
    next = wk_mktag (next, t, DID_FDREADY);
    for (fd = 0; fd < width; fd++) {
      filp = __current->fd[fd];
      if (readfds && FD_ISSET (fd, readfds)) {
	if (had_prev_term)
	  next = wk_mkop (next, t, WK_OR);	
	next += DOOP (filp,select_pred,(filp,SELECT_READ,&t[next]));
	had_prev_term = 1;
      }
	  
      if (writefds && FD_ISSET (fd, writefds)) {
	if (had_prev_term)
	  next = wk_mkop (next, t, WK_OR);	
	next += DOOP (filp,select_pred,(filp,SELECT_WRITE,&t[next]));	
	had_prev_term = 1;
      }

      if (SELECT_EXCEPT_CONDITIONS && exceptfds && FD_ISSET (fd, exceptfds)) {
	if (had_prev_term)
	  next = wk_mkop (next, t, WK_OR);	
	next += DOOP (filp,select_pred,(filp,SELECT_EXCEPT,&t[next]));	
	had_prev_term = 1;
      }
    }
    /* slap on a final term to wake us when the timeout occurrs, if there
       is one */

    if (timeout) {
      if (had_prev_term)
	next = wk_mkop (next, t, WK_OR);
      next = wk_mktag (next, t, DID_TIMEOUT);
      next += wk_mksleep_pred (&t[next], wait_ticks + __sysinfo.si_system_ticks);
      had_prev_term = 1;
    }

    /* we need to wakeup if a signal comes in */
    if (had_prev_term) {
       next = wk_mkop (next, t, WK_OR);
    }
    next = wk_mktag (next, t, DID_SIGNAL);
    next += wk_mksig_pred (&t[next]);
    had_prev_term = 1;
    
    /* wait for predicate to evaluate to true */
    wk_waitfor_pred (t, next);

    /* u_pred_tag is set to the piece of the predicate that caused
       us to wake up */

    if (UAREA.u_pred_tag == DID_TIMEOUT) {
      if (readfds) FD_ZERO(readfds);
      if (writefds) FD_ZERO(writefds);
      if (exceptfds) FD_ZERO(exceptfds);
      OSCALLEXIT(OSCALL_select);
      return 0;
    }
    if (UAREA.u_pred_tag == DID_SIGNAL) {
      //kprintf("%d select interrupted by signal\n",getpid());
      errno = EINTR;
      OSCALLEXIT(OSCALL_select);
      return -1;
    }
  
  } while (1);
}
Ejemplo n.º 4
0
/* could implement tsleep in terms of following tsleep_pred */
int tsleep (void *chan, int pri, char *wmesg, int ticks) {
#define PREDSZ 32
  struct wk_term t[PREDSZ];
  int sz = 0;
  int sig = 0;
  int catch = pri & PCATCH;
  void **wchan;
  int ret, i, CriticalLevels;
  unsigned long long dest_ticks = ticks;
retry:
  sz = 0;
  d0printf("%d tsleep chan: %p, catch: %d, ticks: %d (lbolt? %d)\n",
	  getpid(),chan, catch ?1:0, ticks, chan == &lbolt);

  global_ftable->counter0++;
  if (chan == &lbolt)   global_ftable->counter2++;

  wchan = &synch_table->wchan[envidx(__envid)];
  *wchan = chan;

  /* for timeout */
  if (dest_ticks) {
    dest_ticks += __sysinfo.si_system_ticks; 
    sz += wk_mksleep_pred(t, dest_ticks); /* t is fine since it is first */
    sz = wk_mkop(sz, t, WK_OR);
  }
  /* for channel */
  if (chan != &lbolt) {
    sz = wk_mkvar (sz, t, wk_phys (wchan), 0);
    sz = wk_mkimm (sz, t, 0);
    sz = wk_mkop (sz, t, WK_EQ);
  } else {
    /* sleep for 0.5 seconds */
    sz += wk_mksleep_pred(&t[sz],(500000/__sysinfo.si_rate) +
			  __sysinfo.si_system_ticks);
  }
  /* for signals */
  if (catch) {
    //kprintf("%d tsleep interruptible (sigready? %d)\n",getpid(),__issigready());

    if ((sig = __issigready())) goto resume;
    sz = wk_mkop(sz, t, WK_OR);
    sz += wk_mksig_pred(&t[sz]);
  }

  assert(sz <= PREDSZ);
  /* make sure when sleeping on lbolt => no ticks */
  assert(!(chan == &lbolt && dest_ticks != 0)); 

  /* Leave and then Enter Critical Region */
  i = CriticalLevels = CriticalNesting();  assert(i >= 0);
  while (i-- > 0) ExitCritical(); assert(CriticalNesting() == 0);
  
  wk_waitfor_pred (t, sz);

  i = 0; while (i++ < CriticalLevels) EnterCritical();
  assert(CriticalLevels == CriticalNesting());

resume:
  ret = 0;
  if (catch && (sig != 0 || (sig = __issigready()))) {
    /* there is a signal ready */
    //kprintf("%d tsleep interrupted by a signal: %d (%s)\n",getpid(),sig,sys_signame[sig]);
    if (__issigstopping(sig)) {
      __signal_stop_process(sig);
      goto retry;
    }
    if (__issigrestart(sig)) ret = ERESTART;
    else ret = EINTR;
    goto done;
  }
  if (chan != &lbolt && dest_ticks && __sysinfo.si_system_ticks > dest_ticks) {
    ret = EWOULDBLOCK;
  }
done:
  d0printf("%d tsleep ret: %d chan: %p, catch: %d, dest_ticks: %qu (lbolt? %d) -> %d\n",
	  getpid(),ret,chan, catch ?1:0, dest_ticks, chan == &lbolt, ret);
  /* clear waiting channel */
  *wchan = 0;
  return ret;
}