D-Bus 1.4.20
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-mainloop.c Main loop utility 00003 * 00004 * Copyright (C) 2003, 2004 Red Hat, Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 * 00022 */ 00023 00024 #include <config.h> 00025 #include "dbus-mainloop.h" 00026 00027 #ifndef DOXYGEN_SHOULD_SKIP_THIS 00028 00029 #include <dbus/dbus-list.h> 00030 #include <dbus/dbus-sysdeps.h> 00031 #include <dbus/dbus-watch.h> 00032 00033 #define MAINLOOP_SPEW 0 00034 00035 #if MAINLOOP_SPEW 00036 #ifdef DBUS_ENABLE_VERBOSE_MODE 00037 static const char* 00038 watch_flags_to_string (int flags) 00039 { 00040 const char *watch_type; 00041 00042 if ((flags & DBUS_WATCH_READABLE) && 00043 (flags & DBUS_WATCH_WRITABLE)) 00044 watch_type = "readwrite"; 00045 else if (flags & DBUS_WATCH_READABLE) 00046 watch_type = "read"; 00047 else if (flags & DBUS_WATCH_WRITABLE) 00048 watch_type = "write"; 00049 else 00050 watch_type = "not read or write"; 00051 return watch_type; 00052 } 00053 #endif /* DBUS_ENABLE_VERBOSE_MODE */ 00054 #endif /* MAINLOOP_SPEW */ 00055 00056 struct DBusLoop 00057 { 00058 int refcount; 00059 DBusList *callbacks; 00060 int callback_list_serial; 00061 int watch_count; 00062 int timeout_count; 00063 int depth; 00064 DBusList *need_dispatch; 00065 }; 00066 00067 typedef enum 00068 { 00069 CALLBACK_WATCH, 00070 CALLBACK_TIMEOUT 00071 } CallbackType; 00072 00073 typedef struct 00074 { 00075 int refcount; 00076 CallbackType type; 00077 void *data; 00078 DBusFreeFunction free_data_func; 00079 } Callback; 00080 00081 typedef struct 00082 { 00083 Callback callback; 00084 DBusWatchFunction function; 00085 DBusWatch *watch; 00086 /* last watch handle failed due to OOM */ 00087 unsigned int last_iteration_oom : 1; 00088 } WatchCallback; 00089 00090 typedef struct 00091 { 00092 Callback callback; 00093 DBusTimeout *timeout; 00094 DBusTimeoutFunction function; 00095 unsigned long last_tv_sec; 00096 unsigned long last_tv_usec; 00097 } TimeoutCallback; 00098 00099 #define WATCH_CALLBACK(callback) ((WatchCallback*)callback) 00100 #define TIMEOUT_CALLBACK(callback) ((TimeoutCallback*)callback) 00101 00102 static WatchCallback* 00103 watch_callback_new (DBusWatch *watch, 00104 DBusWatchFunction function, 00105 void *data, 00106 DBusFreeFunction free_data_func) 00107 { 00108 WatchCallback *cb; 00109 00110 cb = dbus_new (WatchCallback, 1); 00111 if (cb == NULL) 00112 return NULL; 00113 00114 cb->watch = watch; 00115 cb->function = function; 00116 cb->last_iteration_oom = FALSE; 00117 cb->callback.refcount = 1; 00118 cb->callback.type = CALLBACK_WATCH; 00119 cb->callback.data = data; 00120 cb->callback.free_data_func = free_data_func; 00121 00122 return cb; 00123 } 00124 00125 static TimeoutCallback* 00126 timeout_callback_new (DBusTimeout *timeout, 00127 DBusTimeoutFunction function, 00128 void *data, 00129 DBusFreeFunction free_data_func) 00130 { 00131 TimeoutCallback *cb; 00132 00133 cb = dbus_new (TimeoutCallback, 1); 00134 if (cb == NULL) 00135 return NULL; 00136 00137 cb->timeout = timeout; 00138 cb->function = function; 00139 _dbus_get_current_time (&cb->last_tv_sec, 00140 &cb->last_tv_usec); 00141 cb->callback.refcount = 1; 00142 cb->callback.type = CALLBACK_TIMEOUT; 00143 cb->callback.data = data; 00144 cb->callback.free_data_func = free_data_func; 00145 00146 return cb; 00147 } 00148 00149 static Callback * 00150 callback_ref (Callback *cb) 00151 { 00152 _dbus_assert (cb->refcount > 0); 00153 00154 cb->refcount += 1; 00155 00156 return cb; 00157 } 00158 00159 static void 00160 callback_unref (Callback *cb) 00161 { 00162 _dbus_assert (cb->refcount > 0); 00163 00164 cb->refcount -= 1; 00165 00166 if (cb->refcount == 0) 00167 { 00168 if (cb->free_data_func) 00169 (* cb->free_data_func) (cb->data); 00170 00171 dbus_free (cb); 00172 } 00173 } 00174 00175 static dbus_bool_t 00176 add_callback (DBusLoop *loop, 00177 Callback *cb) 00178 { 00179 if (!_dbus_list_append (&loop->callbacks, cb)) 00180 return FALSE; 00181 00182 loop->callback_list_serial += 1; 00183 00184 switch (cb->type) 00185 { 00186 case CALLBACK_WATCH: 00187 loop->watch_count += 1; 00188 break; 00189 case CALLBACK_TIMEOUT: 00190 loop->timeout_count += 1; 00191 break; 00192 } 00193 00194 return TRUE; 00195 } 00196 00197 static void 00198 remove_callback (DBusLoop *loop, 00199 DBusList *link) 00200 { 00201 Callback *cb = link->data; 00202 00203 switch (cb->type) 00204 { 00205 case CALLBACK_WATCH: 00206 loop->watch_count -= 1; 00207 break; 00208 case CALLBACK_TIMEOUT: 00209 loop->timeout_count -= 1; 00210 break; 00211 } 00212 00213 callback_unref (cb); 00214 _dbus_list_remove_link (&loop->callbacks, link); 00215 loop->callback_list_serial += 1; 00216 } 00217 00218 DBusLoop* 00219 _dbus_loop_new (void) 00220 { 00221 DBusLoop *loop; 00222 00223 loop = dbus_new0 (DBusLoop, 1); 00224 if (loop == NULL) 00225 return NULL; 00226 00227 loop->refcount = 1; 00228 00229 return loop; 00230 } 00231 00232 DBusLoop * 00233 _dbus_loop_ref (DBusLoop *loop) 00234 { 00235 _dbus_assert (loop != NULL); 00236 _dbus_assert (loop->refcount > 0); 00237 00238 loop->refcount += 1; 00239 00240 return loop; 00241 } 00242 00243 void 00244 _dbus_loop_unref (DBusLoop *loop) 00245 { 00246 _dbus_assert (loop != NULL); 00247 _dbus_assert (loop->refcount > 0); 00248 00249 loop->refcount -= 1; 00250 if (loop->refcount == 0) 00251 { 00252 while (loop->need_dispatch) 00253 { 00254 DBusConnection *connection = _dbus_list_pop_first (&loop->need_dispatch); 00255 00256 dbus_connection_unref (connection); 00257 } 00258 00259 dbus_free (loop); 00260 } 00261 } 00262 00263 dbus_bool_t 00264 _dbus_loop_add_watch (DBusLoop *loop, 00265 DBusWatch *watch, 00266 DBusWatchFunction function, 00267 void *data, 00268 DBusFreeFunction free_data_func) 00269 { 00270 WatchCallback *wcb; 00271 00272 wcb = watch_callback_new (watch, function, data, free_data_func); 00273 if (wcb == NULL) 00274 return FALSE; 00275 00276 if (!add_callback (loop, (Callback*) wcb)) 00277 { 00278 wcb->callback.free_data_func = NULL; /* don't want to have this side effect */ 00279 callback_unref ((Callback*) wcb); 00280 return FALSE; 00281 } 00282 00283 return TRUE; 00284 } 00285 00286 void 00287 _dbus_loop_remove_watch (DBusLoop *loop, 00288 DBusWatch *watch, 00289 DBusWatchFunction function, 00290 void *data) 00291 { 00292 DBusList *link; 00293 00294 link = _dbus_list_get_first_link (&loop->callbacks); 00295 while (link != NULL) 00296 { 00297 DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link); 00298 Callback *this = link->data; 00299 00300 if (this->type == CALLBACK_WATCH && 00301 WATCH_CALLBACK (this)->watch == watch && 00302 this->data == data && 00303 WATCH_CALLBACK (this)->function == function) 00304 { 00305 remove_callback (loop, link); 00306 00307 return; 00308 } 00309 00310 link = next; 00311 } 00312 00313 _dbus_warn ("could not find watch %p function %p data %p to remove\n", 00314 watch, (void *)function, data); 00315 } 00316 00317 dbus_bool_t 00318 _dbus_loop_add_timeout (DBusLoop *loop, 00319 DBusTimeout *timeout, 00320 DBusTimeoutFunction function, 00321 void *data, 00322 DBusFreeFunction free_data_func) 00323 { 00324 TimeoutCallback *tcb; 00325 00326 tcb = timeout_callback_new (timeout, function, data, free_data_func); 00327 if (tcb == NULL) 00328 return FALSE; 00329 00330 if (!add_callback (loop, (Callback*) tcb)) 00331 { 00332 tcb->callback.free_data_func = NULL; /* don't want to have this side effect */ 00333 callback_unref ((Callback*) tcb); 00334 return FALSE; 00335 } 00336 00337 return TRUE; 00338 } 00339 00340 void 00341 _dbus_loop_remove_timeout (DBusLoop *loop, 00342 DBusTimeout *timeout, 00343 DBusTimeoutFunction function, 00344 void *data) 00345 { 00346 DBusList *link; 00347 00348 link = _dbus_list_get_first_link (&loop->callbacks); 00349 while (link != NULL) 00350 { 00351 DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link); 00352 Callback *this = link->data; 00353 00354 if (this->type == CALLBACK_TIMEOUT && 00355 TIMEOUT_CALLBACK (this)->timeout == timeout && 00356 this->data == data && 00357 TIMEOUT_CALLBACK (this)->function == function) 00358 { 00359 remove_callback (loop, link); 00360 00361 return; 00362 } 00363 00364 link = next; 00365 } 00366 00367 _dbus_warn ("could not find timeout %p function %p data %p to remove\n", 00368 timeout, (void *)function, data); 00369 } 00370 00371 /* Convolutions from GLib, there really must be a better way 00372 * to do this. 00373 */ 00374 static dbus_bool_t 00375 check_timeout (unsigned long tv_sec, 00376 unsigned long tv_usec, 00377 TimeoutCallback *tcb, 00378 int *timeout) 00379 { 00380 long sec_remaining; 00381 long msec_remaining; 00382 unsigned long expiration_tv_sec; 00383 unsigned long expiration_tv_usec; 00384 long interval_seconds; 00385 long interval_milliseconds; 00386 int interval; 00387 00388 /* I'm pretty sure this function could suck (a lot) less */ 00389 00390 interval = dbus_timeout_get_interval (tcb->timeout); 00391 00392 interval_seconds = interval / 1000L; 00393 interval_milliseconds = interval % 1000L; 00394 00395 expiration_tv_sec = tcb->last_tv_sec + interval_seconds; 00396 expiration_tv_usec = tcb->last_tv_usec + interval_milliseconds * 1000; 00397 if (expiration_tv_usec >= 1000000) 00398 { 00399 expiration_tv_usec -= 1000000; 00400 expiration_tv_sec += 1; 00401 } 00402 00403 sec_remaining = expiration_tv_sec - tv_sec; 00404 /* need to force this to be signed, as it is intended to sometimes 00405 * produce a negative result 00406 */ 00407 msec_remaining = ((long) expiration_tv_usec - (long) tv_usec) / 1000L; 00408 00409 #if MAINLOOP_SPEW 00410 _dbus_verbose ("Interval is %ld seconds %ld msecs\n", 00411 interval_seconds, 00412 interval_milliseconds); 00413 _dbus_verbose ("Now is %lu seconds %lu usecs\n", 00414 tv_sec, tv_usec); 00415 _dbus_verbose ("Last is %lu seconds %lu usecs\n", 00416 tcb->last_tv_sec, tcb->last_tv_usec); 00417 _dbus_verbose ("Exp is %lu seconds %lu usecs\n", 00418 expiration_tv_sec, expiration_tv_usec); 00419 _dbus_verbose ("Pre-correction, sec_remaining %ld msec_remaining %ld\n", 00420 sec_remaining, msec_remaining); 00421 #endif 00422 00423 /* We do the following in a rather convoluted fashion to deal with 00424 * the fact that we don't have an integral type big enough to hold 00425 * the difference of two timevals in milliseconds. 00426 */ 00427 if (sec_remaining < 0 || (sec_remaining == 0 && msec_remaining < 0)) 00428 { 00429 *timeout = 0; 00430 } 00431 else 00432 { 00433 if (msec_remaining < 0) 00434 { 00435 msec_remaining += 1000; 00436 sec_remaining -= 1; 00437 } 00438 00439 if (sec_remaining > (_DBUS_INT_MAX / 1000) || 00440 msec_remaining > _DBUS_INT_MAX) 00441 *timeout = _DBUS_INT_MAX; 00442 else 00443 *timeout = sec_remaining * 1000 + msec_remaining; 00444 } 00445 00446 if (*timeout > interval) 00447 { 00448 /* This indicates that the system clock probably moved backward */ 00449 _dbus_verbose ("System clock set backward! Resetting timeout.\n"); 00450 00451 tcb->last_tv_sec = tv_sec; 00452 tcb->last_tv_usec = tv_usec; 00453 00454 *timeout = interval; 00455 } 00456 00457 #if MAINLOOP_SPEW 00458 _dbus_verbose (" timeout expires in %d milliseconds\n", *timeout); 00459 #endif 00460 00461 return *timeout == 0; 00462 } 00463 00464 dbus_bool_t 00465 _dbus_loop_dispatch (DBusLoop *loop) 00466 { 00467 00468 #if MAINLOOP_SPEW 00469 _dbus_verbose (" %d connections to dispatch\n", _dbus_list_get_length (&loop->need_dispatch)); 00470 #endif 00471 00472 if (loop->need_dispatch == NULL) 00473 return FALSE; 00474 00475 next: 00476 while (loop->need_dispatch != NULL) 00477 { 00478 DBusConnection *connection = _dbus_list_pop_first (&loop->need_dispatch); 00479 00480 while (TRUE) 00481 { 00482 DBusDispatchStatus status; 00483 00484 status = dbus_connection_dispatch (connection); 00485 00486 if (status == DBUS_DISPATCH_COMPLETE) 00487 { 00488 dbus_connection_unref (connection); 00489 goto next; 00490 } 00491 else 00492 { 00493 if (status == DBUS_DISPATCH_NEED_MEMORY) 00494 _dbus_wait_for_memory (); 00495 } 00496 } 00497 } 00498 00499 return TRUE; 00500 } 00501 00502 dbus_bool_t 00503 _dbus_loop_queue_dispatch (DBusLoop *loop, 00504 DBusConnection *connection) 00505 { 00506 if (_dbus_list_append (&loop->need_dispatch, connection)) 00507 { 00508 dbus_connection_ref (connection); 00509 return TRUE; 00510 } 00511 else 00512 return FALSE; 00513 } 00514 00515 /* Returns TRUE if we invoked any timeouts or have ready file 00516 * descriptors, which is just used in test code as a debug hack 00517 */ 00518 00519 dbus_bool_t 00520 _dbus_loop_iterate (DBusLoop *loop, 00521 dbus_bool_t block) 00522 { 00523 #define N_STACK_DESCRIPTORS 64 00524 dbus_bool_t retval; 00525 DBusPollFD *fds; 00526 DBusPollFD stack_fds[N_STACK_DESCRIPTORS]; 00527 int n_fds; 00528 WatchCallback **watches_for_fds; 00529 WatchCallback *stack_watches_for_fds[N_STACK_DESCRIPTORS]; 00530 int i; 00531 DBusList *link; 00532 int n_ready; 00533 int initial_serial; 00534 long timeout; 00535 dbus_bool_t oom_watch_pending; 00536 int orig_depth; 00537 00538 retval = FALSE; 00539 00540 fds = NULL; 00541 watches_for_fds = NULL; 00542 n_fds = 0; 00543 oom_watch_pending = FALSE; 00544 orig_depth = loop->depth; 00545 00546 #if MAINLOOP_SPEW 00547 _dbus_verbose ("Iteration block=%d depth=%d timeout_count=%d watch_count=%d\n", 00548 block, loop->depth, loop->timeout_count, loop->watch_count); 00549 #endif 00550 00551 if (loop->callbacks == NULL) 00552 goto next_iteration; 00553 00554 if (loop->watch_count > N_STACK_DESCRIPTORS) 00555 { 00556 fds = dbus_new0 (DBusPollFD, loop->watch_count); 00557 00558 while (fds == NULL) 00559 { 00560 _dbus_wait_for_memory (); 00561 fds = dbus_new0 (DBusPollFD, loop->watch_count); 00562 } 00563 00564 watches_for_fds = dbus_new (WatchCallback*, loop->watch_count); 00565 while (watches_for_fds == NULL) 00566 { 00567 _dbus_wait_for_memory (); 00568 watches_for_fds = dbus_new (WatchCallback*, loop->watch_count); 00569 } 00570 } 00571 else 00572 { 00573 fds = stack_fds; 00574 watches_for_fds = stack_watches_for_fds; 00575 } 00576 00577 /* fill our array of fds and watches */ 00578 n_fds = 0; 00579 link = _dbus_list_get_first_link (&loop->callbacks); 00580 while (link != NULL) 00581 { 00582 DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link); 00583 Callback *cb = link->data; 00584 if (cb->type == CALLBACK_WATCH) 00585 { 00586 unsigned int flags; 00587 WatchCallback *wcb = WATCH_CALLBACK (cb); 00588 int fd = dbus_watch_get_socket (wcb->watch); 00589 00590 if (wcb->last_iteration_oom) 00591 { 00592 /* we skip this one this time, but reenable it next time, 00593 * and have a timeout on this iteration 00594 */ 00595 wcb->last_iteration_oom = FALSE; 00596 oom_watch_pending = TRUE; 00597 00598 retval = TRUE; /* return TRUE here to keep the loop going, 00599 * since we don't know the watch is inactive 00600 */ 00601 00602 #if MAINLOOP_SPEW 00603 _dbus_verbose (" skipping watch on fd %d as it was out of memory last time\n", 00604 fd); 00605 #endif 00606 } 00607 else if (_DBUS_UNLIKELY (fd == -1)) 00608 { 00609 _dbus_warn ("watch %p was invalidated but not removed; " 00610 "removing it now\n", wcb->watch); 00611 _dbus_loop_remove_watch (loop, wcb->watch, wcb->function, 00612 ((Callback *)wcb)->data); 00613 } 00614 else if (dbus_watch_get_enabled (wcb->watch)) 00615 { 00616 watches_for_fds[n_fds] = wcb; 00617 00618 callback_ref (cb); 00619 00620 flags = dbus_watch_get_flags (wcb->watch); 00621 00622 fds[n_fds].fd = fd; 00623 fds[n_fds].revents = 0; 00624 fds[n_fds].events = 0; 00625 if (flags & DBUS_WATCH_READABLE) 00626 fds[n_fds].events |= _DBUS_POLLIN; 00627 if (flags & DBUS_WATCH_WRITABLE) 00628 fds[n_fds].events |= _DBUS_POLLOUT; 00629 00630 #if MAINLOOP_SPEW 00631 _dbus_verbose (" polling watch on fd %d %s\n", 00632 fd, watch_flags_to_string (flags)); 00633 #endif 00634 00635 n_fds += 1; 00636 } 00637 else 00638 { 00639 #if MAINLOOP_SPEW 00640 _dbus_verbose (" skipping disabled watch on fd %d %s\n", 00641 fd, 00642 watch_flags_to_string (dbus_watch_get_flags (wcb->watch))); 00643 #endif 00644 } 00645 } 00646 00647 link = next; 00648 } 00649 00650 timeout = -1; 00651 if (loop->timeout_count > 0) 00652 { 00653 unsigned long tv_sec; 00654 unsigned long tv_usec; 00655 00656 _dbus_get_current_time (&tv_sec, &tv_usec); 00657 00658 link = _dbus_list_get_first_link (&loop->callbacks); 00659 while (link != NULL) 00660 { 00661 DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link); 00662 Callback *cb = link->data; 00663 00664 if (cb->type == CALLBACK_TIMEOUT && 00665 dbus_timeout_get_enabled (TIMEOUT_CALLBACK (cb)->timeout)) 00666 { 00667 TimeoutCallback *tcb = TIMEOUT_CALLBACK (cb); 00668 int msecs_remaining; 00669 00670 check_timeout (tv_sec, tv_usec, tcb, &msecs_remaining); 00671 00672 if (timeout < 0) 00673 timeout = msecs_remaining; 00674 else 00675 timeout = MIN (msecs_remaining, timeout); 00676 00677 #if MAINLOOP_SPEW 00678 _dbus_verbose (" timeout added, %d remaining, aggregate timeout %ld\n", 00679 msecs_remaining, timeout); 00680 #endif 00681 00682 _dbus_assert (timeout >= 0); 00683 00684 if (timeout == 0) 00685 break; /* it's not going to get shorter... */ 00686 } 00687 #if MAINLOOP_SPEW 00688 else if (cb->type == CALLBACK_TIMEOUT) 00689 { 00690 _dbus_verbose (" skipping disabled timeout\n"); 00691 } 00692 #endif 00693 00694 link = next; 00695 } 00696 } 00697 00698 /* Never block if we have stuff to dispatch */ 00699 if (!block || loop->need_dispatch != NULL) 00700 { 00701 timeout = 0; 00702 #if MAINLOOP_SPEW 00703 _dbus_verbose (" timeout is 0 as we aren't blocking\n"); 00704 #endif 00705 } 00706 00707 /* if a watch is OOM, don't wait longer than the OOM 00708 * wait to re-enable it 00709 */ 00710 if (oom_watch_pending) 00711 timeout = MIN (timeout, _dbus_get_oom_wait ()); 00712 00713 #if MAINLOOP_SPEW 00714 _dbus_verbose (" polling on %d descriptors timeout %ld\n", n_fds, timeout); 00715 #endif 00716 00717 n_ready = _dbus_poll (fds, n_fds, timeout); 00718 00719 initial_serial = loop->callback_list_serial; 00720 00721 if (loop->timeout_count > 0) 00722 { 00723 unsigned long tv_sec; 00724 unsigned long tv_usec; 00725 00726 _dbus_get_current_time (&tv_sec, &tv_usec); 00727 00728 /* It'd be nice to avoid this O(n) thingy here */ 00729 link = _dbus_list_get_first_link (&loop->callbacks); 00730 while (link != NULL) 00731 { 00732 DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link); 00733 Callback *cb = link->data; 00734 00735 if (initial_serial != loop->callback_list_serial) 00736 goto next_iteration; 00737 00738 if (loop->depth != orig_depth) 00739 goto next_iteration; 00740 00741 if (cb->type == CALLBACK_TIMEOUT && 00742 dbus_timeout_get_enabled (TIMEOUT_CALLBACK (cb)->timeout)) 00743 { 00744 TimeoutCallback *tcb = TIMEOUT_CALLBACK (cb); 00745 int msecs_remaining; 00746 00747 if (check_timeout (tv_sec, tv_usec, 00748 tcb, &msecs_remaining)) 00749 { 00750 /* Save last callback time and fire this timeout */ 00751 tcb->last_tv_sec = tv_sec; 00752 tcb->last_tv_usec = tv_usec; 00753 00754 #if MAINLOOP_SPEW 00755 _dbus_verbose (" invoking timeout\n"); 00756 #endif 00757 00758 (* tcb->function) (tcb->timeout, 00759 cb->data); 00760 00761 retval = TRUE; 00762 } 00763 else 00764 { 00765 #if MAINLOOP_SPEW 00766 _dbus_verbose (" timeout has not expired\n"); 00767 #endif 00768 } 00769 } 00770 #if MAINLOOP_SPEW 00771 else if (cb->type == CALLBACK_TIMEOUT) 00772 { 00773 _dbus_verbose (" skipping invocation of disabled timeout\n"); 00774 } 00775 #endif 00776 00777 link = next; 00778 } 00779 } 00780 00781 if (n_ready > 0) 00782 { 00783 i = 0; 00784 while (i < n_fds) 00785 { 00786 /* FIXME I think this "restart if we change the watches" 00787 * approach could result in starving watches 00788 * toward the end of the list. 00789 */ 00790 if (initial_serial != loop->callback_list_serial) 00791 goto next_iteration; 00792 00793 if (loop->depth != orig_depth) 00794 goto next_iteration; 00795 00796 if (fds[i].revents != 0) 00797 { 00798 WatchCallback *wcb; 00799 unsigned int condition; 00800 00801 wcb = watches_for_fds[i]; 00802 00803 condition = 0; 00804 if (fds[i].revents & _DBUS_POLLIN) 00805 condition |= DBUS_WATCH_READABLE; 00806 if (fds[i].revents & _DBUS_POLLOUT) 00807 condition |= DBUS_WATCH_WRITABLE; 00808 if (fds[i].revents & _DBUS_POLLHUP) 00809 condition |= DBUS_WATCH_HANGUP; 00810 if (fds[i].revents & _DBUS_POLLERR) 00811 condition |= DBUS_WATCH_ERROR; 00812 00813 /* condition may still be 0 if we got some 00814 * weird POLLFOO thing like POLLWRBAND 00815 */ 00816 00817 if (condition != 0 && 00818 dbus_watch_get_enabled (wcb->watch)) 00819 { 00820 if (!(* wcb->function) (wcb->watch, 00821 condition, 00822 ((Callback*)wcb)->data)) 00823 wcb->last_iteration_oom = TRUE; 00824 00825 #if MAINLOOP_SPEW 00826 _dbus_verbose (" Invoked watch, oom = %d\n", 00827 wcb->last_iteration_oom); 00828 #endif 00829 00830 retval = TRUE; 00831 } 00832 00833 if (_DBUS_UNLIKELY (fds[i].revents & _DBUS_POLLNVAL)) 00834 { 00835 _dbus_warn ("invalid request, socket fd %d not open\n", 00836 fds[i].fd); 00837 _dbus_watch_invalidate (wcb->watch); 00838 _dbus_loop_remove_watch (loop, wcb->watch, wcb->function, 00839 ((Callback *)wcb)->data); 00840 } 00841 } 00842 00843 ++i; 00844 } 00845 } 00846 00847 next_iteration: 00848 #if MAINLOOP_SPEW 00849 _dbus_verbose (" moving to next iteration\n"); 00850 #endif 00851 00852 if (fds && fds != stack_fds) 00853 dbus_free (fds); 00854 if (watches_for_fds) 00855 { 00856 i = 0; 00857 while (i < n_fds) 00858 { 00859 callback_unref (&watches_for_fds[i]->callback); 00860 ++i; 00861 } 00862 00863 if (watches_for_fds != stack_watches_for_fds) 00864 dbus_free (watches_for_fds); 00865 } 00866 00867 if (_dbus_loop_dispatch (loop)) 00868 retval = TRUE; 00869 00870 #if MAINLOOP_SPEW 00871 _dbus_verbose ("Returning %d\n", retval); 00872 #endif 00873 00874 return retval; 00875 } 00876 00877 void 00878 _dbus_loop_run (DBusLoop *loop) 00879 { 00880 int our_exit_depth; 00881 00882 _dbus_assert (loop->depth >= 0); 00883 00884 _dbus_loop_ref (loop); 00885 00886 our_exit_depth = loop->depth; 00887 loop->depth += 1; 00888 00889 _dbus_verbose ("Running main loop, depth %d -> %d\n", 00890 loop->depth - 1, loop->depth); 00891 00892 while (loop->depth != our_exit_depth) 00893 _dbus_loop_iterate (loop, TRUE); 00894 00895 _dbus_loop_unref (loop); 00896 } 00897 00898 void 00899 _dbus_loop_quit (DBusLoop *loop) 00900 { 00901 _dbus_assert (loop->depth > 0); 00902 00903 loop->depth -= 1; 00904 00905 _dbus_verbose ("Quit main loop, depth %d -> %d\n", 00906 loop->depth + 1, loop->depth); 00907 } 00908 00909 int 00910 _dbus_get_oom_wait (void) 00911 { 00912 #ifdef DBUS_BUILD_TESTS 00913 /* make tests go fast */ 00914 return 0; 00915 #else 00916 return 500; 00917 #endif 00918 } 00919 00920 void 00921 _dbus_wait_for_memory (void) 00922 { 00923 _dbus_verbose ("Waiting for more memory\n"); 00924 _dbus_sleep_milliseconds (_dbus_get_oom_wait ()); 00925 } 00926 00927 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */