1155420Sharti/* 2155420Sharti * Copyright (c)1996-2002 by Hartmut Brandt 3155420Sharti * All rights reserved. 4155420Sharti * 5155420Sharti * Author: Hartmut Brandt 6155420Sharti * 7155420Sharti * Redistribution of this software and documentation and use in source and 8155420Sharti * binary forms, with or without modification, are permitted provided that 9155420Sharti * the following conditions are met: 10155420Sharti * 11155420Sharti * 1. Redistributions of source code or documentation must retain the above 12155420Sharti * copyright notice, this list of conditions and the following disclaimer. 13155420Sharti * 2. Redistributions in binary form must reproduce the above copyright 14155420Sharti * notice, this list of conditions and the following disclaimer in the 15155420Sharti * documentation and/or other materials provided with the distribution. 16155420Sharti * 17155420Sharti * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE AUTHOR 18155420Sharti * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 19155420Sharti * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20155420Sharti * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21155420Sharti * THE AUTHOR OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22155420Sharti * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23155420Sharti * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 24155420Sharti * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 25155420Sharti * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26155420Sharti * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 27155420Sharti * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28155420Sharti */ 29155420Sharti/* 30155420Sharti * These functions try to hide the poll/select/setitimer interface from the 31155420Sharti * user. You associate callback functions with file descriptors and timers. 32155420Sharti * 33155420Sharti * $Begemot: libbegemot/rpoll.c,v 1.14 2004/09/21 15:59:00 brandt Exp $ 34155420Sharti */ 35155420Sharti# include <stdio.h> 36155420Sharti# include <stdlib.h> 37155420Sharti# include <stddef.h> 38155420Sharti# include <stdarg.h> 39155420Sharti# include <signal.h> 40155420Sharti# include <string.h> 41155420Sharti# include <errno.h> 42155420Sharti# include <time.h> 43155420Sharti# include <assert.h> 44155420Sharti# include <unistd.h> 45155420Sharti# include <sys/time.h> 46155420Sharti 47155420Sharti/* 48155420Sharti * There happens to be linuxes which read siginfo.h when including 49155420Sharti * signal.h, which, for no appearent reason, defines these symbols. 50155420Sharti */ 51155420Sharti# ifdef POLL_IN 52155420Sharti# undef POLL_IN 53155420Sharti# endif 54155420Sharti# ifdef POLL_OUT 55155420Sharti# undef POLL_OUT 56155420Sharti# endif 57155420Sharti 58155420Sharti# include "rpoll.h" 59155420Sharti 60155420Sharti/* 61155420Sharti# define DEBUG 62155420Sharti*/ 63155420Sharti 64155420Sharti# ifdef USE_POLL 65155420Sharti# ifdef NEED_POLL_XOPEN_TWIDDLE 66155420Sharti# define __USE_XOPEN 67155420Sharti# endif 68155420Sharti# include <poll.h> 69155420Sharti# ifdef NEED_POLL_XOPEN_TWIDDLE 70155420Sharti# undef __USE_XOPEN 71155420Sharti# endif 72155420Sharti# include <stropts.h> 73155420Sharti# endif 74155420Sharti 75155420Sharti/* 76155420Sharti * the second define is for Linux, which sometimes fails to 77155420Sharti * declare INFTIM. 78155420Sharti */ 79155420Sharti# if defined(USE_SELECT) || !defined(INFTIM) 80155420Sharti# define INFTIM (-1) 81155420Sharti# endif 82155420Sharti 83155420Sharti# if defined(SIGPOLL) 84155420Sharti# define SIGNAL SIGPOLL 85155420Sharti# else 86155420Sharti# if defined(SIGIO) 87155420Sharti# define SIGNAL SIGIO 88155420Sharti# endif 89155420Sharti# endif 90155420Sharti 91155420Sharti# ifdef USE_POLL 92155420Sharti# define poll_in (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI) 93155420Sharti# define poll_out (POLLOUT | POLLWRNORM | POLLWRBAND) 94155420Sharti# define poll_except (POLLERR | POLLHUP) 95155420Sharti# endif 96155420Sharti 97155420Sharti# ifdef BROKEN_SELECT_PROTO 98155420Sharti# define SELECT_CAST(P) (int *)P 99155420Sharti# else 100155420Sharti# define SELECT_CAST(P) P 101155420Sharti# endif 102155420Sharti 103155420Sharti 104165009Shartitypedef int64_t tval_t; 105155420Sharti 106165009Shartistatic inline tval_t GETUSECS(void); 107155420Sharti 108155420Shartistatic inline tval_t 109165009ShartiGETUSECS(void) { 110155420Sharti struct timeval tval; 111155420Sharti 112155420Sharti (void)gettimeofday(&tval, NULL); 113165009Sharti return (tval_t)tval.tv_sec * 1000000 + tval.tv_usec; 114155420Sharti} 115155420Sharti 116155420Sharti/* 117155420Sharti * Simple fatal exit. 118155420Sharti */ 119155420Shartistatic void 120155420Sharti_panic(const char *fmt, ...) 121155420Sharti{ 122155420Sharti va_list ap; 123155420Sharti 124155420Sharti va_start(ap, fmt); 125155420Sharti fprintf(stderr, "panic: "); 126155420Sharti vfprintf(stderr, fmt, ap); 127155420Sharti fprintf(stderr, "\n"); 128155420Sharti va_end(ap); 129155420Sharti 130155420Sharti exit(1); 131155420Sharti} 132155420Sharti 133155420Shartistatic void * 134155420Sharti_xrealloc(void *p, size_t s) 135155420Sharti{ 136155420Sharti void *ptr; 137155420Sharti 138155420Sharti if(p == NULL) { 139155420Sharti if((ptr=malloc(s)) == NULL && (s!=0 || (ptr=malloc(1)) == NULL)) 140155420Sharti _panic("out of memory: xrealloc(%lx, %lu)", 141155420Sharti (unsigned long)p, (unsigned long)s); 142155420Sharti } else if(s == 0) { 143155420Sharti free(p); 144155420Sharti if((ptr=malloc(s)) == NULL && (ptr=malloc(1)) == NULL) 145155420Sharti _panic("out of memory: xrealloc(%lx, %lu)", 146155420Sharti (unsigned long)p, (unsigned long)s); 147155420Sharti } else { 148155420Sharti if((ptr = realloc(p, s)) == NULL) 149155420Sharti _panic("out of memory: xrealloc(%lx, %lu)", 150155420Sharti (unsigned long)p, (unsigned long)s); 151155420Sharti } 152155420Sharti 153155420Sharti return ptr; 154155420Sharti} 155155420Sharti 156155420Sharti/* 157155420Sharti * This structure holds one registration record for files 158155420Sharti */ 159155420Shartitypedef struct { 160155420Sharti int fd; /* file descriptor (-1 if struct unused) */ 161155420Sharti int mask; /* event flags */ 162155420Sharti void * arg; /* client arg */ 163155420Sharti poll_f func; /* handler */ 164155420Sharti# ifdef USE_POLL 165155420Sharti struct pollfd *pfd; /* pointer to corresponding poll() structure */ 166155420Sharti# endif 167155420Sharti} PollReg_t; 168155420Sharti 169155420Sharti/* 170155420Sharti * Now for timers 171155420Sharti */ 172155420Shartitypedef struct { 173165009Sharti uint64_t usecs; /* microsecond value of the timer */ 174155420Sharti int repeat; /* one shot or repeat? */ 175155420Sharti void *arg; /* client arg */ 176155420Sharti timer_f func; /* handler, 0 means disfunct */ 177165009Sharti tval_t when; /* next time to trigger in usecs! */ 178155420Sharti} PollTim_t; 179155420Sharti 180155420Sharti/* how many records should our table grow at once? */ 181155420Sharti# define POLL_REG_GROW 100 182155420Sharti 183155420Sharti# ifdef USE_POLL 184155420Shartistatic struct pollfd * pfd; /* fd list for poll() */ 185155420Sharti# endif 186155420Sharti 187155420Sharti# ifdef USE_SELECT 188155420Shartistatic fd_set rset, wset, xset; /* file descriptor sets for select() */ 189155420Shartistatic int maxfd; /* maximum fd number */ 190155420Sharti# endif 191155420Sharti 192155420Shartistatic int in_dispatch; 193155420Sharti 194155420Shartistatic PollReg_t * regs; /* registration records */ 195155420Shartistatic u_int regs_alloc; /* how many are allocated */ 196155420Shartistatic u_int regs_used; /* upper used limit */ 197155420Shartistatic sigset_t bset; /* blocked signals */ 198155420Shartistatic int rebuild; /* rebuild table on next dispatch() */ 199155420Sharti 200155420Shartistatic int * tfd; /* sorted entries */ 201155420Shartistatic u_int tfd_alloc; /* number of entries allocated */ 202155420Shartistatic u_int tfd_used; /* number of entries used */ 203155420Shartistatic PollTim_t * tims; /* timer registration records */ 204155420Shartistatic u_int tims_alloc; /* how many are allocated */ 205155420Shartistatic u_int tims_used; /* how many are used */ 206155420Shartistatic int resort; /* resort on next dispatch */ 207155420Sharti 208155420Shartiint rpoll_trace; 209155420Shartiint rpoll_policy; /* if 0 start sched callbacks from 0 else try round robin */ 210155420Sharti 211155420Shartistatic void poll_build(void); 212155420Shartistatic void poll_blocksig(void); 213155420Shartistatic void poll_unblocksig(void); 214155420Shartistatic void sort_timers(void); 215155420Sharti 216155420Sharti 217155420Sharti/* 218155420Sharti * Private function to block SIGPOLL or SIGIO for a short time. 219155420Sharti * Don't forget to call poll_unblock before return from the calling function. 220155420Sharti * Don't change the mask between this calls (your changes will be lost). 221155420Sharti */ 222155420Shartistatic void 223155420Shartipoll_blocksig(void) 224155420Sharti{ 225155420Sharti sigset_t set; 226155420Sharti 227155420Sharti sigemptyset(&set); 228155420Sharti sigaddset(&set, SIGNAL); 229155420Sharti 230155420Sharti if(sigprocmask(SIG_BLOCK, &set, &bset)) 231155420Sharti _panic("sigprocmask(SIG_BLOCK): %s", strerror(errno)); 232155420Sharti} 233155420Sharti 234155420Sharti/* 235155420Sharti * unblock the previously blocked signal 236155420Sharti */ 237155420Shartistatic void 238155420Shartipoll_unblocksig(void) 239155420Sharti{ 240155420Sharti if(sigprocmask(SIG_SETMASK, &bset, NULL)) 241155420Sharti _panic("sigprocmask(SIG_SETMASK): %s", strerror(errno)); 242155420Sharti} 243155420Sharti 244155420Sharti/* 245155420Sharti * Register the file descriptor fd. If the event corresponding to 246155420Sharti * mask arrives func is called with arg. 247155420Sharti * If fd is already registered with that func and arg, only the mask 248155420Sharti * is changed. 249155420Sharti * We block the IO-signal, so the dispatch function can be called from 250155420Sharti * within the signal handler. 251155420Sharti */ 252155420Shartiint 253155420Shartipoll_register(int fd, poll_f func, void *arg, int mask) 254155420Sharti{ 255155420Sharti PollReg_t * p; 256155420Sharti 257155420Sharti poll_blocksig(); 258155420Sharti 259155420Sharti /* already registered? */ 260155420Sharti for(p = regs; p < ®s[regs_alloc]; p++) 261155420Sharti if(p->fd == fd && p->func == func && p->arg == arg) { 262155420Sharti p->mask = mask; 263155420Sharti break; 264155420Sharti } 265155420Sharti 266155420Sharti if(p == ®s[regs_alloc]) { 267155420Sharti /* no - register */ 268155420Sharti 269155420Sharti /* find a free slot */ 270155420Sharti for(p = regs; p < ®s[regs_alloc]; p++) 271155420Sharti if(p->fd == -1) 272155420Sharti break; 273155420Sharti 274155420Sharti if(p == ®s[regs_alloc]) { 275155420Sharti size_t newsize = regs_alloc + POLL_REG_GROW; 276155420Sharti regs = _xrealloc(regs, sizeof(regs[0]) * newsize); 277155420Sharti for(p = ®s[regs_alloc]; p < ®s[newsize]; p++) { 278155420Sharti p->fd = -1; 279155420Sharti# ifdef USE_POLL 280155420Sharti p->pfd = NULL; 281155420Sharti# endif 282155420Sharti } 283155420Sharti p = ®s[regs_alloc]; 284155420Sharti regs_alloc = newsize; 285155420Sharti } 286155420Sharti 287155420Sharti p->fd = fd; 288155420Sharti p->arg = arg; 289155420Sharti p->mask = mask; 290155420Sharti p->func = func; 291155420Sharti 292155420Sharti regs_used++; 293155420Sharti rebuild = 1; 294155420Sharti } 295155420Sharti 296155420Sharti poll_unblocksig(); 297155420Sharti 298155420Sharti if(rpoll_trace) 299165009Sharti fprintf(stderr, "poll_register(%d, %p, %p, %#x)->%tu", 300165009Sharti fd, (void *)func, (void *)arg, mask, p - regs); 301155420Sharti return p - regs; 302155420Sharti} 303155420Sharti 304155420Sharti/* 305155420Sharti * remove registration 306155420Sharti */ 307155420Shartivoid 308155420Shartipoll_unregister(int handle) 309155420Sharti{ 310155420Sharti if(rpoll_trace) 311155420Sharti fprintf(stderr, "poll_unregister(%d)", handle); 312155420Sharti 313155420Sharti poll_blocksig(); 314155420Sharti 315155420Sharti regs[handle].fd = -1; 316155420Sharti# ifdef USE_POLL 317155420Sharti regs[handle].pfd = NULL; 318155420Sharti# endif 319155420Sharti rebuild = 1; 320155420Sharti regs_used--; 321155420Sharti 322155420Sharti poll_unblocksig(); 323155420Sharti} 324155420Sharti 325155420Sharti/* 326155420Sharti * Build the structures used by poll() or select() 327155420Sharti */ 328155420Shartistatic void 329155420Shartipoll_build(void) 330155420Sharti{ 331155420Sharti PollReg_t * p; 332155420Sharti 333155420Sharti# ifdef USE_POLL 334155420Sharti struct pollfd * f; 335155420Sharti 336155420Sharti f = pfd = _xrealloc(pfd, sizeof(pfd[0]) * regs_used); 337155420Sharti 338155420Sharti for(p = regs; p < ®s[regs_alloc]; p++) 339155420Sharti if(p->fd >= 0) { 340155420Sharti f->fd = p->fd; 341155420Sharti f->events = 0; 342155420Sharti if(p->mask & POLL_IN) 343155420Sharti f->events |= poll_in; 344155420Sharti if(p->mask & POLL_OUT) 345155420Sharti f->events |= poll_out; 346155420Sharti if(p->mask & POLL_EXCEPT) 347155420Sharti f->events |= poll_except; 348155420Sharti f->revents = 0; 349155420Sharti p->pfd = f++; 350155420Sharti } 351155420Sharti assert(f == &pfd[regs_used]); 352155420Sharti# endif 353155420Sharti 354155420Sharti# ifdef USE_SELECT 355155420Sharti FD_ZERO(&rset); 356155420Sharti FD_ZERO(&wset); 357155420Sharti FD_ZERO(&xset); 358155420Sharti maxfd = -1; 359155420Sharti for(p = regs; p < ®s[regs_alloc]; p++) 360155420Sharti if(p->fd >= 0) { 361155420Sharti if(p->fd > maxfd) 362155420Sharti maxfd = p->fd; 363155420Sharti if(p->mask & POLL_IN) 364155420Sharti FD_SET(p->fd, &rset); 365155420Sharti if(p->mask & POLL_OUT) 366155420Sharti FD_SET(p->fd, &wset); 367155420Sharti if(p->mask & POLL_EXCEPT) 368155420Sharti FD_SET(p->fd, &xset); 369155420Sharti } 370155420Sharti# endif 371155420Sharti} 372155420Sharti 373155420Shartiint 374155420Shartipoll_start_timer(u_int msecs, int repeat, timer_f func, void *arg) 375155420Sharti{ 376165009Sharti return (poll_start_utimer((unsigned long long)msecs * 1000, 377165009Sharti repeat, func, arg)); 378165009Sharti} 379165009Sharti 380165009Shartiint 381165009Shartipoll_start_utimer(unsigned long long usecs, int repeat, timer_f func, void *arg) 382165009Sharti{ 383155420Sharti PollTim_t *p; 384155420Sharti 385155420Sharti /* find unused entry */ 386155420Sharti for(p = tims; p < &tims[tims_alloc]; p++) 387155420Sharti if(p->func == NULL) 388155420Sharti break; 389155420Sharti 390155420Sharti if(p == &tims[tims_alloc]) { 391155420Sharti if(tims_alloc == tims_used) { 392155420Sharti size_t newsize = tims_alloc + POLL_REG_GROW; 393155420Sharti tims = _xrealloc(tims, sizeof(tims[0]) * newsize); 394155420Sharti for(p = &tims[tims_alloc]; p < &tims[newsize]; p++) 395155420Sharti p->func = NULL; 396155420Sharti p = &tims[tims_alloc]; 397155420Sharti tims_alloc = newsize; 398155420Sharti } 399155420Sharti } 400155420Sharti 401155420Sharti /* create entry */ 402165009Sharti p->usecs = usecs; 403155420Sharti p->repeat = repeat; 404155420Sharti p->arg = arg; 405155420Sharti p->func = func; 406165009Sharti p->when = GETUSECS() + usecs; 407155420Sharti 408155420Sharti tims_used++; 409155420Sharti 410155420Sharti resort = 1; 411155420Sharti 412155420Sharti if(rpoll_trace) 413165009Sharti fprintf(stderr, "poll_start_utimer(%llu, %d, %p, %p)->%tu", 414165009Sharti usecs, repeat, (void *)func, (void *)arg, p - tims); 415155420Sharti 416155420Sharti return p - tims; 417155420Sharti} 418155420Sharti 419155420Sharti/* 420155420Sharti * Here we have to look into the sorted table, whether any entry there points 421155420Sharti * into the registration table for the deleted entry. This is needed, 422155420Sharti * because a unregistration can occure while we are scanning through the 423155420Sharti * table in dispatch(). Do this only, if we are really there - resorting 424155420Sharti * will sort out things if we are called from outside the loop. 425155420Sharti */ 426155420Shartivoid 427155420Shartipoll_stop_timer(int handle) 428155420Sharti{ 429155420Sharti u_int i; 430155420Sharti 431155420Sharti if(rpoll_trace) 432155420Sharti fprintf(stderr, "poll_stop_timer(%d)", handle); 433155420Sharti 434155420Sharti tims[handle].func = NULL; 435155420Sharti tims_used--; 436155420Sharti 437155420Sharti resort = 1; 438155420Sharti 439155420Sharti if(!in_dispatch) 440155420Sharti return; 441155420Sharti 442155420Sharti for(i = 0; i < tfd_used; i++) 443155420Sharti if(tfd[i] == handle) { 444155420Sharti tfd[i] = -1; 445155420Sharti break; 446155420Sharti } 447155420Sharti} 448155420Sharti 449155420Sharti/* 450155420Sharti * Squeeze and sort timer table. 451155420Sharti * Should perhaps use a custom sort. 452155420Sharti */ 453155420Shartistatic int 454155420Shartitim_cmp(const void *p1, const void *p2) 455155420Sharti{ 456155420Sharti int t1 = *(const int *)p1; 457155420Sharti int t2 = *(const int *)p2; 458155420Sharti 459155420Sharti return tims[t1].when < tims[t2].when ? -1 460155420Sharti : tims[t1].when > tims[t2].when ? +1 461155420Sharti : 0; 462155420Sharti} 463155420Sharti 464155420Sharti/* 465155420Sharti * Reconstruct the tfd-array. This will be an sorted array of indexes 466155420Sharti * to the used entries in tims. The next timer to expire will be infront 467155420Sharti * of the array. tfd_used is the number of used entries. The array is 468155420Sharti * re-allocated if needed. 469155420Sharti */ 470155420Shartistatic void 471155420Shartisort_timers(void) 472155420Sharti{ 473155420Sharti int *pp; 474155420Sharti u_int i; 475155420Sharti 476155420Sharti if(tims_used > tfd_alloc) { 477155420Sharti tfd_alloc = tims_used; 478155420Sharti tfd = _xrealloc(tfd, sizeof(int *) * tfd_alloc); 479155420Sharti } 480155420Sharti 481155420Sharti pp = tfd; 482155420Sharti 483155420Sharti for(i = 0; i < tims_alloc; i++) 484155420Sharti if(tims[i].func) 485155420Sharti *pp++ = i; 486155420Sharti assert(pp - tfd == (ptrdiff_t)tims_used); 487155420Sharti 488155420Sharti tfd_used = tims_used; 489155420Sharti if(tfd_used > 1) 490155420Sharti qsort(tfd, tfd_used, sizeof(int), tim_cmp); 491155420Sharti} 492155420Sharti 493155420Sharti/* 494155420Sharti * Poll the file descriptors and dispatch to the right function 495155420Sharti * If wait is true the poll blocks until somewhat happens. 496155420Sharti * Don't use a pointer here, because the called function may cause 497155420Sharti * a reallocation! The check for pfd != NULL is required, because 498155420Sharti * a sequence of unregister/register could make the wrong callback 499155420Sharti * to be called. So we clear pfd in unregister and check here. 500155420Sharti */ 501155420Shartivoid 502155420Shartipoll_dispatch(int wait) 503155420Sharti{ 504155420Sharti u_int i, idx; 505155420Sharti int ret; 506155420Sharti tval_t now; 507165009Sharti tval_t tout; 508155420Sharti static u_int last_index; 509155420Sharti 510155420Sharti# ifdef USE_SELECT 511155420Sharti fd_set nrset, nwset, nxset; 512155420Sharti struct timeval tv; 513155420Sharti# endif 514155420Sharti 515155420Sharti in_dispatch = 1; 516155420Sharti 517155420Sharti if(rebuild) { 518155420Sharti rebuild = 0; 519155420Sharti poll_build(); 520155420Sharti } 521155420Sharti if(resort) { 522155420Sharti resort = 0; 523155420Sharti sort_timers(); 524155420Sharti } 525155420Sharti 526155420Sharti /* in wait mode - compute the timeout */ 527155420Sharti if(wait) { 528155420Sharti if(tfd_used) { 529165009Sharti now = GETUSECS(); 530155420Sharti# ifdef DEBUG 531155420Sharti { 532165009Sharti fprintf(stderr, "now=%llu", now); 533155420Sharti for(i = 0; i < tims_used; i++) 534165009Sharti fprintf(stderr, "timers[%2d] = %lld", 535165009Sharti i, tfd[i]->when - now); 536155420Sharti } 537155420Sharti# endif 538155420Sharti if((tout = tims[tfd[0]].when - now) < 0) 539155420Sharti tout = 0; 540155420Sharti } else 541155420Sharti tout = INFTIM; 542155420Sharti } else 543155420Sharti tout = 0; 544155420Sharti 545155420Sharti# ifdef DEBUG 546155420Sharti fprintf(stderr, "rpoll -- selecting with tout=%u", tout); 547155420Sharti# endif 548155420Sharti 549155420Sharti# ifdef USE_POLL 550165009Sharti ret = poll(pfd, regs_used, tout == INFTIM ? INFTIM : (tout / 1000)); 551155420Sharti# endif 552155420Sharti 553155420Sharti# ifdef USE_SELECT 554155420Sharti nrset = rset; 555155420Sharti nwset = wset; 556155420Sharti nxset = xset; 557155420Sharti if(tout != INFTIM) { 558165009Sharti tv.tv_sec = tout / 1000000; 559165009Sharti tv.tv_usec = tout % 1000000; 560155420Sharti } 561155420Sharti ret = select(maxfd+1, 562155420Sharti SELECT_CAST(&nrset), 563155420Sharti SELECT_CAST(&nwset), 564165009Sharti SELECT_CAST(&nxset), (tout==INFTIM) ? NULL : &tv); 565155420Sharti# endif 566155420Sharti 567155420Sharti if(ret == -1) { 568155420Sharti if(errno == EINTR) 569155420Sharti return; 570155420Sharti _panic("poll/select: %s", strerror(errno)); 571155420Sharti } 572155420Sharti 573155420Sharti /* dispatch files */ 574155420Sharti if(ret > 0) { 575155420Sharti for(i = 0; i < regs_alloc; i++) { 576155420Sharti idx = rpoll_policy ? ((last_index+i) % regs_alloc) : i; 577155420Sharti 578155420Sharti assert(idx < regs_alloc); 579155420Sharti 580155420Sharti if(regs[idx].fd >= 0) { 581155420Sharti int mask = 0; 582155420Sharti 583155420Sharti# ifdef USE_POLL 584155420Sharti if(regs[idx].pfd) { 585165009Sharti if ((regs[idx].mask & POLL_IN) && 586165009Sharti (regs[idx].pfd->revents & poll_in)) 587155420Sharti mask |= POLL_IN; 588165009Sharti if ((regs[idx].mask & POLL_OUT) && 589165009Sharti (regs[idx].pfd->revents & poll_out)) 590155420Sharti mask |= POLL_OUT; 591165009Sharti if((regs[idx].mask & POLL_EXCEPT) && 592165009Sharti (regs[idx].pfd->revents & poll_except)) 593155420Sharti mask |= POLL_EXCEPT; 594155420Sharti } 595155420Sharti# endif 596155420Sharti# ifdef USE_SELECT 597165009Sharti if ((regs[idx].mask & POLL_IN) && 598165009Sharti FD_ISSET(regs[idx].fd, &nrset)) 599155420Sharti mask |= POLL_IN; 600165009Sharti if ((regs[idx].mask & POLL_OUT) && 601165009Sharti FD_ISSET(regs[idx].fd, &nwset)) 602155420Sharti mask |= POLL_OUT; 603165009Sharti if ((regs[idx].mask & POLL_EXCEPT) && 604165009Sharti FD_ISSET(regs[idx].fd, &nxset)) 605155420Sharti mask |= POLL_EXCEPT; 606155420Sharti# endif 607155420Sharti assert(idx < regs_alloc); 608155420Sharti 609155420Sharti if(mask) { 610155420Sharti if(rpoll_trace) 611155420Sharti fprintf(stderr, "poll_dispatch() -- " 612165009Sharti "file %d/%d %x", 613165009Sharti regs[idx].fd, idx, mask); 614155420Sharti (*regs[idx].func)(regs[idx].fd, mask, regs[idx].arg); 615155420Sharti } 616155420Sharti } 617155420Sharti 618155420Sharti } 619155420Sharti last_index++; 620155420Sharti } 621155420Sharti 622155420Sharti /* dispatch timeouts */ 623155420Sharti if(tfd_used) { 624165009Sharti now = GETUSECS(); 625155420Sharti for(i = 0; i < tfd_used; i++) { 626155420Sharti if(tfd[i] < 0) 627155420Sharti continue; 628155420Sharti if(tims[tfd[i]].when > now) 629155420Sharti break; 630155420Sharti if(rpoll_trace) 631155420Sharti fprintf(stderr, "rpoll_dispatch() -- timeout %d",tfd[i]); 632155420Sharti (*tims[tfd[i]].func)(tfd[i], tims[tfd[i]].arg); 633155420Sharti if(tfd[i] < 0) 634155420Sharti continue; 635155420Sharti if(tims[tfd[i]].repeat) 636165009Sharti tims[tfd[i]].when = now + tims[tfd[i]].usecs; 637155420Sharti else { 638155420Sharti tims[tfd[i]].func = NULL; 639155420Sharti tims_used--; 640155420Sharti tfd[i] = -1; 641155420Sharti } 642155420Sharti resort = 1; 643155420Sharti } 644155420Sharti } 645155420Sharti in_dispatch = 0; 646155420Sharti} 647155420Sharti 648155420Sharti 649155420Sharti# ifdef TESTME 650155420Shartistruct timeval start, now; 651155420Shartiint t0, t1; 652155420Sharti 653155420Shartidouble elaps(void); 654155420Shartivoid infunc(int fd, int mask, void *arg); 655155420Sharti 656155420Shartidouble 657155420Shartielaps(void) 658155420Sharti{ 659155420Sharti gettimeofday(&now, NULL); 660155420Sharti 661165009Sharti return (double)(10 * now.tv_sec + now.tv_usec / 100000 - 662165009Sharti 10 * start.tv_sec - start.tv_usec / 100000) / 10; 663155420Sharti} 664155420Sharti 665155420Shartivoid 666155420Shartiinfunc(int fd, int mask, void *arg) 667155420Sharti{ 668155420Sharti char buf[1024]; 669155420Sharti int ret; 670155420Sharti 671155420Sharti mask = mask; 672155420Sharti arg = arg; 673155420Sharti if((ret = read(fd, buf, sizeof(buf))) < 0) 674155420Sharti _panic("read: %s", strerror(errno)); 675155420Sharti write(1, "stdin:", 6); 676155420Sharti write(1, buf, ret); 677155420Sharti} 678155420Sharti 679155420Shartivoid tfunc0(int tid, void *arg); 680155420Shartivoid tfunc1(int tid, void *arg); 681155420Sharti 682155420Shartivoid 683155420Shartitfunc0(int tid, void *arg) 684155420Sharti{ 685155420Sharti printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg); 686155420Sharti} 687155420Shartivoid 688155420Shartitfunc1(int tid, void *arg) 689155420Sharti{ 690155420Sharti printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg); 691155420Sharti} 692165009Shartivoid 693165009Shartitfunc2(int tid, void *arg) 694165009Sharti{ 695165009Sharti static u_int count = 0; 696155420Sharti 697165009Sharti if (++count % 10000 == 0) 698165009Sharti printf("%4.1f -- %d\n", elaps(), tid); 699165009Sharti} 700165009Sharti 701155420Shartivoid first(int tid, void *arg); 702155420Shartivoid second(int tid, void *arg); 703155420Sharti 704155420Shartivoid 705155420Shartisecond(int tid, void *arg) 706155420Sharti{ 707155420Sharti printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg); 708165009Sharti poll_start_utimer(5500000, 0, first, "first"); 709155420Sharti poll_stop_timer(t1); 710155420Sharti t0 = poll_start_timer(1000, 1, tfunc0, "1 second"); 711155420Sharti} 712155420Shartivoid 713155420Shartifirst(int tid, void *arg) 714155420Sharti{ 715155420Sharti printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg); 716155420Sharti poll_start_timer(3700, 0, second, "second"); 717155420Sharti poll_stop_timer(t0); 718155420Sharti t1 = poll_start_timer(250, 1, tfunc1, "1/4 second"); 719155420Sharti} 720155420Sharti 721155420Shartiint 722155420Shartimain(int argc, char *argv[]) 723155420Sharti{ 724155420Sharti argv = argv; 725155420Sharti gettimeofday(&start, NULL); 726155420Sharti poll_register(0, infunc, NULL, POLL_IN); 727155420Sharti 728165009Sharti if (argc < 2) { 729165009Sharti t0 = poll_start_timer(1000, 1, tfunc0, "1 second"); 730165009Sharti poll_start_timer(2500, 0, first, "first"); 731165009Sharti } else { 732165009Sharti t0 = poll_start_utimer(300, 1, tfunc2, NULL); 733165009Sharti } 734165009Sharti 735155420Sharti while(1) 736155420Sharti poll_dispatch(1); 737155420Sharti 738155420Sharti return 0; 739155420Sharti} 740155420Sharti# endif 741