source: select.c @ 7df7be2

Last change on this file since 7df7be2 was 7df7be2, checked in by David Benjamin <davidben@mit.edu>, 13 years ago
Replace BarnOwl::Timer with a perl wrapper over AnyEvent This also allows us to kill owl_timer altogether.
  • Property mode set to 100644
File size: 6.9 KB
RevLine 
[9c7a701]1#include "owl.h"
2
[2c79eae]3static GMainLoop *loop = NULL;
[44976fe]4static GMainContext *main_context;
[1895c29]5static int dispatch_active = 0;
6
[2c79eae]7static GSource *owl_io_dispatch_source;
[b7bb454]8
[33b6431b]9/* Returns the valid owl_io_dispatch for a given file descriptor. */
10static owl_io_dispatch *owl_select_find_valid_io_dispatch_by_fd(const int fd)
[df0138f]11{
12  int i, len;
13  const owl_list *dl;
14  owl_io_dispatch *d;
15  dl = owl_global_get_io_dispatch_list(&g);
16  len = owl_list_get_size(dl);
17  for(i = 0; i < len; i++) {
18    d = owl_list_get_element(dl, i);
[33b6431b]19    if (d->fd == fd && d->valid) return d;
[df0138f]20  }
21  return NULL;
22}
23
24static int owl_select_find_io_dispatch(const owl_io_dispatch *in)
25{
26  int i, len;
27  const owl_list *dl;
28
29  if (in != NULL) {
30    dl = owl_global_get_io_dispatch_list(&g);
31    len = owl_list_get_size(dl);
32    for(i = 0; i < len; i++) {
33      const owl_io_dispatch *d = owl_list_get_element(dl, i);
34      if (d == in) return i;
35    }
36  }
37  return -1;
38}
39
[33b6431b]40static void owl_select_invalidate_io_dispatch(owl_io_dispatch *d)
41{
42  if (d == NULL || !d->valid)
43    return;
44  d->valid = false;
45  g_source_remove_poll(owl_io_dispatch_source, &d->pollfd);
46}
47
[df0138f]48void owl_select_remove_io_dispatch(const owl_io_dispatch *in)
49{
50  int elt;
51  if (in != NULL) {
52    elt = owl_select_find_io_dispatch(in);
53    if (elt != -1) {
54      owl_list *dl = owl_global_get_io_dispatch_list(&g);
55      owl_io_dispatch *d = owl_list_get_element(dl, elt);
56      if (dispatch_active)
57        d->needs_gc = 1;
58      else {
[33b6431b]59        owl_select_invalidate_io_dispatch(d);
[df0138f]60        owl_list_remove_element(dl, elt);
61        if (d->destroy)
62          d->destroy(d);
[ddbbcffa]63        g_free(d);
[df0138f]64      }
65    }
66  }
67}
68
[ebb8498]69static void owl_select_io_dispatch_gc(void)
[df0138f]70{
71  int i;
72  owl_list *dl;
73
74  dl = owl_global_get_io_dispatch_list(&g);
75  /*
76   * Count down so we aren't set off by removing items from the list
77   * during the iteration.
78   */
79  for(i = owl_list_get_size(dl) - 1; i >= 0; i--) {
80    owl_io_dispatch *d = owl_list_get_element(dl, i);
81    if(d->needs_gc) {
82      owl_select_remove_io_dispatch(d);
83    }
84  }
85}
86
[33b6431b]87/* Each FD may have at most one valid dispatcher.
[df0138f]88 * If a new dispatch is added for an FD, the old one is removed.
89 * mode determines what types of events are watched for, and may be any combination of:
90 * OWL_IO_READ, OWL_IO_WRITE, OWL_IO_EXCEPT
91 */
92const 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)
93{
[96828e4]94  owl_io_dispatch *d = g_new(owl_io_dispatch, 1);
[df0138f]95  owl_list *dl = owl_global_get_io_dispatch_list(&g);
[33b6431b]96  owl_io_dispatch *other;
[df0138f]97
98  d->fd = fd;
[33b6431b]99  d->valid = true;
[df0138f]100  d->needs_gc = 0;
101  d->mode = mode;
102  d->callback = cb;
103  d->destroy = destroy;
104  d->data = data;
105
[2c79eae]106  /* TODO: Allow changing fd and mode in the middle? Probably don't care... */
107  d->pollfd.fd = fd;
108  d->pollfd.events = 0;
109  if (d->mode & OWL_IO_READ)
110    d->pollfd.events |= G_IO_IN | G_IO_HUP | G_IO_ERR;
111  if (d->mode & OWL_IO_WRITE)
112    d->pollfd.events |= G_IO_OUT | G_IO_ERR;
113  if (d->mode & OWL_IO_EXCEPT)
114    d->pollfd.events |= G_IO_PRI | G_IO_ERR;
115  g_source_add_poll(owl_io_dispatch_source, &d->pollfd);
116
117
[33b6431b]118  other = owl_select_find_valid_io_dispatch_by_fd(fd);
119  if (other)
120    owl_select_invalidate_io_dispatch(other);
[df0138f]121  owl_list_append_element(dl, d);
122
123  return d;
124}
125
[2c79eae]126static gboolean owl_io_dispatch_prepare(GSource *source, int *timeout) {
127  *timeout = -1;
128  return FALSE;
129}
[df0138f]130
[2c79eae]131static gboolean owl_io_dispatch_check(GSource *source) {
132  int i, len;
133  const owl_list *dl;
134
135  dl = owl_global_get_io_dispatch_list(&g);
[df0138f]136  len = owl_list_get_size(dl);
[2c79eae]137  for(i = 0; i < len; i++) {
[33b6431b]138    owl_io_dispatch *d = owl_list_get_element(dl, i);
139    if (!d->valid) continue;
140    if (d->pollfd.revents & G_IO_NVAL) {
141      owl_function_debugmsg("Pruning defunct dispatch on fd %d.", d->fd);
142      owl_select_invalidate_io_dispatch(d);
143    }
[2c79eae]144    if (d->pollfd.revents & d->pollfd.events)
145      return TRUE;
[df0138f]146  }
[2c79eae]147  return FALSE;
[df0138f]148}
149
[2c79eae]150static gboolean owl_io_dispatch_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) {
[df0138f]151  int i, len;
[2c79eae]152  const owl_list *dl;
[df0138f]153
154  dispatch_active = 1;
[2c79eae]155  dl = owl_global_get_io_dispatch_list(&g);
[df0138f]156  len = owl_list_get_size(dl);
157  for (i = 0; i < len; i++) {
[2c79eae]158    owl_io_dispatch *d = owl_list_get_element(dl, i);
[33b6431b]159    if (!d->valid) continue;
[2c79eae]160    if ((d->pollfd.revents & d->pollfd.events) && d->callback != NULL) {
[df0138f]161      d->callback(d, d->data);
162    }
163  }
164  dispatch_active = 0;
165  owl_select_io_dispatch_gc();
[2c79eae]166
167  return TRUE;
[df0138f]168}
169
[2c79eae]170static GSourceFuncs owl_io_dispatch_funcs = {
171  owl_io_dispatch_prepare,
172  owl_io_dispatch_check,
173  owl_io_dispatch_dispatch,
174  NULL
175};
176
[df0138f]177int owl_select_add_perl_io_dispatch(int fd, int mode, SV *cb)
178{
[33b6431b]179  const owl_io_dispatch *d = owl_select_find_valid_io_dispatch_by_fd(fd);
[df0138f]180  if (d != NULL && d->callback != owl_perlconfig_io_dispatch) {
181    /* Don't mess with non-perl dispatch functions from here. */
182    return 1;
183  }
[33b6431b]184  /* Also remove any invalidated perl dispatch functions that may have
185   * stuck around. */
186  owl_select_remove_perl_io_dispatch(fd);
[df0138f]187  owl_select_add_io_dispatch(fd, mode, owl_perlconfig_io_dispatch, owl_perlconfig_io_dispatch_destroy, cb);
188  return 0;
189}
190
[33b6431b]191static owl_io_dispatch *owl_select_find_perl_io_dispatch(int fd)
192{
193  int i, len;
194  const owl_list *dl;
195  owl_io_dispatch *d;
196  dl = owl_global_get_io_dispatch_list(&g);
197  len = owl_list_get_size(dl);
198  for(i = 0; i < len; i++) {
199    d = owl_list_get_element(dl, i);
200    if (d->fd == fd && d->callback == owl_perlconfig_io_dispatch)
201      return d;
202  }
203  return NULL;
204}
205
[df0138f]206int owl_select_remove_perl_io_dispatch(int fd)
207{
[33b6431b]208  owl_io_dispatch *d = owl_select_find_perl_io_dispatch(fd);
209  if (d != NULL) {
[df0138f]210    /* Only remove perl io dispatchers from here. */
211    owl_select_remove_io_dispatch(d);
212    return 0;
213  }
214  return 1;
215}
216
[2c79eae]217void owl_select_init(void)
[4f2166b]218{
[2c79eae]219  owl_io_dispatch_source = g_source_new(&owl_io_dispatch_funcs, sizeof(GSource));
220  g_source_attach(owl_io_dispatch_source, NULL);
[4f2166b]221}
222
[3ecd78b]223void owl_select_run_loop(void)
[4f2166b]224{
[44976fe]225  main_context = g_main_context_default();
226  loop = g_main_loop_new(main_context, FALSE);
[2c79eae]227  g_main_loop_run(loop);
[4f2166b]228}
229
[3ecd78b]230void owl_select_quit_loop(void)
[4f2166b]231{
[2c79eae]232  if (loop) {
233    g_main_loop_quit(loop);
234    loop = NULL;
[4f2166b]235  }
236}
237
[ba12b44]238typedef struct _owl_task { /*noproto*/
239  void (*cb)(void *);
240  void *cbdata;
241  void (*destroy_cbdata)(void *);
242} owl_task;
[3a84694]243
[ba12b44]244static gboolean _run_task(gpointer data)
245{
246  owl_task *t = data;
247  if (t->cb)
248    t->cb(t->cbdata);
249  return FALSE;
[9c7a701]250}
[3ecd78b]251
[ba12b44]252static void _destroy_task(void *data)
[3ecd78b]253{
[ba12b44]254  owl_task *t = data;
255  if (t->destroy_cbdata)
256    t->destroy_cbdata(t->cbdata);
257  g_free(t);
[3ecd78b]258}
259
[44976fe]260void owl_select_post_task(void (*cb)(void*), void *cbdata, void (*destroy_cbdata)(void*), GMainContext *context)
[3ecd78b]261{
[ba12b44]262  GSource *source = g_idle_source_new();
263  owl_task *t = g_new0(owl_task, 1);
264  t->cb = cb;
265  t->cbdata = cbdata;
266  t->destroy_cbdata = destroy_cbdata;
267  g_source_set_priority(source, G_PRIORITY_DEFAULT);
268  g_source_set_callback(source, _run_task, t, _destroy_task);
269  g_source_attach(source, context);
270  g_source_unref(source);
[3ecd78b]271}
Note: See TracBrowser for help on using the repository browser.