source: select.c @ 8d0796c0

owl
Last change on this file since 8d0796c0 was c2bcd54, checked in by James M. Kretchmar <kretch@mit.edu>, 13 years ago
debug message in the wrong place
  • Property mode set to 100644
File size: 7.0 KB
Line 
1/* Copyright (c) 2002,2003,2004,2009 James M. Kretchmar
2 *
3 * This file is part of Owl.
4 *
5 * Owl is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * Owl is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with Owl.  If not, see <http://www.gnu.org/licenses/>.
17 *
18 * ---------------------------------------------------------------
19 *
20 * As of Owl version 2.1.12 there are patches contributed by
21 * developers of the branched BarnOwl project, Copyright (c)
22 * 2006-2009 The BarnOwl Developers. All rights reserved.
23 */
24
25/* This select loop implementation was contributed by developers of
26 * the branched BarnOwl project.
27 */
28 
29#include "owl.h"
30
31static const char fileIdent[] = "$Id $";
32
33static int dispatch_active = 0;
34
35/* Returns the index of the dispatch for the file descriptor. */
36int owl_select_find_dispatch(int fd)
37{
38  int i, len;
39  owl_list *dl;
40  owl_dispatch *d;
41
42  dl = owl_global_get_dispatchlist(&g);
43  len = owl_list_get_size(dl);
44  owl_function_debugmsg("test: len is %i", len);
45  for(i = 0; i < len; i++) {
46    d = (owl_dispatch*)owl_list_get_element(dl, i);
47    if (d->fd == fd) return i;
48  }
49  return -1;
50}
51
52void owl_select_remove_dispatch_at(int elt) /* noproto */
53{
54  owl_list *dl;
55  owl_dispatch *d;
56
57  dl = owl_global_get_dispatchlist(&g);
58  d = (owl_dispatch*)owl_list_get_element(dl, elt);
59  owl_list_remove_element(dl, elt);
60  if (d->destroy) {
61    d->destroy(d);
62  }
63}
64
65/* Adds a new owl_dispatch to the list, replacing existing ones if needed. */
66void owl_select_add_dispatch(owl_dispatch *d)
67{
68  int elt;
69  owl_list *dl;
70
71  d->needs_gc = 0;
72
73  elt = owl_select_find_dispatch(d->fd);
74  dl = owl_global_get_dispatchlist(&g);
75
76  if (elt != -1) {  /* If we have a dispatch for this FD */
77    owl_dispatch *d_old;
78    owl_function_debugmsg("select: duplicate dispatch found");
79    d_old = (owl_dispatch*)owl_list_get_element(dl, elt);
80    /* Ignore if we're adding the same dispatch again.  Otherwise
81       replace the old dispatch. */
82    if (d_old != d) {
83      owl_select_remove_dispatch_at(elt);
84    }
85  }
86  owl_list_append_element(dl, d);
87}
88
89/* Removes an owl_dispatch to the list, based on it's file descriptor. */
90void owl_select_remove_dispatch(int fd)
91{
92  int elt;
93  owl_list *dl;
94  owl_dispatch *d;
95
96  elt = owl_select_find_dispatch(fd);
97  if(elt == -1) {
98    return;
99  } else if(dispatch_active) {
100    /* Defer the removal until dispatch is done walking the list */
101    dl = owl_global_get_dispatchlist(&g);
102    d = (owl_dispatch*)owl_list_get_element(dl, elt);
103    d->needs_gc = 1;
104  } else {
105    owl_select_remove_dispatch_at(elt);
106  }
107}
108
109int owl_select_dispatch_count()
110{
111  return owl_list_get_size(owl_global_get_dispatchlist(&g));
112}
113
114int owl_select_dispatch_prepare_fd_sets(fd_set *r, fd_set *e)
115{
116  int i, len, max_fd;
117  owl_dispatch *d;
118  owl_list *dl;
119
120  dl = owl_global_get_dispatchlist(&g);
121  FD_ZERO(r);
122  FD_ZERO(e);
123  max_fd = 0;
124  len = owl_select_dispatch_count(g);
125  for(i = 0; i < len; i++) {
126    d = (owl_dispatch*)owl_list_get_element(dl, i);
127    FD_SET(d->fd, r);
128    FD_SET(d->fd, e);
129    if (max_fd < d->fd) max_fd = d->fd;
130  }
131  return max_fd + 1;
132}
133
134void owl_select_gc()
135{
136  int i;
137  owl_list *dl;
138
139  dl = owl_global_get_dispatchlist(&g);
140  /*
141   * Count down so we aren't set off by removing items from the list
142   * during the iteration.
143   */
144  for(i = owl_list_get_size(dl) - 1; i >= 0; i--) {
145    owl_dispatch *d = owl_list_get_element(dl, i);
146    if(d->needs_gc) {
147      owl_select_remove_dispatch_at(i);
148    }
149  }
150}
151
152void owl_select_dispatch(fd_set *fds, int max_fd)
153{
154  int i, len;
155  owl_dispatch *d;
156  owl_list *dl;
157
158  dl = owl_global_get_dispatchlist(&g);
159  len = owl_select_dispatch_count();
160
161  dispatch_active = 1;
162
163  for(i = 0; i < len; i++) {
164    d = (owl_dispatch*)owl_list_get_element(dl, i);
165    /* While d shouldn't normally be null, the list may be altered by
166     * functions we dispatch to. */
167    if (d != NULL && !d->needs_gc && FD_ISSET(d->fd, fds)) {
168      if (d->cfunc != NULL) {
169        d->cfunc(d);
170      }
171    }
172  }
173
174  dispatch_active = 0;
175  owl_select_gc();
176}
177
178int owl_select_aim_hack(fd_set *rfds, fd_set *wfds)
179{
180  aim_conn_t *cur;
181  aim_session_t *sess;
182  int max_fd;
183
184  FD_ZERO(rfds);
185  FD_ZERO(wfds);
186  max_fd = 0;
187  sess = owl_global_get_aimsess(&g);
188  for (cur = sess->connlist, max_fd = 0; cur; cur = cur->next) {
189    if (cur->fd != -1) {
190      FD_SET(cur->fd, rfds);
191      if (cur->status & AIM_CONN_STATUS_INPROGRESS) {
192        /* Yes, we're checking writable sockets here. Without it, AIM
193           login is really slow. */
194        FD_SET(cur->fd, wfds);
195      }
196     
197      if (cur->fd > max_fd)
198        max_fd = cur->fd;
199    }
200  }
201  return max_fd;
202}
203
204void owl_select()
205{
206  int i, max_fd, aim_max_fd, aim_done;
207  fd_set r;
208  fd_set e;
209  fd_set aim_rfds, aim_wfds;
210  struct timeval timeout;
211
212  /* owl_select_process_timers(&timeout); */
213
214  /* settings to 5 seconds for the moment, we can raise this when the
215   * odd select behavior with zephyr is understood
216   */
217  timeout.tv_sec = 5;
218  timeout.tv_usec = 0;
219
220  max_fd = owl_select_dispatch_prepare_fd_sets(&r, &e);
221
222  /* AIM HACK:
223   *
224   *  The problem - I'm not sure where to hook into the owl/faim
225   *  interface to keep track of when the AIM socket(s) open and
226   *  close. In particular, the bosconn thing throws me off. So,
227   *  rather than register particular dispatchers for AIM, I look up
228   *  the relevant FDs and add them to select's watch lists, then
229   *  check for them individually before moving on to the other
230   *  dispatchers. --asedeno
231   */
232  aim_done = 1;
233  FD_ZERO(&aim_rfds);
234  FD_ZERO(&aim_wfds);
235  if (owl_global_is_doaimevents(&g)) {
236    aim_done = 0;
237    aim_max_fd = owl_select_aim_hack(&aim_rfds, &aim_wfds);
238    if (max_fd < aim_max_fd) max_fd = aim_max_fd;
239    for(i = 0; i <= aim_max_fd; i++) {
240      if (FD_ISSET(i, &aim_rfds)) {
241        FD_SET(i, &r);
242        FD_SET(i, &e);
243      }
244    }
245  }
246  /* END AIM HACK */
247
248  if ( select(max_fd+1, &r, &aim_wfds, &e, &timeout) ) {
249    /* Merge fd_sets and clear AIM FDs. */
250    for(i = 0; i <= max_fd; i++) {
251      /* Merge all interesting FDs into one set, since we have a
252         single dispatch per FD. */
253      if (FD_ISSET(i, &r) || FD_ISSET(i, &aim_wfds) || FD_ISSET(i, &e)) {
254        /* AIM HACK: no separate dispatch, just process here if
255           needed, and only once per run through. */
256        if (!aim_done && (FD_ISSET(i, &aim_rfds) || FD_ISSET(i, &aim_wfds))) {
257          owl_process_aim();
258          aim_done = 1;
259        }
260        else {
261          FD_SET(i, &r);
262        }
263      }
264    }
265    /* NOTE: the same dispatch function is called for both exceptional
266       and read ready FDs. */
267    owl_select_dispatch(&r, max_fd);
268  }
269}
Note: See TracBrowser for help on using the repository browser.