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