Changes in select.c [f0781ba:d4927a7]
Legend:
- Unmodified
- Added
- Removed
-
select.c
rf0781ba rd4927a7 1 1 #include "owl.h" 2 2 3 static GMainLoop *loop = NULL;4 static GMainContext *main_context;5 3 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) { 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) { 11 8 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; 12 13 } 13 14 … … 42 43 } 43 44 44 static gboolean owl_timer_prepare(GSource *source, int *timeout) { 45 void owl_select_process_timers(struct timespec *timeout) 46 { 47 time_t now = time(NULL); 45 48 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? */ 49 94 50 while(*timers) { 95 51 owl_timer *t = (*timers)->data; 96 52 int remove = 0; 97 53 98 if(t->time > now .tv_sec)54 if(t->time > now) 99 55 break; 100 56 101 57 /* Reschedule if appropriate */ 102 58 if(t->interval > 0) { 103 t->time = now .tv_sec+ t->interval;59 t->time = now + t->interval; 104 60 *timers = g_list_remove(*timers, t); 105 61 *timers = g_list_insert_sorted(*timers, t, … … 115 71 } 116 72 } 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) 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) 129 87 { 130 88 int i, len; … … 135 93 for(i = 0; i < len; i++) { 136 94 d = owl_list_get_element(dl, i); 137 if (d->fd == fd && d->valid) return d;95 if (d->fd == fd) return d; 138 96 } 139 97 return NULL; … … 154 112 } 155 113 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 114 } 165 115 … … 175 125 d->needs_gc = 1; 176 126 else { 177 owl_select_invalidate_io_dispatch(d);178 127 owl_list_remove_element(dl, elt); 179 128 if (d->destroy) … … 185 134 } 186 135 187 staticvoid owl_select_io_dispatch_gc(void)136 void owl_select_io_dispatch_gc(void) 188 137 { 189 138 int i; … … 203 152 } 204 153 205 /* Each FD may have at most one validdispatcher.154 /* Each FD may have at most one dispatcher. 206 155 * If a new dispatch is added for an FD, the old one is removed. 207 156 * mode determines what types of events are watched for, and may be any combination of: … … 212 161 owl_io_dispatch *d = g_new(owl_io_dispatch, 1); 213 162 owl_list *dl = owl_global_get_io_dispatch_list(&g); 214 owl_io_dispatch *other;215 163 216 164 d->fd = fd; 217 d->valid = true;218 165 d->needs_gc = 0; 219 166 d->mode = mode; … … 222 169 d->data = data; 223 170 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); 171 owl_select_remove_io_dispatch(owl_select_find_io_dispatch_by_fd(fd)); 239 172 owl_list_append_element(dl, d); 240 173 … … 242 175 } 243 176 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); 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; 274 183 len = owl_list_get_size(dl); 275 184 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) { 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)))) { 279 210 d->callback(d, d->data); 280 211 } … … 282 213 dispatch_active = 0; 283 214 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 }; 215 } 294 216 295 217 int owl_select_add_perl_io_dispatch(int fd, int mode, SV *cb) 296 218 { 297 const owl_io_dispatch *d = owl_select_find_ valid_io_dispatch_by_fd(fd);219 const owl_io_dispatch *d = owl_select_find_io_dispatch_by_fd(fd); 298 220 if (d != NULL && d->callback != owl_perlconfig_io_dispatch) { 299 221 /* Don't mess with non-perl dispatch functions from here. */ 300 222 return 1; 301 223 } 302 /* Also remove any invalidated perl dispatch functions that may have303 * stuck around. */304 owl_select_remove_perl_io_dispatch(fd);305 224 owl_select_add_io_dispatch(fd, mode, owl_perlconfig_io_dispatch, owl_perlconfig_io_dispatch_destroy, cb); 306 225 return 0; 307 226 } 308 227 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 228 int owl_select_remove_perl_io_dispatch(int fd) 325 229 { 326 owl_io_dispatch *d = owl_select_find_perl_io_dispatch(fd);327 if (d != NULL ) {230 const owl_io_dispatch *d = owl_select_find_io_dispatch_by_fd(fd); 231 if (d != NULL && d->callback == owl_perlconfig_io_dispatch) { 328 232 /* Only remove perl io dispatchers from here. */ 329 233 owl_select_remove_io_dispatch(d); … … 333 237 } 334 238 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); 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 } 342 440 } 343 441 344 442 void owl_select_run_loop(void) 345 443 { 346 main_context = g_main_context_default(); 347 loop = g_main_loop_new(main_context, FALSE); 348 g_main_loop_run(loop); 444 loop_active = 1; 445 while (loop_active) { 446 owl_select(); 447 } 349 448 } 350 449 351 450 void owl_select_quit_loop(void) 352 451 { 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 } 452 loop_active = 0; 453 }
Note: See TracChangeset
for help on using the changeset viewer.