Changeset fc625fb for select.c


Ignore:
Timestamp:
Jun 22, 2011, 3:45:52 PM (13 years ago)
Author:
GitHub Merge Button <merge-button@github.com>
Parents:
b343c2c (diff), 6376af1 (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 6376af1d0990d3324261fd650a8d36af1195eacf into b343c2c1248ccfcd8b514c26f4c896c1ec41888b
File:
1 edited

Legend:

Unmodified
Added
Removed
  • select.c

    r44976fe r84a071f  
    22
    33static GMainLoop *loop = NULL;
    4 static GMainContext *main_context;
    5 static 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) {
    11   return t1->time - t2->time;
    12 }
    13 
    14 owl_timer *owl_select_add_timer(const char* name, int after, int interval, void (*cb)(owl_timer *, void *), void (*destroy)(owl_timer*), void *data)
    15 {
    16   owl_timer *t = g_new(owl_timer, 1);
    17   GList **timers = owl_global_get_timerlist(&g);
    18 
    19   t->time = time(NULL) + after;
    20   t->interval = interval;
    21   t->callback = cb;
    22   t->destroy = destroy;
    23   t->data = data;
    24   t->name = name ? g_strdup(name) : NULL;
    25 
    26   *timers = g_list_insert_sorted(*timers, t,
    27                                  (GCompareFunc)_owl_select_timer_cmp);
    28   return t;
    29 }
    30 
    31 void owl_select_remove_timer(owl_timer *t)
    32 {
    33   GList **timers = owl_global_get_timerlist(&g);
    34   if (t && g_list_find(*timers, t)) {
    35     *timers = g_list_remove(*timers, t);
    36     if(t->destroy) {
    37       t->destroy(t);
    38     }
    39     g_free(t->name);
    40     g_free(t);
    41   }
    42 }
    43 
    44 static 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 
    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? */
    94   while(*timers) {
    95     owl_timer *t = (*timers)->data;
    96     int remove = 0;
    97 
    98     if(t->time > now.tv_sec)
    99       break;
    100 
    101     /* Reschedule if appropriate */
    102     if(t->interval > 0) {
    103       t->time = now.tv_sec + t->interval;
    104       *timers = g_list_remove(*timers, t);
    105       *timers = g_list_insert_sorted(*timers, t,
    106                                      (GCompareFunc)_owl_select_timer_cmp);
    107     } else {
    108       remove = 1;
    109     }
    110 
    111     /* Do the callback */
    112     t->callback(t, t->data);
    113     if(remove) {
    114       owl_select_remove_timer(t);
    115     }
    116   }
    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 
    127 /* Returns the valid owl_io_dispatch for a given file descriptor. */
    128 static owl_io_dispatch *owl_select_find_valid_io_dispatch_by_fd(const int fd)
    129 {
    130   int i, len;
    131   const owl_list *dl;
    132   owl_io_dispatch *d;
    133   dl = owl_global_get_io_dispatch_list(&g);
    134   len = owl_list_get_size(dl);
    135   for(i = 0; i < len; i++) {
    136     d = owl_list_get_element(dl, i);
    137     if (d->fd == fd && d->valid) return d;
    138   }
    139   return NULL;
    140 }
    141 
    142 static int owl_select_find_io_dispatch(const owl_io_dispatch *in)
    143 {
    144   int i, len;
    145   const owl_list *dl;
    146 
    147   if (in != NULL) {
    148     dl = owl_global_get_io_dispatch_list(&g);
    149     len = owl_list_get_size(dl);
    150     for(i = 0; i < len; i++) {
    151       const owl_io_dispatch *d = owl_list_get_element(dl, i);
    152       if (d == in) return i;
    153     }
    154   }
    155   return -1;
    156 }
    157 
    158 static void owl_select_invalidate_io_dispatch(owl_io_dispatch *d)
    159 {
    160   if (d == NULL || !d->valid)
    161     return;
    162   d->valid = false;
    163   g_source_remove_poll(owl_io_dispatch_source, &d->pollfd);
    164 }
    165 
    166 void owl_select_remove_io_dispatch(const owl_io_dispatch *in)
    167 {
    168   int elt;
    169   if (in != NULL) {
    170     elt = owl_select_find_io_dispatch(in);
    171     if (elt != -1) {
    172       owl_list *dl = owl_global_get_io_dispatch_list(&g);
    173       owl_io_dispatch *d = owl_list_get_element(dl, elt);
    174       if (dispatch_active)
    175         d->needs_gc = 1;
    176       else {
    177         owl_select_invalidate_io_dispatch(d);
    178         owl_list_remove_element(dl, elt);
    179         if (d->destroy)
    180           d->destroy(d);
    181         g_free(d);
    182       }
    183     }
    184   }
    185 }
    186 
    187 static void owl_select_io_dispatch_gc(void)
    188 {
    189   int i;
    190   owl_list *dl;
    191 
    192   dl = owl_global_get_io_dispatch_list(&g);
    193   /*
    194    * Count down so we aren't set off by removing items from the list
    195    * during the iteration.
    196    */
    197   for(i = owl_list_get_size(dl) - 1; i >= 0; i--) {
    198     owl_io_dispatch *d = owl_list_get_element(dl, i);
    199     if(d->needs_gc) {
    200       owl_select_remove_io_dispatch(d);
    201     }
    202   }
    203 }
    204 
    205 /* Each FD may have at most one valid dispatcher.
    206  * If a new dispatch is added for an FD, the old one is removed.
    207  * mode determines what types of events are watched for, and may be any combination of:
    208  * OWL_IO_READ, OWL_IO_WRITE, OWL_IO_EXCEPT
    209  */
    210 const owl_io_dispatch *owl_select_add_io_dispatch(int fd, int mode, void (*cb)(const owl_io_dispatch *, void *), void (*destroy)(const owl_io_dispatch *), void *data)
    211 {
    212   owl_io_dispatch *d = g_new(owl_io_dispatch, 1);
    213   owl_list *dl = owl_global_get_io_dispatch_list(&g);
    214   owl_io_dispatch *other;
    215 
    216   d->fd = fd;
    217   d->valid = true;
    218   d->needs_gc = 0;
    219   d->mode = mode;
    220   d->callback = cb;
    221   d->destroy = destroy;
    222   d->data = data;
    223 
    224   /* TODO: Allow changing fd and mode in the middle? Probably don't care... */
    225   d->pollfd.fd = fd;
    226   d->pollfd.events = 0;
    227   if (d->mode & OWL_IO_READ)
    228     d->pollfd.events |= G_IO_IN | G_IO_HUP | G_IO_ERR;
    229   if (d->mode & OWL_IO_WRITE)
    230     d->pollfd.events |= G_IO_OUT | G_IO_ERR;
    231   if (d->mode & OWL_IO_EXCEPT)
    232     d->pollfd.events |= G_IO_PRI | G_IO_ERR;
    233   g_source_add_poll(owl_io_dispatch_source, &d->pollfd);
    234 
    235 
    236   other = owl_select_find_valid_io_dispatch_by_fd(fd);
    237   if (other)
    238     owl_select_invalidate_io_dispatch(other);
    239   owl_list_append_element(dl, d);
    240 
    241   return d;
    242 }
    243 
    244 static gboolean owl_io_dispatch_prepare(GSource *source, int *timeout) {
    245   *timeout = -1;
    246   return FALSE;
    247 }
    248 
    249 static gboolean owl_io_dispatch_check(GSource *source) {
    250   int i, len;
    251   const owl_list *dl;
    252 
    253   dl = owl_global_get_io_dispatch_list(&g);
    254   len = owl_list_get_size(dl);
    255   for(i = 0; i < len; i++) {
    256     owl_io_dispatch *d = owl_list_get_element(dl, i);
    257     if (!d->valid) continue;
    258     if (d->pollfd.revents & G_IO_NVAL) {
    259       owl_function_debugmsg("Pruning defunct dispatch on fd %d.", d->fd);
    260       owl_select_invalidate_io_dispatch(d);
    261     }
    262     if (d->pollfd.revents & d->pollfd.events)
    263       return TRUE;
    264   }
    265   return FALSE;
    266 }
    267 
    268 static gboolean owl_io_dispatch_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) {
    269   int i, len;
    270   const owl_list *dl;
    271 
    272   dispatch_active = 1;
    273   dl = owl_global_get_io_dispatch_list(&g);
    274   len = owl_list_get_size(dl);
    275   for (i = 0; i < len; i++) {
    276     owl_io_dispatch *d = owl_list_get_element(dl, i);
    277     if (!d->valid) continue;
    278     if ((d->pollfd.revents & d->pollfd.events) && d->callback != NULL) {
    279       d->callback(d, d->data);
    280     }
    281   }
    282   dispatch_active = 0;
    283   owl_select_io_dispatch_gc();
    284 
    285   return TRUE;
    286 }
    287 
    288 static GSourceFuncs owl_io_dispatch_funcs = {
    289   owl_io_dispatch_prepare,
    290   owl_io_dispatch_check,
    291   owl_io_dispatch_dispatch,
    292   NULL
    293 };
    294 
    295 int owl_select_add_perl_io_dispatch(int fd, int mode, SV *cb)
    296 {
    297   const owl_io_dispatch *d = owl_select_find_valid_io_dispatch_by_fd(fd);
    298   if (d != NULL && d->callback != owl_perlconfig_io_dispatch) {
    299     /* Don't mess with non-perl dispatch functions from here. */
    300     return 1;
    301   }
    302   /* Also remove any invalidated perl dispatch functions that may have
    303    * stuck around. */
    304   owl_select_remove_perl_io_dispatch(fd);
    305   owl_select_add_io_dispatch(fd, mode, owl_perlconfig_io_dispatch, owl_perlconfig_io_dispatch_destroy, cb);
    306   return 0;
    307 }
    308 
    309 static owl_io_dispatch *owl_select_find_perl_io_dispatch(int fd)
    310 {
    311   int i, len;
    312   const owl_list *dl;
    313   owl_io_dispatch *d;
    314   dl = owl_global_get_io_dispatch_list(&g);
    315   len = owl_list_get_size(dl);
    316   for(i = 0; i < len; i++) {
    317     d = owl_list_get_element(dl, i);
    318     if (d->fd == fd && d->callback == owl_perlconfig_io_dispatch)
    319       return d;
    320   }
    321   return NULL;
    322 }
    323 
    324 int owl_select_remove_perl_io_dispatch(int fd)
    325 {
    326   owl_io_dispatch *d = owl_select_find_perl_io_dispatch(fd);
    327   if (d != NULL) {
    328     /* Only remove perl io dispatchers from here. */
    329     owl_select_remove_io_dispatch(d);
    330     return 0;
    331   }
    332   return 1;
    333 }
    3344
    3355void owl_select_init(void)
    3366{
    337   owl_timer_source = g_source_new(&owl_timer_funcs, sizeof(GSource));
    338   g_source_attach(owl_timer_source, NULL);
    339 
    340   owl_io_dispatch_source = g_source_new(&owl_io_dispatch_funcs, sizeof(GSource));
    341   g_source_attach(owl_io_dispatch_source, NULL);
    3427}
    3438
    3449void owl_select_run_loop(void)
    34510{
    346   main_context = g_main_context_default();
    347   loop = g_main_loop_new(main_context, FALSE);
     11  loop = g_main_loop_new(NULL, FALSE);
    34812  g_main_loop_run(loop);
    34913}
     
    35317  if (loop) {
    35418    g_main_loop_quit(loop);
     19    g_main_loop_unref(loop);
    35520    loop = NULL;
    35621  }
Note: See TracChangeset for help on using the changeset viewer.