Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • select.c

    rba12b44 rfb96152  
    11#include "owl.h"
    2 
    3 static GMainLoop *loop = NULL;
    4 static GMainContext *context;
     2#include <sys/stat.h>
     3
    54static int dispatch_active = 0;
    6 
    7 static GSource *owl_timer_source;
    8 static GSource *owl_io_dispatch_source;
    9 
    10 static int _owl_select_timer_cmp(const owl_timer *t1, const owl_timer *t2) {
     5static int psa_active = 0;
     6static int loop_active = 0;
     7
     8int _owl_select_timer_cmp(const owl_timer *t1, const owl_timer *t2) {
    119  return t1->time - t2->time;
     10}
     11
     12int _owl_select_timer_eq(const owl_timer *t1, const owl_timer *t2) {
     13  return t1 == t2;
    1214}
    1315
     
    4244}
    4345
    44 static gboolean owl_timer_prepare(GSource *source, int *timeout) {
     46void owl_select_process_timers(struct timespec *timeout)
     47{
     48  time_t now = time(NULL);
    4549  GList **timers = owl_global_get_timerlist(&g);
    46   GTimeVal now;
    47 
    48   /* TODO: In the far /far/ future, g_source_get_time is what the cool
    49    * kids use to get system monotonic time. */
    50   g_source_get_current_time(source, &now);
    51 
    52   /* FIXME: bother with millisecond accuracy now that we can? */
    53   if (*timers) {
    54     owl_timer *t = (*timers)->data;
    55     *timeout = t->time - now.tv_sec;
    56     if (*timeout <= 0) {
    57       *timeout = 0;
    58       return TRUE;
    59     }
    60     if (*timeout > 60 * 1000)
    61       *timeout = 60 * 1000;
    62   } else {
    63     *timeout = 60 * 1000;
    64   }
    65   return FALSE;
    66 }
    67 
    68 static gboolean owl_timer_check(GSource *source) {
    69   GList **timers = owl_global_get_timerlist(&g);
    70   GTimeVal now;
    71 
    72   /* TODO: In the far /far/ future, g_source_get_time is what the cool
    73    * kids use to get system monotonic time. */
    74   g_source_get_current_time(source, &now);
    75 
    76   /* FIXME: bother with millisecond accuracy now that we can? */
    77   if (*timers) {
    78     owl_timer *t = (*timers)->data;
    79     return t->time >= now.tv_sec;
    80   }
    81   return FALSE;
    82 }
    83 
    84 
    85 static gboolean owl_timer_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) {
    86   GList **timers = owl_global_get_timerlist(&g);
    87   GTimeVal now;
    88 
    89   /* TODO: In the far /far/ future, g_source_get_time is what the cool
    90    * kids use to get system monotonic time. */
    91   g_source_get_current_time(source, &now);
    92 
    93   /* FIXME: bother with millisecond accuracy now that we can? */
     50
    9451  while(*timers) {
    9552    owl_timer *t = (*timers)->data;
    9653    int remove = 0;
    9754
    98     if(t->time > now.tv_sec)
     55    if(t->time > now)
    9956      break;
    10057
    10158    /* Reschedule if appropriate */
    10259    if(t->interval > 0) {
    103       t->time = now.tv_sec + t->interval;
     60      t->time = now + t->interval;
    10461      *timers = g_list_remove(*timers, t);
    10562      *timers = g_list_insert_sorted(*timers, t,
     
    11572    }
    11673  }
    117   return TRUE;
    118 }
    119 
    120 static GSourceFuncs owl_timer_funcs = {
    121   owl_timer_prepare,
    122   owl_timer_check,
    123   owl_timer_dispatch,
    124   NULL
    125 };
    126 
     74
     75  if(*timers) {
     76    owl_timer *t = (*timers)->data;
     77    timeout->tv_sec = t->time - now;
     78    if (timeout->tv_sec > 60)
     79      timeout->tv_sec = 60;
     80  } else {
     81    timeout->tv_sec = 60;
     82  }
     83
     84  timeout->tv_nsec = 0;
     85}
    12786
    12887static const owl_io_dispatch *owl_select_find_io_dispatch_by_fd(const int fd)
     
    170129        if (d->destroy)
    171130          d->destroy(d);
    172         g_source_remove_poll(owl_io_dispatch_source, &d->pollfd);
    173131        g_free(d);
    174132      }
     
    177135}
    178136
    179 static void owl_select_io_dispatch_gc(void)
     137void owl_select_io_dispatch_gc(void)
    180138{
    181139  int i;
     
    212170  d->data = data;
    213171
    214   /* TODO: Allow changing fd and mode in the middle? Probably don't care... */
    215   d->pollfd.fd = fd;
    216   d->pollfd.events = 0;
    217   if (d->mode & OWL_IO_READ)
    218     d->pollfd.events |= G_IO_IN | G_IO_HUP | G_IO_ERR;
    219   if (d->mode & OWL_IO_WRITE)
    220     d->pollfd.events |= G_IO_OUT | G_IO_ERR;
    221   if (d->mode & OWL_IO_EXCEPT)
    222     d->pollfd.events |= G_IO_PRI | G_IO_ERR;
    223   g_source_add_poll(owl_io_dispatch_source, &d->pollfd);
    224 
    225 
    226172  owl_select_remove_io_dispatch(owl_select_find_io_dispatch_by_fd(fd));
    227173  owl_list_append_element(dl, d);
     
    230176}
    231177
    232 static gboolean owl_io_dispatch_prepare(GSource *source, int *timeout) {
    233   *timeout = -1;
    234   return FALSE;
    235 }
    236 
    237 static gboolean owl_io_dispatch_check(GSource *source) {
    238   int i, len;
    239   const owl_list *dl;
    240 
    241   dl = owl_global_get_io_dispatch_list(&g);
    242   len = owl_list_get_size(dl);
    243   for(i = 0; i < len; i++) {
    244     const owl_io_dispatch *d = owl_list_get_element(dl, i);
    245     if (d->pollfd.revents & d->pollfd.events)
    246       return TRUE;
    247   }
    248   return FALSE;
    249 }
    250 
    251 static gboolean owl_io_dispatch_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) {
    252   int i, len;
    253   const owl_list *dl;
    254 
    255   dispatch_active = 1;
    256   dl = owl_global_get_io_dispatch_list(&g);
     178int owl_select_prepare_io_dispatch_fd_sets(fd_set *rfds, fd_set *wfds, fd_set *efds) {
     179  int i, len, max_fd;
     180  owl_io_dispatch *d;
     181  owl_list *dl = owl_global_get_io_dispatch_list(&g);
     182
     183  max_fd = 0;
    257184  len = owl_list_get_size(dl);
    258185  for (i = 0; i < len; i++) {
    259     owl_io_dispatch *d = owl_list_get_element(dl, i);
    260     if ((d->pollfd.revents & d->pollfd.events) && d->callback != NULL) {
     186    d = owl_list_get_element(dl, i);
     187    if (d->mode & (OWL_IO_READ | OWL_IO_WRITE | OWL_IO_EXCEPT)) {
     188      if (max_fd < d->fd) max_fd = d->fd;
     189      if (d->mode & OWL_IO_READ) FD_SET(d->fd, rfds);
     190      if (d->mode & OWL_IO_WRITE) FD_SET(d->fd, wfds);
     191      if (d->mode & OWL_IO_EXCEPT) FD_SET(d->fd, efds);
     192    }
     193  }
     194  return max_fd + 1;
     195}
     196
     197void owl_select_io_dispatch(const fd_set *rfds, const fd_set *wfds, const fd_set *efds, const int max_fd)
     198{
     199  int i, len;
     200  owl_io_dispatch *d;
     201  owl_list *dl = owl_global_get_io_dispatch_list(&g);
     202
     203  dispatch_active = 1;
     204  len = owl_list_get_size(dl);
     205  for (i = 0; i < len; i++) {
     206    d = owl_list_get_element(dl, i);
     207    if (d->fd < max_fd && d->callback != NULL &&
     208        ((d->mode & OWL_IO_READ && FD_ISSET(d->fd, rfds)) ||
     209         (d->mode & OWL_IO_WRITE && FD_ISSET(d->fd, wfds)) ||
     210         (d->mode & OWL_IO_EXCEPT && FD_ISSET(d->fd, efds)))) {
    261211      d->callback(d, d->data);
    262212    }
     
    264214  dispatch_active = 0;
    265215  owl_select_io_dispatch_gc();
    266 
    267   return TRUE;
    268 }
    269 
    270 static GSourceFuncs owl_io_dispatch_funcs = {
    271   owl_io_dispatch_prepare,
    272   owl_io_dispatch_check,
    273   owl_io_dispatch_dispatch,
    274   NULL
    275 };
     216}
    276217
    277218int owl_select_add_perl_io_dispatch(int fd, int mode, SV *cb)
     
    297238}
    298239
    299 void owl_select_init(void)
    300 {
    301   owl_timer_source = g_source_new(&owl_timer_funcs, sizeof(GSource));
    302   g_source_attach(owl_timer_source, NULL);
    303 
    304   owl_io_dispatch_source = g_source_new(&owl_io_dispatch_funcs, sizeof(GSource));
    305   g_source_attach(owl_io_dispatch_source, NULL);
     240int owl_select_aim_hack(fd_set *rfds, fd_set *wfds)
     241{
     242  aim_conn_t *cur;
     243  aim_session_t *sess;
     244  int max_fd;
     245
     246  max_fd = 0;
     247  sess = owl_global_get_aimsess(&g);
     248  for (cur = sess->connlist; cur; cur = cur->next) {
     249    if (cur->fd != -1) {
     250      FD_SET(cur->fd, rfds);
     251      if (cur->status & AIM_CONN_STATUS_INPROGRESS) {
     252        /* Yes, we're checking writable sockets here. Without it, AIM
     253           login is really slow. */
     254        FD_SET(cur->fd, wfds);
     255      }
     256     
     257      if (cur->fd > max_fd)
     258        max_fd = cur->fd;
     259    }
     260  }
     261  return max_fd;
     262}
     263
     264void owl_process_input_char(owl_input j)
     265{
     266  int ret;
     267
     268  owl_global_set_lastinputtime(&g, time(NULL));
     269  ret = owl_keyhandler_process(owl_global_get_keyhandler(&g), j);
     270  if (ret!=0 && ret!=1) {
     271    owl_function_makemsg("Unable to handle keypress");
     272  }
     273}
     274
     275void owl_select_mask_signals(sigset_t *oldmask) {
     276  sigset_t set;
     277
     278  sigemptyset(&set);
     279  sigaddset(&set, SIGWINCH);
     280  sigaddset(&set, SIGALRM);
     281  sigaddset(&set, SIGPIPE);
     282  sigaddset(&set, SIGTERM);
     283  sigaddset(&set, SIGHUP);
     284  sigaddset(&set, SIGINT);
     285  sigprocmask(SIG_BLOCK, &set, oldmask);
     286}
     287
     288void owl_select_handle_intr(sigset_t *restore)
     289{
     290  owl_input in;
     291
     292  owl_global_unset_interrupted(&g);
     293
     294  sigprocmask(SIG_SETMASK, restore, NULL);
     295
     296  in.ch = in.uch = owl_global_get_startup_tio(&g)->c_cc[VINTR];
     297  owl_process_input_char(in);
     298}
     299
     300owl_ps_action *owl_select_add_pre_select_action(int (*cb)(owl_ps_action *, void *), void (*destroy)(owl_ps_action *), void *data)
     301{
     302  owl_ps_action *a = g_new(owl_ps_action, 1);
     303  owl_list *psa_list = owl_global_get_psa_list(&g);
     304  a->needs_gc = 0;
     305  a->callback = cb;
     306  a->destroy = destroy;
     307  a->data = data;
     308  owl_list_append_element(psa_list, a);
     309  return a;
     310}
     311
     312void owl_select_psa_gc(void)
     313{
     314  int i;
     315  owl_list *psa_list;
     316  owl_ps_action *a;
     317
     318  psa_list = owl_global_get_psa_list(&g);
     319  for (i = owl_list_get_size(psa_list) - 1; i >= 0; i--) {
     320    a = owl_list_get_element(psa_list, i);
     321    if (a->needs_gc) {
     322      owl_list_remove_element(psa_list, i);
     323      if (a->destroy) {
     324        a->destroy(a);
     325      }
     326      g_free(a);
     327    }
     328  }
     329}
     330
     331void owl_select_remove_pre_select_action(owl_ps_action *a)
     332{
     333  a->needs_gc = 1;
     334  if (!psa_active)
     335    owl_select_psa_gc();
     336}
     337
     338int owl_select_do_pre_select_actions(void)
     339{
     340  int i, len, ret;
     341  owl_list *psa_list;
     342
     343  psa_active = 1;
     344  ret = 0;
     345  psa_list = owl_global_get_psa_list(&g);
     346  len = owl_list_get_size(psa_list);
     347  for (i = 0; i < len; i++) {
     348    owl_ps_action *a = owl_list_get_element(psa_list, i);
     349    if (a->callback != NULL && a->callback(a, a->data)) {
     350      ret = 1;
     351    }
     352  }
     353  psa_active = 0;
     354  owl_select_psa_gc();
     355  return ret;
     356}
     357
     358static void owl_select_prune_bad_fds(void) {
     359  owl_list *dl = owl_global_get_io_dispatch_list(&g);
     360  int len, i;
     361  struct stat st;
     362  owl_io_dispatch *d;
     363
     364  len = owl_list_get_size(dl);
     365  for (i = 0; i < len; i++) {
     366    d = owl_list_get_element(dl, i);
     367    if (fstat(d->fd, &st) < 0 && errno == EBADF) {
     368      owl_function_debugmsg("Pruning defunct dispatch on fd %d.", d->fd);
     369      d->needs_gc = 1;
     370    }
     371  }
     372  owl_select_io_dispatch_gc();
     373}
     374
     375void owl_select(void)
     376{
     377  int i, max_fd, max_fd2, aim_done, ret;
     378  fd_set r;
     379  fd_set w;
     380  fd_set e;
     381  fd_set aim_rfds, aim_wfds;
     382  struct timespec timeout;
     383  sigset_t mask;
     384
     385  owl_select_process_timers(&timeout);
     386
     387  owl_select_mask_signals(&mask);
     388
     389  if(owl_global_is_interrupted(&g)) {
     390    owl_select_handle_intr(&mask);
     391    return;
     392  }
     393  FD_ZERO(&r);
     394  FD_ZERO(&w);
     395  FD_ZERO(&e);
     396
     397  max_fd = owl_select_prepare_io_dispatch_fd_sets(&r, &w, &e);
     398
     399  /* AIM HACK:
     400   *
     401   *  The problem - I'm not sure where to hook into the owl/faim
     402   *  interface to keep track of when the AIM socket(s) open and
     403   *  close. In particular, the bosconn thing throws me off. So,
     404   *  rather than register particular dispatchers for AIM, I look up
     405   *  the relevant FDs and add them to select's watch lists, then
     406   *  check for them individually before moving on to the other
     407   *  dispatchers. --asedeno
     408   */
     409  aim_done = 1;
     410  FD_ZERO(&aim_rfds);
     411  FD_ZERO(&aim_wfds);
     412  if (owl_global_is_doaimevents(&g)) {
     413    aim_done = 0;
     414    max_fd2 = owl_select_aim_hack(&aim_rfds, &aim_wfds);
     415    if (max_fd < max_fd2) max_fd = max_fd2;
     416    for(i = 0; i <= max_fd2; i++) {
     417      if (FD_ISSET(i, &aim_rfds)) {
     418        FD_SET(i, &r);
     419        FD_SET(i, &e);
     420      }
     421      if (FD_ISSET(i, &aim_wfds)) {
     422        FD_SET(i, &w);
     423        FD_SET(i, &e);
     424      }
     425    }
     426  }
     427  /* END AIM HACK */
     428
     429  if (owl_select_do_pre_select_actions()) {
     430    timeout.tv_sec = 0;
     431    timeout.tv_nsec = 0;
     432  }
     433
     434  ret = pselect(max_fd+1, &r, &w, &e, &timeout, &mask);
     435
     436  if(ret < 0) {
     437    if (errno == EINTR) {
     438      if(owl_global_is_interrupted(&g)) {
     439        owl_select_handle_intr(NULL);
     440      }
     441    } else if (errno == EBADF) {
     442      /* Perl must have closed an fd on us without removing it first. */
     443      owl_select_prune_bad_fds();
     444    }
     445    sigprocmask(SIG_SETMASK, &mask, NULL);
     446    return;
     447  }
     448
     449  sigprocmask(SIG_SETMASK, &mask, NULL);
     450
     451  if(ret > 0) {
     452    /* AIM HACK: process all AIM events at once. */
     453    for(i = 0; !aim_done && i <= max_fd; i++) {
     454      if (FD_ISSET(i, &r) || FD_ISSET(i, &w) || FD_ISSET(i, &e)) {
     455        if (FD_ISSET(i, &aim_rfds) || FD_ISSET(i, &aim_wfds)) {
     456          owl_process_aim();
     457          aim_done = 1;
     458        }
     459      }
     460    }
     461    owl_select_io_dispatch(&r, &w, &e, max_fd);
     462  }
    306463}
    307464
    308465void owl_select_run_loop(void)
    309466{
    310   context = g_main_context_default();
    311   loop = g_main_loop_new(context, FALSE);
    312   g_main_loop_run(loop);
     467  loop_active = 1;
     468  while (loop_active) {
     469    owl_select();
     470  }
    313471}
    314472
    315473void owl_select_quit_loop(void)
    316474{
    317   if (loop) {
    318     g_main_loop_quit(loop);
    319     loop = NULL;
    320   }
    321 }
    322 
    323 typedef struct _owl_task { /*noproto*/
    324   void (*cb)(void *);
    325   void *cbdata;
    326   void (*destroy_cbdata)(void *);
    327 } owl_task;
    328 
    329 static gboolean _run_task(gpointer data)
    330 {
    331   owl_task *t = data;
    332   if (t->cb)
    333     t->cb(t->cbdata);
    334   return FALSE;
    335 }
    336 
    337 static void _destroy_task(void *data)
    338 {
    339   owl_task *t = data;
    340   if (t->destroy_cbdata)
    341     t->destroy_cbdata(t->cbdata);
    342   g_free(t);
    343 }
    344 
    345 void owl_select_post_task(void (*cb)(void*), void *cbdata, void (*destroy_cbdata)(void*))
    346 {
    347   GSource *source = g_idle_source_new();
    348   owl_task *t = g_new0(owl_task, 1);
    349   t->cb = cb;
    350   t->cbdata = cbdata;
    351   t->destroy_cbdata = destroy_cbdata;
    352   g_source_set_priority(source, G_PRIORITY_DEFAULT);
    353   g_source_set_callback(source, _run_task, t, _destroy_task);
    354   g_source_attach(source, context);
    355   g_source_unref(source);
    356 }
     475  loop_active = 0;
     476}
Note: See TracChangeset for help on using the changeset viewer.