static inline int wk_mkneq_pred(int sz, struct wk_term *t, int *addr, int value, u_int cap) { sz = wk_mkvar (sz, t, wk_phys (addr), cap); sz = wk_mkimm (sz, t, value); sz = wk_mkop (sz, t, WK_NEQ); return (sz); }
static int wk_mktty_pred (struct wk_term *t, void *p, int ticks) { int s = 0; #undef WK_TTY_PRED_SZ #define WK_TTY_PRED_SZ 7 s = wk_mkvar (s, t, wk_phys (p), 0); s = wk_mkimm (s, t, 0); s = wk_mkop (s, t, WK_EQ); if (ticks) { s = wk_mkop (s, t, WK_OR); s = wk_mkvar (s, t, wk_phys (&__sysinfo.si_system_ticks), 0); s = wk_mkimm (s, t, ticks); s = wk_mkop (s, t, WK_GT); } return (s); }
void exos_bufcache_waitforio (struct bc_entry *bc_entry) { assert (bc_entry != NULL); if (exos_bufcache_isiopending (bc_entry)) { struct wk_term t[(2*UWK_MKCMP_EQ_PRED_SIZE)+1]; int sz = 0; sz += wk_mkcmp_eq_pred (&t[sz], &bc_entry->buf_state, BC_VALID, CAP_ROOT); sz = wk_mkop (sz, t, WK_OR); sz += wk_mkcmp_eq_pred (&t[sz], &bc_entry->buf_state, BC_EMPTY, CAP_ROOT); wk_waitfor_pred (t, sz); } }
/* * 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; }
void xio_tcp_waitforChange (xio_nwinfo_t *nwinfo, u_quad_t timeout) { #ifdef EXOPC #define XIO_PRED_LEN 64 struct wk_term t[XIO_PRED_LEN]; int predlen; u_int delta; u_quad_t current_time = __ticks2usecs (__sysinfo.si_system_ticks); delta = timeout - current_time; /* don't sleep if we're past or almost at our timeout. */ //kprintf ("timeout = %qd current_time = %qd\n", timeout, current_time); predlen = xio_net_wrap_wkpred_packetarrival (nwinfo, t); if (predlen != -1) { if (timeout) { if (timeout < current_time) delta = 0; predlen = wk_mkop (predlen, t, WK_OR); //delta = 250000; predlen += wk_mkusleep_pred (&t[predlen], delta); } assert ((predlen > 0) && (predlen <= XIO_PRED_LEN)); wk_waitfor_pred (t, predlen); } #else /* do a blocking select on the fd that is nwinfo->ringid, */ /* with max time equal to the timeout time */ fd_set fds; struct timeval tv; int timeout = ((tcb) && (tcb->timer_retrans)); int ret; if (nwinfo->ringid < 0) { return; } FD_ZERO (&fds); FD_SET (nwinfo->ringid, &fds); if (timeout) { assert (0); /* timer_retrans is now in usecs */ tv.tv_sec = max (0, tcb->timer_retrans - time(NULL)); tv.tv_usec = 0; } #if 0 else { tv.tv_sec = 10; tv.tv_usec = 0; } ret = select ((nwinfo->ringid + 1), &fds, NULL, NULL, &tv); #else ret = select ((nwinfo->ringid + 1), &fds, NULL, NULL, ((timeout) ? &tv : NULL)); #endif #if 0 if (ret <= 0) { printf ("xio_tcp_waitfor timeout (ret %d, tcb %p, timeout %d)\n", ret, tcb, (int)((tcb) ? (tcb->timer_retrans - time(NULL)) : -1)); } #endif #endif }
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); }
/* 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; } } }
/* 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; }