Changeset f97c1a6 for select.c


Ignore:
Timestamp:
May 23, 2011, 9:09:44 PM (10 years ago)
Author:
David Benjamin <davidben@mit.edu>
Branches:
master, release-1.8, release-1.9
Children:
33b6431b
Parents:
4c7c21f (diff), 1d21d9f (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:
Merge branch 'g_main_loop'

The logic in owl_select_prune_bad_fds still needs to be reimplemented.

Conflicts:
	configure.ac
	owl.c
	select.c
File:
1 edited

Legend:

Unmodified
Added
Removed
  • select.c

    rfb96152 rf97c1a6  
    11#include "owl.h"
    2 #include <sys/stat.h>
    3 
     2
     3static GMainLoop *loop = NULL;
     4static GMainContext *context;
    45static int dispatch_active = 0;
    5 static int psa_active = 0;
    6 static int loop_active = 0;
    7 
    8 int _owl_select_timer_cmp(const owl_timer *t1, const owl_timer *t2) {
     6
     7static GSource *owl_timer_source;
     8static GSource *owl_io_dispatch_source;
     9
     10static int _owl_select_timer_cmp(const owl_timer *t1, const owl_timer *t2) {
    911  return t1->time - t2->time;
    10 }
    11 
    12 int _owl_select_timer_eq(const owl_timer *t1, const owl_timer *t2) {
    13   return t1 == t2;
    1412}
    1513
     
    4442}
    4543
    46 void owl_select_process_timers(struct timespec *timeout)
    47 {
    48   time_t now = time(NULL);
    49   GList **timers = owl_global_get_timerlist(&g);
    50 
     44static gboolean owl_timer_prepare(GSource *source, int *timeout) {
     45  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
     68static 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
     85static 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? */
    5194  while(*timers) {
    5295    owl_timer *t = (*timers)->data;
    5396    int remove = 0;
    5497
    55     if(t->time > now)
     98    if(t->time > now.tv_sec)
    5699      break;
    57100
    58101    /* Reschedule if appropriate */
    59102    if(t->interval > 0) {
    60       t->time = now + t->interval;
     103      t->time = now.tv_sec + t->interval;
    61104      *timers = g_list_remove(*timers, t);
    62105      *timers = g_list_insert_sorted(*timers, t,
     
    72115    }
    73116  }
    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 }
     117  return TRUE;
     118}
     119
     120static GSourceFuncs owl_timer_funcs = {
     121  owl_timer_prepare,
     122  owl_timer_check,
     123  owl_timer_dispatch,
     124  NULL
     125};
     126
    86127
    87128static const owl_io_dispatch *owl_select_find_io_dispatch_by_fd(const int fd)
     
    129170        if (d->destroy)
    130171          d->destroy(d);
     172        g_source_remove_poll(owl_io_dispatch_source, &d->pollfd);
    131173        g_free(d);
    132174      }
     
    135177}
    136178
    137 void owl_select_io_dispatch_gc(void)
     179static void owl_select_io_dispatch_gc(void)
    138180{
    139181  int i;
     
    170212  d->data = data;
    171213
     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
    172226  owl_select_remove_io_dispatch(owl_select_find_io_dispatch_by_fd(fd));
    173227  owl_list_append_element(dl, d);
     
    176230}
    177231
    178 int 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;
     232static gboolean owl_io_dispatch_prepare(GSource *source, int *timeout) {
     233  *timeout = -1;
     234  return FALSE;
     235}
     236
     237static 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
     251static 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);
    184257  len = owl_list_get_size(dl);
    185258  for (i = 0; i < len; i++) {
    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 
    197 void 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)))) {
     259    owl_io_dispatch *d = owl_list_get_element(dl, i);
     260    if ((d->pollfd.revents & d->pollfd.events) && d->callback != NULL) {
    211261      d->callback(d, d->data);
    212262    }
     
    214264  dispatch_active = 0;
    215265  owl_select_io_dispatch_gc();
    216 }
     266
     267  return TRUE;
     268}
     269
     270static GSourceFuncs owl_io_dispatch_funcs = {
     271  owl_io_dispatch_prepare,
     272  owl_io_dispatch_check,
     273  owl_io_dispatch_dispatch,
     274  NULL
     275};
    217276
    218277int owl_select_add_perl_io_dispatch(int fd, int mode, SV *cb)
     
    238297}
    239298
    240 int 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 
    264 void 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 
    275 void 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 
    288 void 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 
    300 owl_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 
    312 void 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 
    331 void 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 
    338 int 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 
     299void 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);
     306}
     307
     308void owl_select_run_loop(void)
     309{
     310  context = g_main_context_default();
     311  loop = g_main_loop_new(context, FALSE);
     312  g_main_loop_run(loop);
     313}
     314
     315void owl_select_quit_loop(void)
     316{
     317  if (loop) {
     318    g_main_loop_quit(loop);
     319    loop = NULL;
     320  }
     321}
     322
     323#if 0
     324/* FIXME: Reimplement this check in the glib world. */
    358325static void owl_select_prune_bad_fds(void) {
    359326  owl_list *dl = owl_global_get_io_dispatch_list(&g);
     
    372339  owl_select_io_dispatch_gc();
    373340}
    374 
    375 void 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   }
    463 }
    464 
    465 void owl_select_run_loop(void)
    466 {
    467   loop_active = 1;
    468   while (loop_active) {
    469     owl_select();
    470   }
    471 }
    472 
    473 void owl_select_quit_loop(void)
    474 {
    475   loop_active = 0;
    476 }
     341#endif
     342
     343typedef struct _owl_task { /*noproto*/
     344  void (*cb)(void *);
     345  void *cbdata;
     346  void (*destroy_cbdata)(void *);
     347} owl_task;
     348
     349static gboolean _run_task(gpointer data)
     350{
     351  owl_task *t = data;
     352  if (t->cb)
     353    t->cb(t->cbdata);
     354  return FALSE;
     355}
     356
     357static void _destroy_task(void *data)
     358{
     359  owl_task *t = data;
     360  if (t->destroy_cbdata)
     361    t->destroy_cbdata(t->cbdata);
     362  g_free(t);
     363}
     364
     365void owl_select_post_task(void (*cb)(void*), void *cbdata, void (*destroy_cbdata)(void*))
     366{
     367  GSource *source = g_idle_source_new();
     368  owl_task *t = g_new0(owl_task, 1);
     369  t->cb = cb;
     370  t->cbdata = cbdata;
     371  t->destroy_cbdata = destroy_cbdata;
     372  g_source_set_priority(source, G_PRIORITY_DEFAULT);
     373  g_source_set_callback(source, _run_task, t, _destroy_task);
     374  g_source_attach(source, context);
     375  g_source_unref(source);
     376}
Note: See TracChangeset for help on using the changeset viewer.