1/* 2 * Copyright (c)1996-2002 by Hartmut Brandt 3 * All rights reserved. 4 * 5 * Author: Hartmut Brandt 6 * 7 * Redistribution of this software and documentation and use in source and 8 * binary forms, with or without modification, are permitted provided that 9 * the following conditions are met: 10 * 11 * 1. Redistributions of source code or documentation must retain the above 12 * copyright notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE AUTHOR 18 * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 19 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE AUTHOR OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 24 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 27 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29/* 30 * These functions try to hide the poll/select/setitimer interface from the 31 * user. You associate callback functions with file descriptors and timers. 32 * 33 * $Begemot: libbegemot/rpoll.c,v 1.14 2004/09/21 15:59:00 brandt Exp $ 34 */ 35# include <stdio.h> 36# include <stdlib.h> 37# include <stddef.h> 38# include <stdarg.h> 39# include <signal.h> 40# include <string.h> 41# include <errno.h> 42# include <time.h> 43# include <assert.h> 44# include <unistd.h> 45# include <sys/time.h> 46 47/* 48 * There happens to be linuxes which read siginfo.h when including 49 * signal.h, which, for no appearent reason, defines these symbols. 50 */ 51# ifdef POLL_IN 52# undef POLL_IN 53# endif 54# ifdef POLL_OUT 55# undef POLL_OUT 56# endif 57 58# include "rpoll.h" 59 60/* 61# define DEBUG 62*/ 63 64# ifdef USE_POLL 65# ifdef NEED_POLL_XOPEN_TWIDDLE 66# define __USE_XOPEN 67# endif 68# include <poll.h> 69# ifdef NEED_POLL_XOPEN_TWIDDLE 70# undef __USE_XOPEN 71# endif 72# include <stropts.h> 73# endif 74 75/* 76 * the second define is for Linux, which sometimes fails to 77 * declare INFTIM. 78 */ 79# if defined(USE_SELECT) || !defined(INFTIM) 80# define INFTIM (-1) 81# endif 82 83# if defined(SIGPOLL) 84# define SIGNAL SIGPOLL 85# else 86# if defined(SIGIO) 87# define SIGNAL SIGIO 88# endif 89# endif 90 91# ifdef USE_POLL 92# define poll_in (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI) 93# define poll_out (POLLOUT | POLLWRNORM | POLLWRBAND) 94# define poll_except (POLLERR | POLLHUP) 95# endif 96 97# ifdef BROKEN_SELECT_PROTO 98# define SELECT_CAST(P) (int *)P 99# else 100# define SELECT_CAST(P) P 101# endif 102 103
|
104typedef signed long long tval_t;
|
104typedef int64_t tval_t; |
105
|
106static inline tval_t GETMSECS(void);
|
106static inline tval_t GETUSECS(void); |
107 108static inline tval_t
|
109GETMSECS(void) {
|
109GETUSECS(void) { |
110 struct timeval tval; 111 112 (void)gettimeofday(&tval, NULL);
|
113 return (tval_t)tval.tv_sec*1000+tval.tv_usec/1000;
|
113 return (tval_t)tval.tv_sec * 1000000 + tval.tv_usec; |
114} 115 116/* 117 * Simple fatal exit. 118 */ 119static void 120_panic(const char *fmt, ...) 121{ 122 va_list ap; 123 124 va_start(ap, fmt); 125 fprintf(stderr, "panic: "); 126 vfprintf(stderr, fmt, ap); 127 fprintf(stderr, "\n"); 128 va_end(ap); 129 130 exit(1); 131} 132 133static void * 134_xrealloc(void *p, size_t s) 135{ 136 void *ptr; 137 138 if(p == NULL) { 139 if((ptr=malloc(s)) == NULL && (s!=0 || (ptr=malloc(1)) == NULL)) 140 _panic("out of memory: xrealloc(%lx, %lu)", 141 (unsigned long)p, (unsigned long)s); 142 } else if(s == 0) { 143 free(p); 144 if((ptr=malloc(s)) == NULL && (ptr=malloc(1)) == NULL) 145 _panic("out of memory: xrealloc(%lx, %lu)", 146 (unsigned long)p, (unsigned long)s); 147 } else { 148 if((ptr = realloc(p, s)) == NULL) 149 _panic("out of memory: xrealloc(%lx, %lu)", 150 (unsigned long)p, (unsigned long)s); 151 } 152 153 return ptr; 154} 155 156/* 157 * This structure holds one registration record for files 158 */ 159typedef struct { 160 int fd; /* file descriptor (-1 if struct unused) */ 161 int mask; /* event flags */ 162 void * arg; /* client arg */ 163 poll_f func; /* handler */ 164# ifdef USE_POLL 165 struct pollfd *pfd; /* pointer to corresponding poll() structure */ 166# endif 167} PollReg_t; 168 169/* 170 * Now for timers 171 */ 172typedef struct {
|
173 u_int msecs; /* millisecond value of the timer */
|
173 uint64_t usecs; /* microsecond value of the timer */ |
174 int repeat; /* one shot or repeat? */ 175 void *arg; /* client arg */ 176 timer_f func; /* handler, 0 means disfunct */
|
177 tval_t when; /* next time to trigger in msecs! */
|
177 tval_t when; /* next time to trigger in usecs! */ |
178} PollTim_t; 179 180/* how many records should our table grow at once? */ 181# define POLL_REG_GROW 100 182 183# ifdef USE_POLL 184static struct pollfd * pfd; /* fd list for poll() */ 185# endif 186 187# ifdef USE_SELECT 188static fd_set rset, wset, xset; /* file descriptor sets for select() */ 189static int maxfd; /* maximum fd number */ 190# endif 191 192static int in_dispatch; 193 194static PollReg_t * regs; /* registration records */ 195static u_int regs_alloc; /* how many are allocated */ 196static u_int regs_used; /* upper used limit */ 197static sigset_t bset; /* blocked signals */ 198static int rebuild; /* rebuild table on next dispatch() */ 199 200static int * tfd; /* sorted entries */ 201static u_int tfd_alloc; /* number of entries allocated */ 202static u_int tfd_used; /* number of entries used */ 203static PollTim_t * tims; /* timer registration records */ 204static u_int tims_alloc; /* how many are allocated */ 205static u_int tims_used; /* how many are used */ 206static int resort; /* resort on next dispatch */ 207 208int rpoll_trace; 209int rpoll_policy; /* if 0 start sched callbacks from 0 else try round robin */ 210 211static void poll_build(void); 212static void poll_blocksig(void); 213static void poll_unblocksig(void); 214static void sort_timers(void); 215 216 217/* 218 * Private function to block SIGPOLL or SIGIO for a short time. 219 * Don't forget to call poll_unblock before return from the calling function. 220 * Don't change the mask between this calls (your changes will be lost). 221 */ 222static void 223poll_blocksig(void) 224{ 225 sigset_t set; 226 227 sigemptyset(&set); 228 sigaddset(&set, SIGNAL); 229 230 if(sigprocmask(SIG_BLOCK, &set, &bset)) 231 _panic("sigprocmask(SIG_BLOCK): %s", strerror(errno)); 232} 233 234/* 235 * unblock the previously blocked signal 236 */ 237static void 238poll_unblocksig(void) 239{ 240 if(sigprocmask(SIG_SETMASK, &bset, NULL)) 241 _panic("sigprocmask(SIG_SETMASK): %s", strerror(errno)); 242} 243 244/* 245 * Register the file descriptor fd. If the event corresponding to 246 * mask arrives func is called with arg. 247 * If fd is already registered with that func and arg, only the mask 248 * is changed. 249 * We block the IO-signal, so the dispatch function can be called from 250 * within the signal handler. 251 */ 252int 253poll_register(int fd, poll_f func, void *arg, int mask) 254{ 255 PollReg_t * p; 256 257 poll_blocksig(); 258 259 /* already registered? */ 260 for(p = regs; p < ®s[regs_alloc]; p++) 261 if(p->fd == fd && p->func == func && p->arg == arg) { 262 p->mask = mask; 263 break; 264 } 265 266 if(p == ®s[regs_alloc]) { 267 /* no - register */ 268 269 /* find a free slot */ 270 for(p = regs; p < ®s[regs_alloc]; p++) 271 if(p->fd == -1) 272 break; 273 274 if(p == ®s[regs_alloc]) { 275 size_t newsize = regs_alloc + POLL_REG_GROW; 276 regs = _xrealloc(regs, sizeof(regs[0]) * newsize); 277 for(p = ®s[regs_alloc]; p < ®s[newsize]; p++) { 278 p->fd = -1; 279# ifdef USE_POLL 280 p->pfd = NULL; 281# endif 282 } 283 p = ®s[regs_alloc]; 284 regs_alloc = newsize; 285 } 286 287 p->fd = fd; 288 p->arg = arg; 289 p->mask = mask; 290 p->func = func; 291 292 regs_used++; 293 rebuild = 1; 294 } 295 296 poll_unblocksig(); 297 298 if(rpoll_trace)
|
299 fprintf(stderr, "poll_register(%d, %#lx, %#lx, %#x)->%d",
300 fd, (u_long)func, (u_long)arg, mask, p - regs);
|
299 fprintf(stderr, "poll_register(%d, %p, %p, %#x)->%tu", 300 fd, (void *)func, (void *)arg, mask, p - regs); |
301 return p - regs; 302} 303 304/* 305 * remove registration 306 */ 307void 308poll_unregister(int handle) 309{ 310 if(rpoll_trace) 311 fprintf(stderr, "poll_unregister(%d)", handle); 312 313 poll_blocksig(); 314 315 regs[handle].fd = -1; 316# ifdef USE_POLL 317 regs[handle].pfd = NULL; 318# endif 319 rebuild = 1; 320 regs_used--; 321 322 poll_unblocksig(); 323} 324 325/* 326 * Build the structures used by poll() or select() 327 */ 328static void 329poll_build(void) 330{ 331 PollReg_t * p; 332 333# ifdef USE_POLL 334 struct pollfd * f; 335 336 f = pfd = _xrealloc(pfd, sizeof(pfd[0]) * regs_used); 337 338 for(p = regs; p < ®s[regs_alloc]; p++) 339 if(p->fd >= 0) { 340 f->fd = p->fd; 341 f->events = 0; 342 if(p->mask & POLL_IN) 343 f->events |= poll_in; 344 if(p->mask & POLL_OUT) 345 f->events |= poll_out; 346 if(p->mask & POLL_EXCEPT) 347 f->events |= poll_except; 348 f->revents = 0; 349 p->pfd = f++; 350 } 351 assert(f == &pfd[regs_used]); 352# endif 353 354# ifdef USE_SELECT 355 FD_ZERO(&rset); 356 FD_ZERO(&wset); 357 FD_ZERO(&xset); 358 maxfd = -1; 359 for(p = regs; p < ®s[regs_alloc]; p++) 360 if(p->fd >= 0) { 361 if(p->fd > maxfd) 362 maxfd = p->fd; 363 if(p->mask & POLL_IN) 364 FD_SET(p->fd, &rset); 365 if(p->mask & POLL_OUT) 366 FD_SET(p->fd, &wset); 367 if(p->mask & POLL_EXCEPT) 368 FD_SET(p->fd, &xset); 369 } 370# endif 371} 372 373int 374poll_start_timer(u_int msecs, int repeat, timer_f func, void *arg) 375{
|
376 return (poll_start_utimer((unsigned long long)msecs * 1000, 377 repeat, func, arg)); 378} 379 380int 381poll_start_utimer(unsigned long long usecs, int repeat, timer_f func, void *arg) 382{ |
383 PollTim_t *p; 384 385 /* find unused entry */ 386 for(p = tims; p < &tims[tims_alloc]; p++) 387 if(p->func == NULL) 388 break; 389 390 if(p == &tims[tims_alloc]) { 391 if(tims_alloc == tims_used) { 392 size_t newsize = tims_alloc + POLL_REG_GROW; 393 tims = _xrealloc(tims, sizeof(tims[0]) * newsize); 394 for(p = &tims[tims_alloc]; p < &tims[newsize]; p++) 395 p->func = NULL; 396 p = &tims[tims_alloc]; 397 tims_alloc = newsize; 398 } 399 } 400 401 /* create entry */
|
395 p->msecs = msecs;
|
402 p->usecs = usecs; |
403 p->repeat = repeat; 404 p->arg = arg; 405 p->func = func;
|
399 p->when = GETMSECS() + msecs;
|
406 p->when = GETUSECS() + usecs; |
407 408 tims_used++; 409 410 resort = 1; 411 412 if(rpoll_trace)
|
406 fprintf(stderr, "poll_start_timer(%u, %d, %#lx, %#lx)->%u",
407 msecs, repeat, (u_long)func, (u_long)arg, p - tims);
|
413 fprintf(stderr, "poll_start_utimer(%llu, %d, %p, %p)->%tu", 414 usecs, repeat, (void *)func, (void *)arg, p - tims); |
415 416 return p - tims; 417} 418 419/* 420 * Here we have to look into the sorted table, whether any entry there points 421 * into the registration table for the deleted entry. This is needed, 422 * because a unregistration can occure while we are scanning through the 423 * table in dispatch(). Do this only, if we are really there - resorting 424 * will sort out things if we are called from outside the loop. 425 */ 426void 427poll_stop_timer(int handle) 428{ 429 u_int i; 430 431 if(rpoll_trace) 432 fprintf(stderr, "poll_stop_timer(%d)", handle); 433 434 tims[handle].func = NULL; 435 tims_used--; 436 437 resort = 1; 438 439 if(!in_dispatch) 440 return; 441 442 for(i = 0; i < tfd_used; i++) 443 if(tfd[i] == handle) { 444 tfd[i] = -1; 445 break; 446 } 447} 448 449/* 450 * Squeeze and sort timer table. 451 * Should perhaps use a custom sort. 452 */ 453static int 454tim_cmp(const void *p1, const void *p2) 455{ 456 int t1 = *(const int *)p1; 457 int t2 = *(const int *)p2; 458 459 return tims[t1].when < tims[t2].when ? -1 460 : tims[t1].when > tims[t2].when ? +1 461 : 0; 462} 463 464/* 465 * Reconstruct the tfd-array. This will be an sorted array of indexes 466 * to the used entries in tims. The next timer to expire will be infront 467 * of the array. tfd_used is the number of used entries. The array is 468 * re-allocated if needed. 469 */ 470static void 471sort_timers(void) 472{ 473 int *pp; 474 u_int i; 475 476 if(tims_used > tfd_alloc) { 477 tfd_alloc = tims_used; 478 tfd = _xrealloc(tfd, sizeof(int *) * tfd_alloc); 479 } 480 481 pp = tfd; 482 483 for(i = 0; i < tims_alloc; i++) 484 if(tims[i].func) 485 *pp++ = i; 486 assert(pp - tfd == (ptrdiff_t)tims_used); 487 488 tfd_used = tims_used; 489 if(tfd_used > 1) 490 qsort(tfd, tfd_used, sizeof(int), tim_cmp); 491} 492 493/* 494 * Poll the file descriptors and dispatch to the right function 495 * If wait is true the poll blocks until somewhat happens. 496 * Don't use a pointer here, because the called function may cause 497 * a reallocation! The check for pfd != NULL is required, because 498 * a sequence of unregister/register could make the wrong callback 499 * to be called. So we clear pfd in unregister and check here. 500 */ 501void 502poll_dispatch(int wait) 503{ 504 u_int i, idx; 505 int ret; 506 tval_t now;
|
500 int tout;
|
507 tval_t tout; |
508 static u_int last_index; 509 510# ifdef USE_SELECT 511 fd_set nrset, nwset, nxset; 512 struct timeval tv; 513# endif 514 515 in_dispatch = 1; 516 517 if(rebuild) { 518 rebuild = 0; 519 poll_build(); 520 } 521 if(resort) { 522 resort = 0; 523 sort_timers(); 524 } 525 526 /* in wait mode - compute the timeout */ 527 if(wait) { 528 if(tfd_used) {
|
522 now = GETMSECS();
|
529 now = GETUSECS(); |
530# ifdef DEBUG 531 {
|
525 fprintf(stderr, "now=%"QUADFMT"u", now);
|
532 fprintf(stderr, "now=%llu", now); |
533 for(i = 0; i < tims_used; i++)
|
527 fprintf(stderr, "timers[%2d] = %"QUADFMT"d", i, tfd[i]->when - now);
|
534 fprintf(stderr, "timers[%2d] = %lld", 535 i, tfd[i]->when - now); |
536 } 537# endif 538 if((tout = tims[tfd[0]].when - now) < 0) 539 tout = 0; 540 } else 541 tout = INFTIM; 542 } else 543 tout = 0; 544 545# ifdef DEBUG 546 fprintf(stderr, "rpoll -- selecting with tout=%u", tout); 547# endif 548 549# ifdef USE_POLL
|
542 ret = poll(pfd, regs_used, tout);
|
550 ret = poll(pfd, regs_used, tout == INFTIM ? INFTIM : (tout / 1000)); |
551# endif 552 553# ifdef USE_SELECT 554 nrset = rset; 555 nwset = wset; 556 nxset = xset; 557 if(tout != INFTIM) {
|
550 tv.tv_sec = tout / 1000;
551 tv.tv_usec = (tout % 1000) * 1000;
|
558 tv.tv_sec = tout / 1000000; 559 tv.tv_usec = tout % 1000000; |
560 } 561 ret = select(maxfd+1, 562 SELECT_CAST(&nrset), 563 SELECT_CAST(&nwset),
|
556 SELECT_CAST(&nxset), (tout==INFTIM) ? 0 : &tv);
|
564 SELECT_CAST(&nxset), (tout==INFTIM) ? NULL : &tv); |
565# endif 566 567 if(ret == -1) { 568 if(errno == EINTR) 569 return; 570 _panic("poll/select: %s", strerror(errno)); 571 } 572 573 /* dispatch files */ 574 if(ret > 0) { 575 for(i = 0; i < regs_alloc; i++) { 576 idx = rpoll_policy ? ((last_index+i) % regs_alloc) : i; 577 578 assert(idx < regs_alloc); 579 580 if(regs[idx].fd >= 0) { 581 int mask = 0; 582 583# ifdef USE_POLL 584 if(regs[idx].pfd) {
|
577 if(regs[idx].pfd->revents & poll_in)
|
585 if ((regs[idx].mask & POLL_IN) && 586 (regs[idx].pfd->revents & poll_in)) |
587 mask |= POLL_IN;
|
579 if(regs[idx].pfd->revents & poll_out)
|
588 if ((regs[idx].mask & POLL_OUT) && 589 (regs[idx].pfd->revents & poll_out)) |
590 mask |= POLL_OUT;
|
581 if(regs[idx].pfd->revents & poll_except)
|
591 if((regs[idx].mask & POLL_EXCEPT) && 592 (regs[idx].pfd->revents & poll_except)) |
593 mask |= POLL_EXCEPT; 594 } 595# endif 596# ifdef USE_SELECT
|
586 if(FD_ISSET(regs[idx].fd, &nrset))
|
597 if ((regs[idx].mask & POLL_IN) && 598 FD_ISSET(regs[idx].fd, &nrset)) |
599 mask |= POLL_IN;
|
588 if(FD_ISSET(regs[idx].fd, &nwset))
|
600 if ((regs[idx].mask & POLL_OUT) && 601 FD_ISSET(regs[idx].fd, &nwset)) |
602 mask |= POLL_OUT;
|
590 if(FD_ISSET(regs[idx].fd, &nxset))
|
603 if ((regs[idx].mask & POLL_EXCEPT) && 604 FD_ISSET(regs[idx].fd, &nxset)) |
605 mask |= POLL_EXCEPT; 606# endif 607 assert(idx < regs_alloc); 608 609 if(mask) { 610 if(rpoll_trace) 611 fprintf(stderr, "poll_dispatch() -- "
|
598 "file %d/%d",
599 regs[idx].fd, idx);
|
612 "file %d/%d %x", 613 regs[idx].fd, idx, mask); |
614 (*regs[idx].func)(regs[idx].fd, mask, regs[idx].arg); 615 } 616 } 617 618 } 619 last_index++; 620 } 621 622 /* dispatch timeouts */ 623 if(tfd_used) {
|
610 now = GETMSECS();
|
624 now = GETUSECS(); |
625 for(i = 0; i < tfd_used; i++) { 626 if(tfd[i] < 0) 627 continue; 628 if(tims[tfd[i]].when > now) 629 break; 630 if(rpoll_trace) 631 fprintf(stderr, "rpoll_dispatch() -- timeout %d",tfd[i]); 632 (*tims[tfd[i]].func)(tfd[i], tims[tfd[i]].arg); 633 if(tfd[i] < 0) 634 continue; 635 if(tims[tfd[i]].repeat)
|
622 tims[tfd[i]].when = now + tims[tfd[i]].msecs;
|
636 tims[tfd[i]].when = now + tims[tfd[i]].usecs; |
637 else { 638 tims[tfd[i]].func = NULL; 639 tims_used--; 640 tfd[i] = -1; 641 } 642 resort = 1; 643 } 644 } 645 in_dispatch = 0; 646} 647 648 649# ifdef TESTME 650struct timeval start, now; 651int t0, t1; 652 653double elaps(void); 654void infunc(int fd, int mask, void *arg); 655 656double 657elaps(void) 658{ 659 gettimeofday(&now, NULL); 660
|
647 return (double)(10 * now.tv_sec + now.tv_usec / 100000 - 10 * start.tv_sec - start.tv_usec / 100000)
648 / 10;
|
661 return (double)(10 * now.tv_sec + now.tv_usec / 100000 - 662 10 * start.tv_sec - start.tv_usec / 100000) / 10; |
663} 664 665void 666infunc(int fd, int mask, void *arg) 667{ 668 char buf[1024]; 669 int ret; 670 671 mask = mask; 672 arg = arg; 673 if((ret = read(fd, buf, sizeof(buf))) < 0) 674 _panic("read: %s", strerror(errno)); 675 write(1, "stdin:", 6); 676 write(1, buf, ret); 677} 678 679void tfunc0(int tid, void *arg); 680void tfunc1(int tid, void *arg); 681 682void 683tfunc0(int tid, void *arg) 684{ 685 printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg); 686} 687void 688tfunc1(int tid, void *arg) 689{ 690 printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg); 691}
|
692void 693tfunc2(int tid, void *arg) 694{ 695 static u_int count = 0; |
696
|
697 if (++count % 10000 == 0) 698 printf("%4.1f -- %d\n", elaps(), tid); 699} 700 |
701void first(int tid, void *arg); 702void second(int tid, void *arg); 703 704void 705second(int tid, void *arg) 706{ 707 printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg);
|
686 poll_start_timer(5500, 0, first, "first");
|
708 poll_start_utimer(5500000, 0, first, "first"); |
709 poll_stop_timer(t1); 710 t0 = poll_start_timer(1000, 1, tfunc0, "1 second"); 711} 712void 713first(int tid, void *arg) 714{ 715 printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg); 716 poll_start_timer(3700, 0, second, "second"); 717 poll_stop_timer(t0); 718 t1 = poll_start_timer(250, 1, tfunc1, "1/4 second"); 719} 720 721int 722main(int argc, char *argv[]) 723{
|
702 argc = argc;
|
724 argv = argv; 725 gettimeofday(&start, NULL); 726 poll_register(0, infunc, NULL, POLL_IN);
|
706 t0 = poll_start_timer(1000, 1, tfunc0, "1 second");
707 poll_start_timer(2500, 0, first, "first");
|
727
|
728 if (argc < 2) { 729 t0 = poll_start_timer(1000, 1, tfunc0, "1 second"); 730 poll_start_timer(2500, 0, first, "first"); 731 } else { 732 t0 = poll_start_utimer(300, 1, tfunc2, NULL); 733 } 734 |
735 while(1) 736 poll_dispatch(1); 737 738 return 0; 739} 740# endif
|