"Fossies" - the Fresh Open Source Software Archive

Member "links-1.03/select.c" (19 Nov 2011, 9350 Bytes) of archive /linux/www/links-1.03.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "select.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.8_vs_1.03.

    1 #include "links.h"
    2 
    3 struct thread {
    4     void (*read_func)(void *);
    5     void (*write_func)(void *);
    6     void (*error_func)(void *);
    7     void *data;
    8 };
    9 
   10 struct thread threads[FD_SETSIZE];
   11 
   12 fd_set w_read;
   13 fd_set w_write;
   14 fd_set w_error;
   15 
   16 fd_set x_read;
   17 fd_set x_write;
   18 fd_set x_error;
   19 
   20 int w_max;
   21 
   22 int timer_id = 0;
   23 
   24 struct timer {
   25     struct timer *next;
   26     struct timer *prev;
   27     ttime interval;
   28     void (*func)(void *);
   29     void *data;
   30     int id;
   31 };
   32 
   33 struct list_head timers = {&timers, &timers};
   34 
   35 ttime get_time()
   36 {
   37     struct timeval tv;
   38     gettimeofday(&tv, NULL);
   39     return tv.tv_sec * 1000 + tv.tv_usec / 1000;
   40 }
   41 
   42 long select_info(int type)
   43 {
   44     int i = 0, j;
   45     struct cache_entry *ce;
   46     switch (type) {
   47         case CI_FILES:
   48             for (j = 0; j < FD_SETSIZE; j++)
   49                 if (threads[j].read_func || threads[j].write_func || threads[j].error_func) i++;
   50             return i;
   51         case CI_TIMERS:
   52             foreach(ce, timers) i++;
   53             return i;
   54         default:
   55             internal("cache_info: bad request");
   56     }
   57     return 0;
   58 }
   59 
   60 struct bottom_half {
   61     struct bottom_half *next;
   62     struct bottom_half *prev;
   63     void (*fn)(void *);
   64     void *data;
   65 };
   66 
   67 struct list_head bottom_halves = { &bottom_halves, &bottom_halves };
   68 
   69 int register_bottom_half(void (*fn)(void *), void *data)
   70 {
   71     struct bottom_half *bh;
   72     foreach(bh, bottom_halves) if (bh->fn == fn && bh->data == data) return 0;
   73     if (!(bh = mem_alloc(sizeof(struct bottom_half)))) return -1;
   74     bh->fn = fn;
   75     bh->data = data;
   76     add_to_list(bottom_halves, bh);
   77     return 0;
   78 }
   79 
   80 void check_bottom_halves()
   81 {
   82     struct bottom_half *bh;
   83     void (*fn)(void *);
   84     void *data;
   85     rep:
   86     if (list_empty(bottom_halves)) return;
   87     bh = bottom_halves.prev;
   88     fn = bh->fn;
   89     data = bh->data;
   90     del_from_list(bh);
   91     mem_free(bh);
   92     fn(data);
   93     goto rep;
   94 }
   95 
   96 #define CHK_BH if (!list_empty(bottom_halves)) check_bottom_halves()
   97         
   98 ttime last_time;
   99 
  100 void check_timers()
  101 {
  102     ttime interval = get_time() - last_time;
  103     struct timer *t;
  104     foreach(t, timers) t->interval -= interval;
  105     ch:
  106     foreach(t, timers) if (t->interval <= 0) {
  107         struct timer *tt = t;
  108         del_from_list(tt);
  109         tt->func(tt->data);
  110         mem_free(tt);
  111         CHK_BH;
  112         goto ch;
  113     } else break;
  114     last_time += interval;
  115 }
  116 
  117 int install_timer(ttime t, void (*func)(void *), void *data)
  118 {
  119     struct timer *tm, *tt;
  120     if (!(tm = mem_alloc(sizeof(struct timer)))) return -1;
  121     tm->interval = t;
  122     tm->func = func;
  123     tm->data = data;
  124     new_id:
  125     tm->id = timer_id;
  126     timer_id++;
  127     if (timer_id == MAXINT) timer_id = 0;
  128     foreach(tt, timers) if (tt->id == tm->id) goto new_id;
  129     foreach(tt, timers) if (tt->interval >= t) break;
  130     add_at_pos(tt->prev, tm);
  131     return tm->id;
  132 }
  133 
  134 void kill_timer(int id)
  135 {
  136     struct timer *tm;
  137     int k = 0;
  138     foreach(tm, timers) if (tm->id == id) {
  139         struct timer *tt = tm;
  140         del_from_list(tm);
  141         tm = tm->prev;
  142         mem_free(tt);
  143         k++;
  144     }
  145     if (!k) internal("trying to kill nonexisting timer");
  146     if (k >= 2) internal("more timers with same id");
  147 }
  148 
  149 void *get_handler(int fd, int tp)
  150 {
  151     if (fd < 0)
  152         internal("get_handler: handle %d", fd);
  153     if (fd >= (int)FD_SETSIZE) {
  154         error("too big handle %d");
  155         fatal_tty_exit();
  156         exit(RET_FATAL);
  157         return NULL;
  158     }
  159     switch (tp) {
  160         case H_READ:    return threads[fd].read_func;
  161         case H_WRITE:   return threads[fd].write_func;
  162         case H_ERROR:   return threads[fd].error_func;
  163         case H_DATA:    return threads[fd].data;
  164     }
  165     internal("get_handler: bad type %d", tp);
  166     return NULL;
  167 }
  168 
  169 void set_handlers(int fd, void (*read_func)(void *), void (*write_func)(void *), void (*error_func)(void *), void *data)
  170 {
  171     if (fd < 0)
  172         internal("set_handlers: handle %d", fd);
  173     if (fd >= (int)FD_SETSIZE) {
  174         error("too big handle %d");
  175         fatal_tty_exit();
  176         exit(RET_FATAL);
  177         return;
  178     }
  179     threads[fd].read_func = read_func;
  180     threads[fd].write_func = write_func;
  181     threads[fd].error_func = error_func;
  182     threads[fd].data = data;
  183     if (read_func) FD_SET(fd, &w_read);
  184     else {
  185         FD_CLR(fd, &w_read);
  186         FD_CLR(fd, &x_read);
  187     }
  188     if (write_func) FD_SET(fd, &w_write);
  189     else {
  190         FD_CLR(fd, &w_write);
  191         FD_CLR(fd, &x_write);
  192     }
  193     if (error_func) FD_SET(fd, &w_error);
  194     else {
  195         FD_CLR(fd, &w_error);
  196         FD_CLR(fd, &x_error);
  197     }
  198     if (read_func || write_func || error_func) {
  199         if (fd >= w_max) w_max = fd + 1;
  200     } else if (fd == w_max - 1) {
  201         int i;
  202         for (i = fd - 1; i >= 0; i--)
  203             if (FD_ISSET(i, &w_read) || FD_ISSET(i, &w_write) ||
  204                 FD_ISSET(i, &w_error)) break;
  205         w_max = i + 1;
  206     }
  207 }
  208 
  209 #define NUM_SIGNALS 32
  210 
  211 struct signal_handler {
  212     void (*fn)(void *);
  213     void *data;
  214     int critical;
  215 };
  216 
  217 int signal_mask[NUM_SIGNALS];
  218 struct signal_handler signal_handlers[NUM_SIGNALS];
  219 
  220 int signal_pipe[2];
  221 
  222 void signal_break(void *data)
  223 {
  224     char c;
  225     while (can_read(signal_pipe[0])) read(signal_pipe[0], &c, 1);
  226 }
  227 
  228 SIGNAL_HANDLER void got_signal(int sig)
  229 {
  230     int sv_errno = errno;
  231     if (sig >= NUM_SIGNALS || sig < 0) {
  232         /*error("ERROR: bad signal number: %d", sig);*/
  233         goto ret;
  234     }
  235     if (!signal_handlers[sig].fn) goto ret;
  236     if (signal_handlers[sig].critical) {
  237         signal_handlers[sig].fn(signal_handlers[sig].data);
  238         goto ret;
  239     }
  240     signal_mask[sig] = 1;
  241     ret:
  242     if (can_write(signal_pipe[1])) write(signal_pipe[1], "x", 1);
  243     errno = sv_errno;
  244 }
  245 
  246 struct sigaction sa_zero;
  247 
  248 void install_signal_handler(int sig, void (*fn)(void *), void *data, int critical)
  249 {
  250     struct sigaction sa = sa_zero;
  251     if (sig >= NUM_SIGNALS || sig < 0) {
  252         internal("bad signal number: %d", sig);
  253         return;
  254     }
  255     if (!fn) sa.sa_handler = SIG_IGN;
  256     else sa.sa_handler = (void *)got_signal;
  257 #ifdef HAVE_SIGFILLSET
  258     sigfillset(&sa.sa_mask);
  259 #else
  260     memset(&sa.sa_mask, -1, sizeof sa.sa_mask);
  261 #endif
  262     sa.sa_flags = SA_RESTART;
  263     if (!fn) sigaction(sig, &sa, NULL);
  264     signal_handlers[sig].fn = fn;
  265     signal_handlers[sig].data = data;
  266     signal_handlers[sig].critical = critical;
  267     if (fn) sigaction(sig, &sa, NULL);
  268 }
  269 
  270 void interruptible_signal(int sig, int in)
  271 {
  272     struct sigaction sa = sa_zero;
  273     if (sig >= NUM_SIGNALS || sig < 0) {
  274         internal("bad signal number: %d", sig);
  275         return;
  276     }
  277     if (!signal_handlers[sig].fn) return;
  278     sa.sa_handler = (void *)got_signal;
  279 #ifdef HAVE_SIGFILLSET
  280     sigfillset(&sa.sa_mask);
  281 #else
  282     memset(&sa.sa_mask, -1, sizeof sa.sa_mask);
  283 #endif
  284     if (!in) sa.sa_flags = SA_RESTART;
  285     sigaction(sig, &sa, NULL);
  286 }
  287 
  288 int check_signals()
  289 {
  290     int i, r = 0;
  291     for (i = 0; i < NUM_SIGNALS; i++)
  292         if (signal_mask[i]) {
  293             signal_mask[i] = 0;
  294             if (signal_handlers[i].fn) signal_handlers[i].fn(signal_handlers[i].data);
  295             CHK_BH;
  296             r = 1;
  297         }
  298     return r;
  299 }
  300 
  301 void sigchld(void *p)
  302 {
  303 #ifndef WNOHANG
  304     wait(NULL);
  305 #else
  306     while (waitpid(-1, NULL, WNOHANG) > 0) ;
  307 #endif
  308 }
  309 
  310 void set_sigcld()
  311 {
  312     install_signal_handler(SIGCHLD, sigchld, NULL, 1);
  313 }
  314 
  315 int terminate = 0;
  316 
  317 void select_loop(void (*init)())
  318 {
  319     struct stat st;
  320     if (stat(".", &st) && getenv("HOME")) chdir(getenv("HOME"));
  321     memset(&sa_zero, 0, sizeof sa_zero);
  322     memset(signal_mask, 0, sizeof signal_mask);
  323     memset(signal_handlers, 0, sizeof signal_handlers);
  324     FD_ZERO(&w_read);
  325     FD_ZERO(&w_write);
  326     FD_ZERO(&w_error);
  327     w_max = 0;
  328     last_time = get_time();
  329     signal(SIGPIPE, SIG_IGN);
  330     if (c_pipe(signal_pipe)) {
  331         error("ERROR: can't create pipe for signal handling");
  332         fatal_tty_exit();
  333         exit(RET_FATAL);
  334     }
  335     fcntl(signal_pipe[0], F_SETFL, O_NONBLOCK);
  336     fcntl(signal_pipe[1], F_SETFL, O_NONBLOCK);
  337     set_handlers(signal_pipe[0], signal_break, NULL, NULL, NULL);
  338     init();
  339     CHK_BH;
  340     while (!terminate) {
  341         int n, i;
  342         struct timeval tv;
  343         struct timeval *tm = NULL;
  344         check_signals();
  345         check_timers();
  346         redraw_all_terminals();
  347 #ifdef OS_BAD_SIGNALS
  348     /* Cygwin has buggy signals that sometimes don't interrupt select.
  349        So don't wait indefinitely in it. */
  350         tv.tv_sec = 1;
  351         tv.tv_usec = 0;
  352         tm = &tv;
  353 #endif
  354         if (!list_empty(timers)) {
  355             ttime tt = ((struct timer *)timers.next)->interval + 1;
  356             if (tt < 0) tt = 0;
  357 #ifdef OS_BAD_SIGNALS
  358             if (tt < 1000)
  359 #endif
  360             {
  361                 tv.tv_sec = tt / 1000;
  362                 tv.tv_usec = (tt % 1000) * 1000;
  363                 tm = &tv;
  364             }
  365         }
  366         memcpy(&x_read, &w_read, sizeof(fd_set));
  367         memcpy(&x_write, &w_write, sizeof(fd_set));
  368         memcpy(&x_error, &w_error, sizeof(fd_set));
  369         /*rep_sel:*/
  370         if (terminate) break;
  371         if (!w_max && list_empty(timers)) break;
  372         if (check_signals()) {
  373             continue;
  374         }
  375             /*{
  376                 int i;
  377                 printf("\nR:");
  378                 for (i = 0; i < 256; i++) if (FD_ISSET(i, &x_read)) printf("%d,", i);
  379                 printf("\nW:");
  380                 for (i = 0; i < 256; i++) if (FD_ISSET(i, &x_write)) printf("%d,", i);
  381                 printf("\nE:");
  382                 for (i = 0; i < 256; i++) if (FD_ISSET(i, &x_error)) printf("%d,", i);
  383                 fflush(stdout);
  384             }*/
  385         if ((n = select(w_max, &x_read, &x_write, &x_error, tm)) < 0) {
  386             if (errno != EINTR) {
  387                 error("ERROR: select failed: %s", strerror(errno));
  388                 fatal_tty_exit();
  389                 exit(RET_FATAL);
  390             }
  391             continue;
  392         }
  393         check_signals();
  394         /*printf("sel: %d\n", n);*/
  395         check_timers();
  396         i = -1;
  397         while (n > 0 && ++i < w_max) {
  398             int k = 0;
  399             /*printf("C %d : %d,%d,%d\n",i,FD_ISSET(i, &w_read),FD_ISSET(i, &w_write),FD_ISSET(i, &w_error));
  400             printf("A %d : %d,%d,%d\n",i,FD_ISSET(i, &x_read),FD_ISSET(i, &x_write),FD_ISSET(i, &x_error));*/
  401             if (FD_ISSET(i, &x_read)) {
  402                 if (threads[i].read_func) {
  403                     threads[i].read_func(threads[i].data);
  404                     CHK_BH;
  405                 }
  406                 k = 1;
  407             }
  408             if (FD_ISSET(i, &x_write)) {
  409                 if (threads[i].write_func) {
  410                     threads[i].write_func(threads[i].data);
  411                     CHK_BH;
  412                 }
  413                 k = 1;
  414             }
  415             if (FD_ISSET(i, &x_error)) {
  416                 if (threads[i].error_func) {
  417                     threads[i].error_func(threads[i].data);
  418                     CHK_BH;
  419                 }
  420                 k = 1;
  421             }
  422             n -= k;
  423         }
  424     }
  425 }