Changes in select.c [d4927a7:f0781ba]
Legend:
- Unmodified
- Added
- Removed
-
select.c
rd4927a7 rf0781ba 1 1 #include "owl.h" 2 2 3 static GMainLoop *loop = NULL; 4 static GMainContext *main_context; 3 5 static int dispatch_active = 0; 4 static int psa_active = 0; 5 static int loop_active = 0; 6 7 int _owl_select_timer_cmp(const owl_timer *t1, const owl_timer *t2) { 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) { 8 11 return t1->time - t2->time; 9 }10 11 int _owl_select_timer_eq(const owl_timer *t1, const owl_timer *t2) {12 return t1 == t2;13 12 } 14 13 … … 43 42 } 44 43 45 void owl_select_process_timers(struct timespec *timeout) 46 { 47 time_t now = time(NULL); 48 GList **timers = owl_global_get_timerlist(&g); 49 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? */ 50 94 while(*timers) { 51 95 owl_timer *t = (*timers)->data; 52 96 int remove = 0; 53 97 54 if(t->time > now )98 if(t->time > now.tv_sec) 55 99 break; 56 100 57 101 /* Reschedule if appropriate */ 58 102 if(t->interval > 0) { 59 t->time = now + t->interval;103 t->time = now.tv_sec + t->interval; 60 104 *timers = g_list_remove(*timers, t); 61 105 *timers = g_list_insert_sorted(*timers, t, … … 71 115 } 72 116 } 73 74 if(*timers) { 75 owl_timer *t = (*timers)->data; 76 timeout->tv_sec = t->time - now; 77 if (timeout->tv_sec > 60) 78 timeout->tv_sec = 60; 79 } else { 80 timeout->tv_sec = 60; 81 } 82 83 timeout->tv_nsec = 0; 84 } 85 86 static const owl_io_dispatch *owl_select_find_io_dispatch_by_fd(const int fd) 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) 87 129 { 88 130 int i, len; … … 93 135 for(i = 0; i < len; i++) { 94 136 d = owl_list_get_element(dl, i); 95 if (d->fd == fd ) return d;137 if (d->fd == fd && d->valid) return d; 96 138 } 97 139 return NULL; … … 112 154 } 113 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); 114 164 } 115 165 … … 125 175 d->needs_gc = 1; 126 176 else { 177 owl_select_invalidate_io_dispatch(d); 127 178 owl_list_remove_element(dl, elt); 128 179 if (d->destroy) … … 134 185 } 135 186 136 void owl_select_io_dispatch_gc(void)187 static void owl_select_io_dispatch_gc(void) 137 188 { 138 189 int i; … … 152 203 } 153 204 154 /* Each FD may have at most one dispatcher.205 /* Each FD may have at most one valid dispatcher. 155 206 * If a new dispatch is added for an FD, the old one is removed. 156 207 * mode determines what types of events are watched for, and may be any combination of: … … 161 212 owl_io_dispatch *d = g_new(owl_io_dispatch, 1); 162 213 owl_list *dl = owl_global_get_io_dispatch_list(&g); 214 owl_io_dispatch *other; 163 215 164 216 d->fd = fd; 217 d->valid = true; 165 218 d->needs_gc = 0; 166 219 d->mode = mode; … … 169 222 d->data = data; 170 223 171 owl_select_remove_io_dispatch(owl_select_find_io_dispatch_by_fd(fd)); 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); 172 239 owl_list_append_element(dl, d); 173 240 … … 175 242 } 176 243 177 int owl_select_prepare_io_dispatch_fd_sets(fd_set *rfds, fd_set *wfds, fd_set *efds) { 178 int i, len, max_fd; 179 owl_io_dispatch *d; 180 owl_list *dl = owl_global_get_io_dispatch_list(&g); 181 182 max_fd = 0; 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); 183 274 len = owl_list_get_size(dl); 184 275 for (i = 0; i < len; i++) { 185 d = owl_list_get_element(dl, i); 186 if (d->mode & (OWL_IO_READ | OWL_IO_WRITE | OWL_IO_EXCEPT)) { 187 if (max_fd < d->fd) max_fd = d->fd; 188 if (d->mode & OWL_IO_READ) FD_SET(d->fd, rfds); 189 if (d->mode & OWL_IO_WRITE) FD_SET(d->fd, wfds); 190 if (d->mode & OWL_IO_EXCEPT) FD_SET(d->fd, efds); 191 } 192 } 193 return max_fd + 1; 194 } 195 196 void owl_select_io_dispatch(const fd_set *rfds, const fd_set *wfds, const fd_set *efds, const int max_fd) 197 { 198 int i, len; 199 owl_io_dispatch *d; 200 owl_list *dl = owl_global_get_io_dispatch_list(&g); 201 202 dispatch_active = 1; 203 len = owl_list_get_size(dl); 204 for (i = 0; i < len; i++) { 205 d = owl_list_get_element(dl, i); 206 if (d->fd < max_fd && d->callback != NULL && 207 ((d->mode & OWL_IO_READ && FD_ISSET(d->fd, rfds)) || 208 (d->mode & OWL_IO_WRITE && FD_ISSET(d->fd, wfds)) || 209 (d->mode & OWL_IO_EXCEPT && FD_ISSET(d->fd, efds)))) { 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) { 210 279 d->callback(d, d->data); 211 280 } … … 213 282 dispatch_active = 0; 214 283 owl_select_io_dispatch_gc(); 215 } 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 }; 216 294 217 295 int owl_select_add_perl_io_dispatch(int fd, int mode, SV *cb) 218 296 { 219 const owl_io_dispatch *d = owl_select_find_ io_dispatch_by_fd(fd);297 const owl_io_dispatch *d = owl_select_find_valid_io_dispatch_by_fd(fd); 220 298 if (d != NULL && d->callback != owl_perlconfig_io_dispatch) { 221 299 /* Don't mess with non-perl dispatch functions from here. */ 222 300 return 1; 223 301 } 302 /* Also remove any invalidated perl dispatch functions that may have 303 * stuck around. */ 304 owl_select_remove_perl_io_dispatch(fd); 224 305 owl_select_add_io_dispatch(fd, mode, owl_perlconfig_io_dispatch, owl_perlconfig_io_dispatch_destroy, cb); 225 306 return 0; 226 307 } 227 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 228 324 int owl_select_remove_perl_io_dispatch(int fd) 229 325 { 230 const owl_io_dispatch *d = owl_select_find_io_dispatch_by_fd(fd);231 if (d != NULL && d->callback == owl_perlconfig_io_dispatch) {326 owl_io_dispatch *d = owl_select_find_perl_io_dispatch(fd); 327 if (d != NULL) { 232 328 /* Only remove perl io dispatchers from here. */ 233 329 owl_select_remove_io_dispatch(d); … … 237 333 } 238 334 239 int owl_select_aim_hack(fd_set *rfds, fd_set *wfds) 240 { 241 aim_conn_t *cur; 242 aim_session_t *sess; 243 int max_fd; 244 245 max_fd = 0; 246 sess = owl_global_get_aimsess(&g); 247 for (cur = sess->connlist; cur; cur = cur->next) { 248 if (cur->fd != -1) { 249 FD_SET(cur->fd, rfds); 250 if (cur->status & AIM_CONN_STATUS_INPROGRESS) { 251 /* Yes, we're checking writable sockets here. Without it, AIM 252 login is really slow. */ 253 FD_SET(cur->fd, wfds); 254 } 255 256 if (cur->fd > max_fd) 257 max_fd = cur->fd; 258 } 259 } 260 return max_fd; 261 } 262 263 void owl_process_input_char(owl_input j) 264 { 265 int ret; 266 267 owl_global_set_lastinputtime(&g, time(NULL)); 268 ret = owl_keyhandler_process(owl_global_get_keyhandler(&g), j); 269 if (ret!=0 && ret!=1) { 270 owl_function_makemsg("Unable to handle keypress"); 271 } 272 } 273 274 void owl_select_mask_signals(sigset_t *oldmask) { 275 sigset_t set; 276 277 sigemptyset(&set); 278 sigaddset(&set, SIGWINCH); 279 sigaddset(&set, SIGALRM); 280 sigaddset(&set, SIGPIPE); 281 sigaddset(&set, SIGTERM); 282 sigaddset(&set, SIGHUP); 283 sigaddset(&set, SIGINT); 284 sigprocmask(SIG_BLOCK, &set, oldmask); 285 } 286 287 void owl_select_handle_intr(sigset_t *restore) 288 { 289 owl_input in; 290 291 owl_global_unset_interrupted(&g); 292 293 sigprocmask(SIG_SETMASK, restore, NULL); 294 295 in.ch = in.uch = owl_global_get_startup_tio(&g)->c_cc[VINTR]; 296 owl_process_input_char(in); 297 } 298 299 owl_ps_action *owl_select_add_pre_select_action(int (*cb)(owl_ps_action *, void *), void (*destroy)(owl_ps_action *), void *data) 300 { 301 owl_ps_action *a = g_new(owl_ps_action, 1); 302 owl_list *psa_list = owl_global_get_psa_list(&g); 303 a->needs_gc = 0; 304 a->callback = cb; 305 a->destroy = destroy; 306 a->data = data; 307 owl_list_append_element(psa_list, a); 308 return a; 309 } 310 311 void owl_select_psa_gc(void) 312 { 313 int i; 314 owl_list *psa_list; 315 owl_ps_action *a; 316 317 psa_list = owl_global_get_psa_list(&g); 318 for (i = owl_list_get_size(psa_list) - 1; i >= 0; i--) { 319 a = owl_list_get_element(psa_list, i); 320 if (a->needs_gc) { 321 owl_list_remove_element(psa_list, i); 322 if (a->destroy) { 323 a->destroy(a); 324 } 325 g_free(a); 326 } 327 } 328 } 329 330 void owl_select_remove_pre_select_action(owl_ps_action *a) 331 { 332 a->needs_gc = 1; 333 if (!psa_active) 334 owl_select_psa_gc(); 335 } 336 337 int owl_select_do_pre_select_actions(void) 338 { 339 int i, len, ret; 340 owl_list *psa_list; 341 342 psa_active = 1; 343 ret = 0; 344 psa_list = owl_global_get_psa_list(&g); 345 len = owl_list_get_size(psa_list); 346 for (i = 0; i < len; i++) { 347 owl_ps_action *a = owl_list_get_element(psa_list, i); 348 if (a->callback != NULL && a->callback(a, a->data)) { 349 ret = 1; 350 } 351 } 352 psa_active = 0; 353 owl_select_psa_gc(); 354 return ret; 355 } 356 357 void owl_select(void) 358 { 359 int i, max_fd, max_fd2, aim_done, ret; 360 fd_set r; 361 fd_set w; 362 fd_set e; 363 fd_set aim_rfds, aim_wfds; 364 struct timespec timeout; 365 sigset_t mask; 366 367 owl_select_process_timers(&timeout); 368 369 owl_select_mask_signals(&mask); 370 371 if(owl_global_is_interrupted(&g)) { 372 owl_select_handle_intr(&mask); 373 return; 374 } 375 FD_ZERO(&r); 376 FD_ZERO(&w); 377 FD_ZERO(&e); 378 379 max_fd = owl_select_prepare_io_dispatch_fd_sets(&r, &w, &e); 380 381 /* AIM HACK: 382 * 383 * The problem - I'm not sure where to hook into the owl/faim 384 * interface to keep track of when the AIM socket(s) open and 385 * close. In particular, the bosconn thing throws me off. So, 386 * rather than register particular dispatchers for AIM, I look up 387 * the relevant FDs and add them to select's watch lists, then 388 * check for them individually before moving on to the other 389 * dispatchers. --asedeno 390 */ 391 aim_done = 1; 392 FD_ZERO(&aim_rfds); 393 FD_ZERO(&aim_wfds); 394 if (owl_global_is_doaimevents(&g)) { 395 aim_done = 0; 396 max_fd2 = owl_select_aim_hack(&aim_rfds, &aim_wfds); 397 if (max_fd < max_fd2) max_fd = max_fd2; 398 for(i = 0; i <= max_fd2; i++) { 399 if (FD_ISSET(i, &aim_rfds)) { 400 FD_SET(i, &r); 401 FD_SET(i, &e); 402 } 403 if (FD_ISSET(i, &aim_wfds)) { 404 FD_SET(i, &w); 405 FD_SET(i, &e); 406 } 407 } 408 } 409 /* END AIM HACK */ 410 411 if (owl_select_do_pre_select_actions()) { 412 timeout.tv_sec = 0; 413 timeout.tv_nsec = 0; 414 } 415 416 ret = pselect(max_fd+1, &r, &w, &e, &timeout, &mask); 417 418 if(ret < 0 && errno == EINTR) { 419 if(owl_global_is_interrupted(&g)) { 420 owl_select_handle_intr(NULL); 421 } 422 sigprocmask(SIG_SETMASK, &mask, NULL); 423 return; 424 } 425 426 sigprocmask(SIG_SETMASK, &mask, NULL); 427 428 if(ret > 0) { 429 /* AIM HACK: process all AIM events at once. */ 430 for(i = 0; !aim_done && i <= max_fd; i++) { 431 if (FD_ISSET(i, &r) || FD_ISSET(i, &w) || FD_ISSET(i, &e)) { 432 if (FD_ISSET(i, &aim_rfds) || FD_ISSET(i, &aim_wfds)) { 433 owl_process_aim(); 434 aim_done = 1; 435 } 436 } 437 } 438 owl_select_io_dispatch(&r, &w, &e, max_fd); 439 } 335 void owl_select_init(void) 336 { 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); 440 342 } 441 343 442 344 void owl_select_run_loop(void) 443 345 { 444 loop_active = 1; 445 while (loop_active) { 446 owl_select(); 447 } 346 main_context = g_main_context_default(); 347 loop = g_main_loop_new(main_context, FALSE); 348 g_main_loop_run(loop); 448 349 } 449 350 450 351 void owl_select_quit_loop(void) 451 352 { 452 loop_active = 0; 453 } 353 if (loop) { 354 g_main_loop_quit(loop); 355 g_main_loop_unref(loop); 356 loop = NULL; 357 } 358 } 359 360 typedef struct _owl_task { /*noproto*/ 361 void (*cb)(void *); 362 void *cbdata; 363 void (*destroy_cbdata)(void *); 364 } owl_task; 365 366 static gboolean _run_task(gpointer data) 367 { 368 owl_task *t = data; 369 if (t->cb) 370 t->cb(t->cbdata); 371 return FALSE; 372 } 373 374 static void _destroy_task(void *data) 375 { 376 owl_task *t = data; 377 if (t->destroy_cbdata) 378 t->destroy_cbdata(t->cbdata); 379 g_free(t); 380 } 381 382 void owl_select_post_task(void (*cb)(void*), void *cbdata, void (*destroy_cbdata)(void*), GMainContext *context) 383 { 384 GSource *source = g_idle_source_new(); 385 owl_task *t = g_new0(owl_task, 1); 386 t->cb = cb; 387 t->cbdata = cbdata; 388 t->destroy_cbdata = destroy_cbdata; 389 g_source_set_priority(source, G_PRIORITY_DEFAULT); 390 g_source_set_callback(source, _run_task, t, _destroy_task); 391 g_source_attach(source, context); 392 g_source_unref(source); 393 }
Note: See TracChangeset
for help on using the changeset viewer.