- Timestamp:
- May 23, 2011, 9:09:44 PM (13 years ago)
- Branches:
- master, release-1.10, release-1.8, release-1.9
- Children:
- 33b6431b
- Parents:
- 4c7c21f (diff), 1d21d9f (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
select.c
rfb96152 rf97c1a6 1 1 #include "owl.h" 2 #include <sys/stat.h> 3 2 3 static GMainLoop *loop = NULL; 4 static GMainContext *context; 4 5 static int dispatch_active = 0; 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) { 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) { 9 11 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;14 12 } 15 13 … … 44 42 } 45 43 46 void owl_select_process_timers(struct timespec *timeout) 47 { 48 time_t now = time(NULL); 49 GList **timers = owl_global_get_timerlist(&g); 50 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? */ 51 94 while(*timers) { 52 95 owl_timer *t = (*timers)->data; 53 96 int remove = 0; 54 97 55 if(t->time > now )98 if(t->time > now.tv_sec) 56 99 break; 57 100 58 101 /* Reschedule if appropriate */ 59 102 if(t->interval > 0) { 60 t->time = now + t->interval;103 t->time = now.tv_sec + t->interval; 61 104 *timers = g_list_remove(*timers, t); 62 105 *timers = g_list_insert_sorted(*timers, t, … … 72 115 } 73 116 } 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 } 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 86 127 87 128 static const owl_io_dispatch *owl_select_find_io_dispatch_by_fd(const int fd) … … 129 170 if (d->destroy) 130 171 d->destroy(d); 172 g_source_remove_poll(owl_io_dispatch_source, &d->pollfd); 131 173 g_free(d); 132 174 } … … 135 177 } 136 178 137 void owl_select_io_dispatch_gc(void)179 static void owl_select_io_dispatch_gc(void) 138 180 { 139 181 int i; … … 170 212 d->data = data; 171 213 214 /* TODO: Allow changing fd and mode in the middle? Probably don't care... */ 215 d->pollfd.fd = fd; 216 d->pollfd.events = 0; 217 if (d->mode & OWL_IO_READ) 218 d->pollfd.events |= G_IO_IN | G_IO_HUP | G_IO_ERR; 219 if (d->mode & OWL_IO_WRITE) 220 d->pollfd.events |= G_IO_OUT | G_IO_ERR; 221 if (d->mode & OWL_IO_EXCEPT) 222 d->pollfd.events |= G_IO_PRI | G_IO_ERR; 223 g_source_add_poll(owl_io_dispatch_source, &d->pollfd); 224 225 172 226 owl_select_remove_io_dispatch(owl_select_find_io_dispatch_by_fd(fd)); 173 227 owl_list_append_element(dl, d); … … 176 230 } 177 231 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; 232 static gboolean owl_io_dispatch_prepare(GSource *source, int *timeout) { 233 *timeout = -1; 234 return FALSE; 235 } 236 237 static gboolean owl_io_dispatch_check(GSource *source) { 238 int i, len; 239 const owl_list *dl; 240 241 dl = owl_global_get_io_dispatch_list(&g); 242 len = owl_list_get_size(dl); 243 for(i = 0; i < len; i++) { 244 const owl_io_dispatch *d = owl_list_get_element(dl, i); 245 if (d->pollfd.revents & d->pollfd.events) 246 return TRUE; 247 } 248 return FALSE; 249 } 250 251 static gboolean owl_io_dispatch_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) { 252 int i, len; 253 const owl_list *dl; 254 255 dispatch_active = 1; 256 dl = owl_global_get_io_dispatch_list(&g); 184 257 len = owl_list_get_size(dl); 185 258 for (i = 0; i < len; i++) { 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)))) { 259 owl_io_dispatch *d = owl_list_get_element(dl, i); 260 if ((d->pollfd.revents & d->pollfd.events) && d->callback != NULL) { 211 261 d->callback(d, d->data); 212 262 } … … 214 264 dispatch_active = 0; 215 265 owl_select_io_dispatch_gc(); 216 } 266 267 return TRUE; 268 } 269 270 static GSourceFuncs owl_io_dispatch_funcs = { 271 owl_io_dispatch_prepare, 272 owl_io_dispatch_check, 273 owl_io_dispatch_dispatch, 274 NULL 275 }; 217 276 218 277 int owl_select_add_perl_io_dispatch(int fd, int mode, SV *cb) … … 238 297 } 239 298 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 299 void owl_select_init(void) 300 { 301 owl_timer_source = g_source_new(&owl_timer_funcs, sizeof(GSource)); 302 g_source_attach(owl_timer_source, NULL); 303 304 owl_io_dispatch_source = g_source_new(&owl_io_dispatch_funcs, sizeof(GSource)); 305 g_source_attach(owl_io_dispatch_source, NULL); 306 } 307 308 void owl_select_run_loop(void) 309 { 310 context = g_main_context_default(); 311 loop = g_main_loop_new(context, FALSE); 312 g_main_loop_run(loop); 313 } 314 315 void owl_select_quit_loop(void) 316 { 317 if (loop) { 318 g_main_loop_quit(loop); 319 loop = NULL; 320 } 321 } 322 323 #if 0 324 /* FIXME: Reimplement this check in the glib world. */ 358 325 static void owl_select_prune_bad_fds(void) { 359 326 owl_list *dl = owl_global_get_io_dispatch_list(&g); … … 372 339 owl_select_io_dispatch_gc(); 373 340 } 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 } 463 } 464 465 void owl_select_run_loop(void) 466 { 467 loop_active = 1; 468 while (loop_active) { 469 owl_select(); 470 } 471 } 472 473 void owl_select_quit_loop(void) 474 { 475 loop_active = 0; 476 } 341 #endif 342 343 typedef struct _owl_task { /*noproto*/ 344 void (*cb)(void *); 345 void *cbdata; 346 void (*destroy_cbdata)(void *); 347 } owl_task; 348 349 static gboolean _run_task(gpointer data) 350 { 351 owl_task *t = data; 352 if (t->cb) 353 t->cb(t->cbdata); 354 return FALSE; 355 } 356 357 static void _destroy_task(void *data) 358 { 359 owl_task *t = data; 360 if (t->destroy_cbdata) 361 t->destroy_cbdata(t->cbdata); 362 g_free(t); 363 } 364 365 void owl_select_post_task(void (*cb)(void*), void *cbdata, void (*destroy_cbdata)(void*)) 366 { 367 GSource *source = g_idle_source_new(); 368 owl_task *t = g_new0(owl_task, 1); 369 t->cb = cb; 370 t->cbdata = cbdata; 371 t->destroy_cbdata = destroy_cbdata; 372 g_source_set_priority(source, G_PRIORITY_DEFAULT); 373 g_source_set_callback(source, _run_task, t, _destroy_task); 374 g_source_attach(source, context); 375 g_source_unref(source); 376 }
Note: See TracChangeset
for help on using the changeset viewer.