home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / fax-3.2.1 / lib / libutil / dispatch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-31  |  12.0 KB  |  603 lines

  1. /*
  2.   This file is part of the NetFax system.
  3.  
  4.   (c) Copyright 1989 by David M. Siegel and Sundar Narasimhan.
  5.       All rights reserved.
  6.  
  7.     This program is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License as published by
  9.     the Free Software Foundation.
  10.  
  11.     This program is distributed in the hope that it will be useful, 
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of 
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. */
  20.  
  21. #include <stdio.h>
  22. #include <signal.h>
  23. #include <errno.h>
  24. #include <sys/types.h>
  25. #include <sys/time.h>
  26. #include <rpc/rpc.h>
  27.  
  28. #include "alloc.h"
  29. #include "list.h"
  30. #include "tv.h"
  31. #include "hash.h"
  32. #include "dispatch.h"
  33.  
  34. #define DIO_MASK_READ   0
  35. #define DIO_MASK_WRITE  1
  36. #define DIO_MASK_EXCEPT 2
  37. #define DIO_MASKS        3
  38.  
  39. struct dqueue {
  40.     int priority;
  41.     LIST *dio_list;
  42. };
  43.  
  44. struct fd_map_key {
  45.     int fd;
  46.     int dtype;
  47. };
  48.  
  49. static LIST *dqueue_list;
  50. static LIST *alarm_list;
  51. static HTTABLE *fd_map;
  52. static fd_set dispatch_masks[DIO_MASKS];
  53. static int recompute_timeout;
  54.  
  55. static int
  56. dqueue_cmp(v1, v2)
  57. struct dqueue *v1, *v2;
  58. {
  59.     return (v2->priority - v1->priority);
  60. }
  61.  
  62. static fd_set *
  63. fd_or(fdset1, fdset2)
  64. fd_set *fdset1;
  65. fd_set *fdset2;
  66. {
  67.     int i;
  68.  
  69.     for (i=0; i<howmany(FD_SETSIZE, NFDBITS); i++)
  70.       fdset1->fds_bits[i] |= fdset2->fds_bits[i];
  71.  
  72.     return (fdset1);
  73. }
  74.  
  75. static fd_set *
  76. fd_and(fdset1, fdset2)
  77. fd_set *fdset1;
  78. fd_set *fdset2;
  79. {
  80.     int i;
  81.  
  82.     for (i=0; i<howmany(FD_SETSIZE, NFDBITS); i++)
  83.       fdset1->fds_bits[i] &= fdset2->fds_bits[i];
  84.  
  85.     return (fdset1);
  86. }
  87.  
  88. static int
  89. fd_any(fdset)
  90. fd_set *fdset;
  91. {
  92.     int i;
  93.     
  94.     for (i=0; i<howmany(FD_SETSIZE, NFDBITS); i++)
  95.       if (fdset->fds_bits[i] != 0)
  96.     return (TRUE);
  97.  
  98.     return (FALSE);
  99. }
  100.  
  101. static int
  102. init()
  103. {
  104.     int dtbsz = getdtablesize();
  105.     int cfree();
  106.  
  107.     if (dqueue_list == NULL)
  108.       if ((dqueue_list = list_make(dqueue_cmp, NULL)) == NULL)
  109.     return (-1);
  110.  
  111.     if (alarm_list == NULL)
  112.       if ((alarm_list = list_make(NULL, NULL)) == NULL)
  113.     return (-1);
  114.  
  115.     if (fd_map == NULL)
  116.       if ((fd_map = htinit(dtbsz, sizeof(struct fd_map_key))) == NULL)
  117.     return (-1);
  118.  
  119.     return (0);
  120. }
  121.  
  122. static struct dqueue *
  123. get_dq(priority)
  124. int priority;
  125. {
  126.     struct dqueue dqi, *dq;
  127.  
  128.     dqi.priority = priority;
  129.     if ((dq = (struct dqueue *)list_find(dqueue_list, (char *)&dqi)) == NULL) {
  130.     if ((dq = salloc(1, struct dqueue)) == NULL)
  131.       return (NULL);
  132.     dq->priority = priority;
  133.     if ((dq->dio_list = list_make(NULL, NULL)) == NULL)
  134.       return (NULL);
  135.     list_insert(dqueue_list, (char *)dq, LIST_ASCENDING);
  136.     }
  137.  
  138.     return (dq);
  139. }
  140.  
  141. static DIO *
  142. get_dio(dtype, fd)
  143. int dtype;
  144. int fd;
  145. {
  146.     struct fd_map_key key;
  147.     if (fd_map == NULL)
  148.       return (NULL);
  149.  
  150.     key.dtype = DIO_FD_EVENT(dtype);
  151.     key.fd = fd;
  152.  
  153.     return ((DIO *)htgetdata((char *)&key, fd_map));
  154. }
  155.  
  156. int
  157. dispatch_unregister(d)
  158. DIO *d;
  159. {
  160.     struct fd_map_key key;
  161.  
  162.     if (DIO_FD_EVENT(d->dtype)) {
  163.     key.dtype = DIO_FD_EVENT(d->dtype);
  164.     key.fd = d->fd;
  165.     htdelete((char *)&key, fd_map);
  166.     FD_CLR(d->fd, &dispatch_masks[DIO_FD_MASK(d->dtype)]);
  167.     }
  168.  
  169.     d->dtype |= DIO_DELETED;
  170.     
  171.     return (0);
  172. }
  173.  
  174. static DIO *
  175. add_dio(d, priority)
  176. DIO *d;
  177. int priority;
  178. {
  179.     struct fd_map_key key;
  180.     struct dqueue *dq;
  181.  
  182.     if (init() < 0)
  183.       return (NULL);
  184.  
  185.     if ((dq = get_dq(priority)) == NULL)
  186.       return (NULL);
  187.  
  188.     list_add(dq->dio_list, (char *)d);
  189.  
  190.     if (DIO_FD_EVENT(d->dtype)) {
  191.     key.dtype = DIO_FD_EVENT(d->dtype);
  192.     key.fd = d->fd;
  193.     htadd((char *)&key, fd_map, (char *)d);
  194.     FD_SET(d->fd, &dispatch_masks[DIO_FD_MASK(d->dtype)]);
  195.     }
  196.  
  197.     if (d->dtype & DIO_TIMEOUT)
  198.       list_add(alarm_list, (char *)d);
  199.  
  200.     return (d);
  201. }
  202.  
  203. static DIO *
  204. register_generic(dtype, priority, fd, tp, routine, data)
  205. int dtype;
  206. int priority;
  207. int fd;
  208. struct timeval *tp;
  209. int (*routine)();
  210. char *data;
  211. {
  212.     struct timeval now;
  213.     DIO *d;
  214.  
  215.     if (DIO_FD_EVENT(dtype))
  216.       if ((d = get_dio(dtype, fd)) != NULL)
  217.     dispatch_unregister(d);
  218.  
  219.     if ((d = salloc(1, DIO)) == NULL)
  220.       return (NULL);
  221.  
  222.     d->dtype = dtype;
  223.     d->fd = fd;
  224.     d->routine = routine;
  225.     d->data = data;
  226.  
  227.     if (dtype & DIO_TIMEOUT) {
  228.     d->time_interval = *tp;
  229.     d->time_next = *tp;
  230.     tv_add(&d->time_next, tv_current(&now));
  231.     recompute_timeout = TRUE;
  232.     }
  233.  
  234.     if (add_dio(d, priority) == NULL) {
  235.     cfree(d);
  236.     return (NULL);
  237.     }
  238.  
  239.     return (d);
  240. }
  241.  
  242. DIO *
  243. dispatch_register_fd(dtype, priority, fd, routine, data)
  244. int dtype;
  245. int priority;
  246. int fd;
  247. int (*routine)();
  248. char *data;
  249. {
  250.     if (!DIO_FD_EVENT(dtype))
  251.       return (NULL);
  252.  
  253.     dtype |= DIO_REPEAT;
  254.  
  255.     return (register_generic(dtype, priority, fd, NULL, routine, data));
  256. }
  257.  
  258. DIO *
  259. dispatch_register_fd_timeout(dtype, priority, fd, timeout, routine, data)
  260. int dtype;
  261. int priority;
  262. int fd;
  263. double timeout;
  264. int (*routine)();
  265. char *data;
  266. {
  267.     struct timeval tv;
  268.  
  269.     if (!DIO_FD_EVENT(dtype))
  270.       return (NULL);
  271.  
  272.     dtype |= (DIO_TIMEOUT|DIO_REPEAT);
  273.  
  274.     tv_period_to_tv(timeout, &tv);
  275.  
  276.     return (register_generic(dtype, priority, fd, &tv, routine, data));
  277. }
  278.  
  279. DIO *
  280. dispatch_register_alarm(priority, period, routine, data)
  281. int priority;
  282. double period;
  283. int (*routine)();
  284. char *data;
  285. {
  286.     struct timeval tv;
  287.  
  288.     tv_period_to_tv(period, &tv);
  289.  
  290.     return (register_generic(DIO_TIMEOUT, priority, -1, &tv, routine, data));
  291. }
  292.  
  293. DIO *
  294. dispatch_register_periodic(priority, period, routine, data)
  295. int priority;
  296. double period;
  297. int (*routine)();
  298. char *data;
  299. {
  300.     struct timeval tv;
  301.  
  302.     tv_period_to_tv(period, &tv);
  303.  
  304.     return (register_generic(DIO_TIMEOUT|DIO_REPEAT, priority, -1, &tv,
  305.                  routine, data));
  306. }
  307.  
  308. DIO *
  309. dispatch_register_rpc(priority)
  310. int priority;
  311. {
  312.     return (register_generic(DIO_RPC, priority, -1, NULL, NULL, NULL));
  313. }
  314.  
  315. int
  316. dispatch_unregister_fd(dtype, fd)
  317. int dtype;
  318. int fd;
  319. {
  320.     DIO *d;
  321.  
  322.     if ((d = get_dio(dtype, fd)) == NULL)
  323.       return (-1);
  324.  
  325.     return (dispatch_unregister(d));
  326. }
  327.  
  328. DIO *
  329. dispatch_change_handler(d, routine)
  330. DIO *d;
  331. int (*routine)();
  332. {
  333.     d->routine = routine;
  334.     
  335.     return (d);
  336. }
  337.  
  338. DIO *
  339. dispatch_change_priority(d, priority)
  340. DIO *d;
  341. int priority;
  342. {
  343.     DIO *new;
  344.  
  345.     if ((new = salloc(1, DIO)) == NULL)
  346.       return (NULL);
  347.  
  348.     /* copy the stuff over */
  349.     *new = *d;
  350.  
  351.     if (dispatch_unregister(d) < 0) {
  352.     cfree(new);
  353.     return (NULL);
  354.     }
  355.  
  356.     if (add_dio(d, priority) == NULL) {
  357.     cfree(new);
  358.     return (NULL);
  359.     }
  360.  
  361.     return (new);
  362. }
  363.  
  364. int
  365. dispatch_print_queues()
  366. {
  367.     NODE *dq_node = NULL;
  368.     NODE *d_node;
  369.     struct dqueue *dq;
  370.     DIO *d;
  371.  
  372.     if (dqueue_list == NULL)
  373.       return (0);
  374.  
  375.     while ((dq = (struct dqueue *)list_next(dqueue_list, &dq_node)) != NULL) {
  376.     if (dq->dio_list != NULL) {
  377.         printf("priority: %d\n", dq->priority);
  378.         d_node = NULL;
  379.         while ((d = (DIO *)list_next(dq->dio_list, &d_node)) != NULL) {
  380.         printf("  ");
  381.         if (d->dtype & DIO_READ)
  382.           printf("read ");
  383.         if (d->dtype & DIO_WRITE)
  384.           printf("write ");
  385.         if (d->dtype & DIO_EXCEPT)
  386.           printf("except ");
  387.         if (d->dtype & DIO_TIMEOUT)
  388.           printf("timeout ");
  389.         if (d->dtype & DIO_REPEAT)
  390.           printf("repeat ");
  391.         if (d->dtype & DIO_DELETED)
  392.           printf("deleted ");
  393.         if (d->dtype & DIO_RPC)
  394.           printf("rpc ");
  395.         printf("fd=%d, next=%d %d, int=%d %d\n",
  396.                d->fd,
  397.                d->time_next.tv_sec, d->time_next.tv_usec,
  398.                d->time_interval.tv_sec, d->time_interval.tv_usec);
  399.         }
  400.     }
  401.     }
  402.     
  403.     return (0);
  404. }
  405.  
  406. int
  407. dispatch_run()
  408. {
  409.     int dtbsz = getdtablesize();
  410.     fd_set masks[DIO_MASKS];
  411.     NODE *d_node, *dq_node;
  412.     struct dqueue *dq;
  413.     struct timeval time_current, time_next, time_zero, time_timeout;
  414.     struct timeval *timeout;
  415.     DIO *d;
  416.     int events;
  417.     int count;
  418.     int i;
  419.  
  420.     recompute_timeout = TRUE;
  421.  
  422.     tv_zero(&time_zero);
  423.  
  424.     for (;;) {
  425.       reselect:
  426.     for (i=0; i<DIO_MASKS; i++)
  427.       masks[i] = dispatch_masks[i];
  428.     
  429.     /* add in the rpc svc set */
  430.     fd_or(&masks[DIO_MASK_READ], &svc_fdset);
  431.  
  432.     /* get alarm wait period */
  433.     if (recompute_timeout) {
  434.         tv_zero(&time_next);
  435.         if (alarm_list != NULL) {
  436.         d_node = NULL;
  437.         while ((d = (DIO *)list_next(alarm_list, &d_node)) != NULL) {
  438.             if (tv_iszero(&time_next)) {
  439.             time_next = d->time_next;
  440.             } else {
  441.             if (tv_cmp(&d->time_next, &time_next) < 0)
  442.               time_next = d->time_next;
  443.             }
  444.         }
  445.         }
  446.         recompute_timeout = FALSE;
  447.     }
  448.  
  449.     if (tv_iszero(&time_next))
  450.       timeout = NULL;
  451.     else {
  452.         if (tv_current(&time_current) == NULL)
  453.           return (-1);
  454.         time_timeout = time_next;
  455.         tv_subtract(&time_timeout, &time_current);
  456.         if (tv_cmp(&time_timeout, &time_zero) < 0)
  457.           timeout = &time_zero;
  458.         else
  459.           timeout = &time_timeout;
  460.     }
  461.  
  462.     count = select(dtbsz, &masks[DIO_MASK_READ], &masks[DIO_MASK_WRITE],
  463.                &masks[DIO_MASK_EXCEPT], timeout);
  464.     if (count < 0) {
  465.         /* system call interrupted us */
  466.         if (errno == EINTR)
  467.           continue;
  468.         else
  469.           return (-1);
  470.     }
  471.  
  472.     if (tv_current(&time_current) == NULL)
  473.       return (-1);
  474.  
  475.     dq_node = NULL; events = 0;
  476.     if (dqueue_list != NULL)
  477.       while ((dq = (struct dqueue *)list_next(dqueue_list, &dq_node)) 
  478.          != NULL){
  479.           if (dq->dio_list != NULL) {
  480.           d_node = NULL;
  481.           d = (DIO *)list_next(dq->dio_list, &d_node);
  482.           while (d) {
  483.               int delete = FALSE; 
  484.               int timeout_changed = FALSE;
  485.               if (d->dtype & DIO_DELETED) {
  486.               delete = TRUE;
  487.               } else if (DIO_FD_EVENT(d->dtype) && 
  488.                  (FD_ISSET(d->fd, 
  489.                        &masks[DIO_FD_MASK(d->dtype)]))) {
  490.               if (d->routine != NULL)
  491.                 (*(d->routine))(d->fd, d->data,
  492.                         DIO_FD_EVENT(d->dtype), d);
  493.               events++;
  494.               count--;
  495.               if (d->dtype & DIO_TIMEOUT)
  496.                 timeout_changed = TRUE;
  497.               if (!(d->dtype & DIO_REPEAT))
  498.                 delete = TRUE;
  499.               /* make sure we don't run again, if re-added */
  500.               FD_CLR(d->fd, &masks[DIO_FD_MASK(d->dtype)]);
  501.               } else if (d->dtype & DIO_TIMEOUT) {
  502. #ifdef DEBUG
  503.               printf("checking for %s\n", d->data);
  504. #endif
  505.               if (tv_cmp(&d->time_next, &time_current) <= 0) {
  506. #ifdef DEBUG
  507.                   printf("  running %s\n", d->data);
  508. #endif
  509.                   if (d->routine != NULL) {
  510.                   if (DIO_FD_EVENT(d->dtype))
  511.                     (*(d->routine))(d->fd, d->data,
  512.                             DIO_TIMEOUT|
  513.                             DIO_FD_EVENT(d->dtype), d);
  514.                   else
  515.                     (*(d->routine))(d->data, d);
  516.                   }
  517.                   if (!(d->dtype & DIO_REPEAT))
  518.                 delete = TRUE;
  519.                   timeout_changed = TRUE;
  520.               }
  521.               } else if (d->dtype & DIO_RPC) {
  522.               fd_set mask;
  523.               mask = masks[DIO_MASK_READ];
  524.               fd_and(&mask, &svc_fdset);
  525.               if (fd_any(&mask))
  526.                 svc_getreqset(&mask);
  527.               }
  528.               if (delete) {
  529.               DIO *hold = d;
  530. #ifdef DEBUG
  531.               printf("deleting %s\n", d->data);
  532. #endif
  533.               if (d->dtype & DIO_TIMEOUT) {
  534.                   list_delete(alarm_list, (char *)d);
  535.                   recompute_timeout = TRUE;
  536.               }
  537.               d = (DIO *)list_delete_next(dq->dio_list, &d_node);
  538.               cfree((char *)hold);
  539.               } else {
  540.               if (timeout_changed) {
  541.                   d->time_next = time_current;
  542.                   tv_add(&d->time_next, &d->time_interval);
  543.                   recompute_timeout = TRUE;
  544.               }
  545.               d = (DIO *)list_next(dq->dio_list, &d_node);
  546. #ifdef DEBUG
  547.               if (d == NULL)
  548.                 printf("\n");
  549. #endif
  550.               }
  551.  
  552.           }
  553.           if (events > 0)
  554.             goto reselect;
  555.           }
  556.       }
  557.     }
  558. }
  559.  
  560. #ifdef DEBUG
  561. DIO *p, *t;
  562. int fd;
  563.  
  564. handler(data)
  565. char *data;
  566. {
  567.     printf("foo %s\n", data);
  568. }
  569.  
  570. /*ARGSUSED*/
  571. terminator(data)
  572. char *data;
  573. {
  574.     printf("bar %s\n", data);
  575.     dispatch_unregister(p);
  576. }
  577.  
  578. timeout(fd, data)
  579. int fd;
  580. char *data;
  581. {
  582.     printf("timeout %d %s\n", fd, data);
  583. }
  584.  
  585. #include <sys/file.h>
  586.  
  587. dispatch_test()
  588. {
  589.     dqueue_list = NULL;
  590.  
  591.     if ((fd = open("/dev/tty", O_RDONLY)) < 0)
  592.       return;
  593.  
  594.     p = dispatch_register_periodic(0, 5.0, handler, "periodic");
  595.     dispatch_register_alarm(0, 10.0, handler, "10 seconds");
  596.     dispatch_register_alarm(0, 30.0, handler, "30 seconds");
  597.     dispatch_register_alarm(0, 40.0, terminator, "40 seconds");
  598.     t = dispatch_register_fd_timeout(DIO_EXCEPT, 0, fd, 5.0, timeout, "timeout test");
  599.  
  600.     return (dispatch_run());
  601. }
  602. #endif
  603.