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