source: select.c @ f81176c

release-1.10release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since f81176c was 7ca5d3e, checked in by Alejandro R. Sedeño <asedeno@mit.edu>, 15 years ago
Remove obsolete dispatch simplifications This should have been part of the I/O Dispatch API changeset that was just merged, had I noticed it when ripping out the old API. Signed-off-by: Alejandro R. Sedeño <asedeno@mit.edu>
  • Property mode set to 100644
File size: 11.9 KB
Line 
1#include "owl.h"
2
3static int dispatch_active = 0;
4static int psa_active = 0;
5
6int _owl_select_timer_cmp(const owl_timer *t1, const owl_timer *t2) {
7  return t1->time - t2->time;
8}
9
10int _owl_select_timer_eq(const owl_timer *t1, const owl_timer *t2) {
11  return t1 == t2;
12}
13
14owl_timer *owl_select_add_timer(int after, int interval, void (*cb)(owl_timer *, void *), void (*destroy)(owl_timer*), void *data)
15{
16  owl_timer *t = owl_malloc(sizeof(owl_timer));
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
25  *timers = g_list_insert_sorted(*timers, t,
26                                 (GCompareFunc)_owl_select_timer_cmp);
27  return t;
28}
29
30void owl_select_remove_timer(owl_timer *t)
31{
32  GList **timers = owl_global_get_timerlist(&g);
33  if (t && g_list_find(*timers, t)) {
34    *timers = g_list_remove(*timers, t);
35    if(t->destroy) {
36      t->destroy(t);
37    }
38    owl_free(t);
39  }
40}
41
42void owl_select_process_timers(struct timespec *timeout)
43{
44  time_t now = time(NULL);
45  GList **timers = owl_global_get_timerlist(&g);
46
47  while(*timers) {
48    owl_timer *t = (*timers)->data;
49    int remove = 0;
50
51    if(t->time > now)
52      break;
53
54    /* Reschedule if appropriate */
55    if(t->interval > 0) {
56      t->time = now + t->interval;
57      *timers = g_list_remove(*timers, t);
58      *timers = g_list_insert_sorted(*timers, t,
59                                     (GCompareFunc)_owl_select_timer_cmp);
60    } else {
61      remove = 1;
62    }
63
64    /* Do the callback */
65    t->callback(t, t->data);
66    if(remove) {
67      owl_select_remove_timer(t);
68    }
69  }
70
71  if(*timers) {
72    owl_timer *t = (*timers)->data;
73    timeout->tv_sec = t->time - now;
74    if (timeout->tv_sec > 60)
75      timeout->tv_sec = 60;
76  } else {
77    timeout->tv_sec = 60;
78  }
79
80  timeout->tv_nsec = 0;
81}
82
83static const owl_io_dispatch *owl_select_find_io_dispatch_by_fd(const int fd)
84{
85  int i, len;
86  const owl_list *dl;
87  owl_io_dispatch *d;
88  dl = owl_global_get_io_dispatch_list(&g);
89  len = owl_list_get_size(dl);
90  for(i = 0; i < len; i++) {
91    d = owl_list_get_element(dl, i);
92    if (d->fd == fd) return d;
93  }
94  return NULL;
95}
96
97static int owl_select_find_io_dispatch(const owl_io_dispatch *in)
98{
99  int i, len;
100  const owl_list *dl;
101
102  if (in != NULL) {
103    dl = owl_global_get_io_dispatch_list(&g);
104    len = owl_list_get_size(dl);
105    for(i = 0; i < len; i++) {
106      const owl_io_dispatch *d = owl_list_get_element(dl, i);
107      if (d == in) return i;
108    }
109  }
110  return -1;
111}
112
113void owl_select_remove_io_dispatch(const owl_io_dispatch *in)
114{
115  int elt;
116  if (in != NULL) {
117    elt = owl_select_find_io_dispatch(in);
118    if (elt != -1) {
119      owl_list *dl = owl_global_get_io_dispatch_list(&g);
120      owl_io_dispatch *d = owl_list_get_element(dl, elt);
121      if (dispatch_active)
122        d->needs_gc = 1;
123      else {
124        owl_list_remove_element(dl, elt);
125        if (d->destroy)
126          d->destroy(d);
127        owl_free(d);
128      }
129    }
130  }
131}
132
133void owl_select_io_dispatch_gc(void)
134{
135  int i;
136  owl_list *dl;
137
138  dl = owl_global_get_io_dispatch_list(&g);
139  /*
140   * Count down so we aren't set off by removing items from the list
141   * during the iteration.
142   */
143  for(i = owl_list_get_size(dl) - 1; i >= 0; i--) {
144    owl_io_dispatch *d = owl_list_get_element(dl, i);
145    if(d->needs_gc) {
146      owl_select_remove_io_dispatch(d);
147    }
148  }
149}
150
151/* Each FD may have at most one dispatcher.
152 * If a new dispatch is added for an FD, the old one is removed.
153 * mode determines what types of events are watched for, and may be any combination of:
154 * OWL_IO_READ, OWL_IO_WRITE, OWL_IO_EXCEPT
155 */
156const 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)
157{
158  owl_io_dispatch *d = owl_malloc(sizeof(owl_io_dispatch));
159  owl_list *dl = owl_global_get_io_dispatch_list(&g);
160
161  d->fd = fd;
162  d->needs_gc = 0;
163  d->mode = mode;
164  d->callback = cb;
165  d->destroy = destroy;
166  d->data = data;
167
168  owl_select_remove_io_dispatch(owl_select_find_io_dispatch_by_fd(fd));
169  owl_list_append_element(dl, d);
170
171  return d;
172}
173
174int owl_select_prepare_io_dispatch_fd_sets(fd_set *rfds, fd_set *wfds, fd_set *efds) {
175  int i, len, max_fd;
176  owl_io_dispatch *d;
177  owl_list *dl = owl_global_get_io_dispatch_list(&g);
178
179  max_fd = 0;
180  len = owl_list_get_size(dl);
181  for (i = 0; i < len; i++) {
182    d = owl_list_get_element(dl, i);
183    if (d->mode & (OWL_IO_READ | OWL_IO_WRITE | OWL_IO_EXCEPT)) {
184      if (max_fd < d->fd) max_fd = d->fd;
185      if (d->mode & OWL_IO_READ) FD_SET(d->fd, rfds);
186      if (d->mode & OWL_IO_WRITE) FD_SET(d->fd, wfds);
187      if (d->mode & OWL_IO_EXCEPT) FD_SET(d->fd, efds);
188    }
189  }
190  return max_fd + 1;
191}
192
193void owl_select_io_dispatch(const fd_set *rfds, const fd_set *wfds, const fd_set *efds, const int max_fd)
194{
195  int i, len;
196  owl_io_dispatch *d;
197  owl_list *dl = owl_global_get_io_dispatch_list(&g);
198
199  dispatch_active = 1;
200  len = owl_list_get_size(dl);
201  for (i = 0; i < len; i++) {
202    d = owl_list_get_element(dl, i);
203    if (d->fd < max_fd && d->callback != NULL &&
204        ((d->mode & OWL_IO_READ && FD_ISSET(d->fd, rfds)) ||
205         (d->mode & OWL_IO_WRITE && FD_ISSET(d->fd, wfds)) ||
206         (d->mode & OWL_IO_EXCEPT && FD_ISSET(d->fd, efds)))) {
207      d->callback(d, d->data);
208    }
209  }
210  dispatch_active = 0;
211  owl_select_io_dispatch_gc();
212}
213
214int owl_select_add_perl_io_dispatch(int fd, int mode, SV *cb)
215{
216  const owl_io_dispatch *d = owl_select_find_io_dispatch_by_fd(fd);
217  if (d != NULL && d->callback != owl_perlconfig_io_dispatch) {
218    /* Don't mess with non-perl dispatch functions from here. */
219    return 1;
220  }
221  owl_select_add_io_dispatch(fd, mode, owl_perlconfig_io_dispatch, owl_perlconfig_io_dispatch_destroy, cb);
222  return 0;
223}
224
225int owl_select_remove_perl_io_dispatch(int fd)
226{
227  const owl_io_dispatch *d = owl_select_find_io_dispatch_by_fd(fd);
228  if (d != NULL && d->callback == owl_perlconfig_io_dispatch) {
229    /* Only remove perl io dispatchers from here. */
230    owl_select_remove_io_dispatch(d);
231    return 0;
232  }
233  return 1;
234}
235
236int owl_select_aim_hack(fd_set *rfds, fd_set *wfds)
237{
238  aim_conn_t *cur;
239  aim_session_t *sess;
240  int max_fd;
241
242  max_fd = 0;
243  sess = owl_global_get_aimsess(&g);
244  for (cur = sess->connlist, max_fd = 0; cur; cur = cur->next) {
245    if (cur->fd != -1) {
246      FD_SET(cur->fd, rfds);
247      if (cur->status & AIM_CONN_STATUS_INPROGRESS) {
248        /* Yes, we're checking writable sockets here. Without it, AIM
249           login is really slow. */
250        FD_SET(cur->fd, wfds);
251      }
252     
253      if (cur->fd > max_fd)
254        max_fd = cur->fd;
255    }
256  }
257  return max_fd;
258}
259
260void owl_process_input_char(owl_input j)
261{
262  int ret;
263  owl_popwin *pw;
264  owl_editwin *tw;
265
266  owl_global_set_lastinputtime(&g, time(NULL));
267  pw=owl_global_get_popwin(&g);
268  tw=owl_global_get_typwin(&g);
269
270  owl_global_set_lastinputtime(&g, time(NULL));
271  /* find and activate the current keymap.
272   * TODO: this should really get fixed by activating
273   * keymaps as we switch between windows...
274   */
275  if (pw && owl_popwin_is_active(pw) && owl_global_get_viewwin(&g)) {
276    owl_context_set_popless(owl_global_get_context(&g), 
277                            owl_global_get_viewwin(&g));
278    owl_function_activate_keymap("popless");
279  } else if (owl_global_is_typwin_active(&g) 
280             && owl_editwin_get_style(tw)==OWL_EDITWIN_STYLE_ONELINE) {
281    /*
282      owl_context_set_editline(owl_global_get_context(&g), tw);
283      owl_function_activate_keymap("editline");
284    */
285  } else if (owl_global_is_typwin_active(&g) 
286             && owl_editwin_get_style(tw)==OWL_EDITWIN_STYLE_MULTILINE) {
287    owl_context_set_editmulti(owl_global_get_context(&g), tw);
288    owl_function_activate_keymap("editmulti");
289  } else {
290    owl_context_set_recv(owl_global_get_context(&g));
291    owl_function_activate_keymap("recv");
292  }
293  /* now actually handle the keypress */
294  ret = owl_keyhandler_process(owl_global_get_keyhandler(&g), j);
295  if (ret!=0 && ret!=1) {
296    owl_function_makemsg("Unable to handle keypress");
297  }
298}
299
300void owl_select_mask_signals(sigset_t *oldmask) {
301  sigset_t set;
302
303  sigemptyset(&set);
304  sigaddset(&set, SIGINT);
305  sigaddset(&set, SIGTSTP);
306  sigprocmask(SIG_BLOCK, &set, oldmask);
307}
308
309void owl_select_handle_intr(sigset_t *restore)
310{
311  owl_input in;
312
313  owl_global_unset_interrupted(&g);
314
315  sigprocmask(SIG_SETMASK, restore, NULL);
316
317  in.ch = in.uch = owl_global_get_startup_tio(&g)->c_cc[VINTR];
318  owl_process_input_char(in);
319}
320
321void owl_select_check_tstp(void) {
322  if(owl_global_is_sigstp(&g)) {
323    owl_function_makemsg("Use :suspend to suspend.");
324    owl_global_unset_got_sigstp(&g);
325  }
326}
327
328owl_ps_action *owl_select_add_pre_select_action(int (*cb)(owl_ps_action *, void *), void (*destroy)(owl_ps_action *), void *data)
329{
330  owl_ps_action *a = owl_malloc(sizeof(owl_ps_action));
331  owl_list *psa_list = owl_global_get_psa_list(&g);
332  a->needs_gc = 0;
333  a->callback = cb;
334  a->destroy = destroy;
335  a->data = data;
336  owl_list_append_element(psa_list, a);
337  return a;
338}
339
340void owl_select_psa_gc(void)
341{
342  int i;
343  owl_list *psa_list;
344  owl_ps_action *a;
345
346  psa_list = owl_global_get_psa_list(&g);
347  for (i = owl_list_get_size(psa_list) - 1; i >= 0; i--) {
348    a = owl_list_get_element(psa_list, i);
349    if (a->needs_gc) {
350      owl_list_remove_element(psa_list, i);
351      if (a->destroy) {
352        a->destroy(a);
353      }
354      owl_free(a);
355    }
356  }
357}
358
359void owl_select_remove_pre_select_action(owl_ps_action *a)
360{
361  a->needs_gc = 1;
362  if (!psa_active)
363    owl_select_psa_gc();
364}
365
366int owl_select_do_pre_select_actions(void)
367{
368  int i, len, ret;
369  owl_list *psa_list;
370
371  psa_active = 1;
372  ret = 0;
373  psa_list = owl_global_get_psa_list(&g);
374  len = owl_list_get_size(psa_list);
375  for (i = 0; i < len; i++) {
376    owl_ps_action *a = owl_list_get_element(psa_list, i);
377    if (a->callback != NULL && a->callback(a, a->data)) {
378      ret = 1;
379    }
380  }
381  psa_active = 0;
382  owl_select_psa_gc();
383  return ret;
384}
385
386void owl_select(void)
387{
388  int i, max_fd, max_fd2, aim_done, ret;
389  fd_set r;
390  fd_set w;
391  fd_set e;
392  fd_set aim_rfds, aim_wfds;
393  struct timespec timeout;
394  sigset_t mask;
395
396  owl_select_process_timers(&timeout);
397
398  owl_select_mask_signals(&mask);
399
400  owl_select_check_tstp();
401  if(owl_global_is_interrupted(&g)) {
402    owl_select_handle_intr(&mask);
403    return;
404  }
405  FD_ZERO(&r);
406  FD_ZERO(&w);
407  FD_ZERO(&e);
408
409  max_fd = owl_select_prepare_io_dispatch_fd_sets(&r, &w, &e);
410
411  /* AIM HACK:
412   *
413   *  The problem - I'm not sure where to hook into the owl/faim
414   *  interface to keep track of when the AIM socket(s) open and
415   *  close. In particular, the bosconn thing throws me off. So,
416   *  rather than register particular dispatchers for AIM, I look up
417   *  the relevant FDs and add them to select's watch lists, then
418   *  check for them individually before moving on to the other
419   *  dispatchers. --asedeno
420   */
421  aim_done = 1;
422  FD_ZERO(&aim_rfds);
423  FD_ZERO(&aim_wfds);
424  if (owl_global_is_doaimevents(&g)) {
425    aim_done = 0;
426    max_fd2 = owl_select_aim_hack(&aim_rfds, &aim_wfds);
427    if (max_fd < max_fd2) max_fd = max_fd2;
428    for(i = 0; i <= max_fd2; i++) {
429      if (FD_ISSET(i, &aim_rfds)) {
430        FD_SET(i, &r);
431        FD_SET(i, &e);
432      }
433      if (FD_ISSET(i, &aim_wfds)) {
434        FD_SET(i, &w);
435        FD_SET(i, &e);
436      }
437    }
438  }
439  /* END AIM HACK */
440
441  if (owl_select_do_pre_select_actions()) {
442    timeout.tv_sec = 0;
443    timeout.tv_nsec = 0;
444  }
445
446  ret = pselect(max_fd+1, &r, &w, &e, &timeout, &mask);
447
448  if(ret < 0 && errno == EINTR) {
449    owl_select_check_tstp();
450    if(owl_global_is_interrupted(&g)) {
451      owl_select_handle_intr(NULL);
452    }
453    sigprocmask(SIG_SETMASK, &mask, NULL);
454    return;
455  }
456
457  sigprocmask(SIG_SETMASK, &mask, NULL);
458
459  if(ret > 0) {
460    /* AIM HACK: process all AIM events at once. */
461    for(i = 0; !aim_done && i <= max_fd; i++) {
462      if (FD_ISSET(i, &r) || FD_ISSET(i, &w) || FD_ISSET(i, &e)) {
463        if (FD_ISSET(i, &aim_rfds) || FD_ISSET(i, &aim_wfds)) {
464          owl_process_aim();
465          aim_done = 1;
466        }
467      }
468    }
469    owl_select_io_dispatch(&r, &w, &e, max_fd);
470  }
471}
Note: See TracBrowser for help on using the repository browser.