source: select.c @ b310c0e

owl
Last change on this file since b310c0e was b310c0e, checked in by James M. Kretchmar <kretch@mit.edu>, 15 years ago
add select.c to the repository
  • Property mode set to 100644
File size: 6.8 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    d_old = (owl_dispatch*)owl_list_get_element(dl, elt);
79    /* Ignore if we're adding the same dispatch again.  Otherwise
80       replace the old dispatch. */
81    if (d_old != d) {
82      owl_select_remove_dispatch_at(elt);
83    }
84  }
85  owl_list_append_element(dl, d);
86}
87
88/* Removes an owl_dispatch to the list, based on it's file descriptor. */
89void owl_select_remove_dispatch(int fd)
90{
91  int elt;
92  owl_list *dl;
93  owl_dispatch *d;
94
95  elt = owl_select_find_dispatch(fd);
96  if(elt == -1) {
97    return;
98  } else if(dispatch_active) {
99    /* Defer the removal until dispatch is done walking the list */
100    dl = owl_global_get_dispatchlist(&g);
101    d = (owl_dispatch*)owl_list_get_element(dl, elt);
102    d->needs_gc = 1;
103  } else {
104    owl_select_remove_dispatch_at(elt);
105  }
106}
107
108int owl_select_dispatch_count()
109{
110  return owl_list_get_size(owl_global_get_dispatchlist(&g));
111}
112
113int owl_select_dispatch_prepare_fd_sets(fd_set *r, fd_set *e)
114{
115  int i, len, max_fd;
116  owl_dispatch *d;
117  owl_list *dl;
118
119  dl = owl_global_get_dispatchlist(&g);
120  FD_ZERO(r);
121  FD_ZERO(e);
122  max_fd = 0;
123  len = owl_select_dispatch_count(g);
124  for(i = 0; i < len; i++) {
125    d = (owl_dispatch*)owl_list_get_element(dl, i);
126    FD_SET(d->fd, r);
127    FD_SET(d->fd, e);
128    if (max_fd < d->fd) max_fd = d->fd;
129  }
130  return max_fd + 1;
131}
132
133void owl_select_gc()
134{
135  int i;
136  owl_list *dl;
137
138  dl = owl_global_get_dispatchlist(&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_dispatch *d = owl_list_get_element(dl, i);
145    if(d->needs_gc) {
146      owl_select_remove_dispatch_at(i);
147    }
148  }
149}
150
151void owl_select_dispatch(fd_set *fds, int max_fd)
152{
153  int i, len;
154  owl_dispatch *d;
155  owl_list *dl;
156
157  dl = owl_global_get_dispatchlist(&g);
158  len = owl_select_dispatch_count();
159
160  dispatch_active = 1;
161
162  for(i = 0; i < len; i++) {
163    d = (owl_dispatch*)owl_list_get_element(dl, i);
164    /* While d shouldn't normally be null, the list may be altered by
165     * functions we dispatch to. */
166    if (d != NULL && !d->needs_gc && FD_ISSET(d->fd, fds)) {
167      if (d->cfunc != NULL) {
168        d->cfunc(d);
169      }
170    }
171  }
172
173  dispatch_active = 0;
174  owl_select_gc();
175}
176
177int owl_select_aim_hack(fd_set *rfds, fd_set *wfds)
178{
179  aim_conn_t *cur;
180  aim_session_t *sess;
181  int max_fd;
182
183  FD_ZERO(rfds);
184  FD_ZERO(wfds);
185  max_fd = 0;
186  sess = owl_global_get_aimsess(&g);
187  for (cur = sess->connlist, max_fd = 0; cur; cur = cur->next) {
188    if (cur->fd != -1) {
189      FD_SET(cur->fd, rfds);
190      if (cur->status & AIM_CONN_STATUS_INPROGRESS) {
191        /* Yes, we're checking writable sockets here. Without it, AIM
192           login is really slow. */
193        FD_SET(cur->fd, wfds);
194      }
195     
196      if (cur->fd > max_fd)
197        max_fd = cur->fd;
198    }
199  }
200  return max_fd;
201}
202
203void owl_select()
204{
205  int i, max_fd, aim_max_fd, aim_done;
206  fd_set r;
207  fd_set e;
208  fd_set aim_rfds, aim_wfds;
209  struct timeval timeout;
210
211  /* owl_select_process_timers(&timeout); */
212  timeout.tv_sec = 60;
213  timeout.tv_usec = 0;
214
215  max_fd = owl_select_dispatch_prepare_fd_sets(&r, &e);
216
217  /* AIM HACK:
218   *
219   *  The problem - I'm not sure where to hook into the owl/faim
220   *  interface to keep track of when the AIM socket(s) open and
221   *  close. In particular, the bosconn thing throws me off. So,
222   *  rather than register particular dispatchers for AIM, I look up
223   *  the relevant FDs and add them to select's watch lists, then
224   *  check for them individually before moving on to the other
225   *  dispatchers. --asedeno
226   */
227  aim_done = 1;
228  FD_ZERO(&aim_rfds);
229  FD_ZERO(&aim_wfds);
230  if (owl_global_is_doaimevents(&g)) {
231    aim_done = 0;
232    aim_max_fd = owl_select_aim_hack(&aim_rfds, &aim_wfds);
233    if (max_fd < aim_max_fd) max_fd = aim_max_fd;
234    for(i = 0; i <= aim_max_fd; i++) {
235      if (FD_ISSET(i, &aim_rfds)) {
236        FD_SET(i, &r);
237        FD_SET(i, &e);
238      }
239    }
240  }
241  /* END AIM HACK */
242
243  if ( select(max_fd+1, &r, &aim_wfds, &e, &timeout) ) {
244    /* Merge fd_sets and clear AIM FDs. */
245    for(i = 0; i <= max_fd; i++) {
246      /* Merge all interesting FDs into one set, since we have a
247         single dispatch per FD. */
248      if (FD_ISSET(i, &r) || FD_ISSET(i, &aim_wfds) || FD_ISSET(i, &e)) {
249        /* AIM HACK: no separate dispatch, just process here if
250           needed, and only once per run through. */
251        if (!aim_done && (FD_ISSET(i, &aim_rfds) || FD_ISSET(i, &aim_wfds))) {
252          owl_process_aim();
253          aim_done = 1;
254        }
255        else {
256          FD_SET(i, &r);
257        }
258      }
259    }
260    /* NOTE: the same dispatch function is called for both exceptional
261       and read ready FDs. */
262    owl_select_dispatch(&r, max_fd);
263  }
264}
Note: See TracBrowser for help on using the repository browser.