D-Bus
1.10.12
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-watch.c DBusWatch implementation 00003 * 00004 * Copyright (C) 2002, 2003 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-internals.h" 00026 #include "dbus-watch.h" 00027 #include "dbus-list.h" 00028 00040 struct DBusWatch 00041 { 00042 int refcount; 00043 DBusPollable fd; 00044 unsigned int flags; 00046 DBusWatchHandler handler; 00047 void *handler_data; 00048 DBusFreeFunction free_handler_data_function; 00050 void *data; 00051 DBusFreeFunction free_data_function; 00052 unsigned int enabled : 1; 00053 unsigned int oom_last_time : 1; 00054 }; 00055 00056 dbus_bool_t 00057 _dbus_watch_get_enabled (DBusWatch *watch) 00058 { 00059 return watch->enabled; 00060 } 00061 00062 dbus_bool_t 00063 _dbus_watch_get_oom_last_time (DBusWatch *watch) 00064 { 00065 return watch->oom_last_time; 00066 } 00067 00068 void 00069 _dbus_watch_set_oom_last_time (DBusWatch *watch, 00070 dbus_bool_t oom) 00071 { 00072 watch->oom_last_time = oom; 00073 } 00074 00087 DBusWatch* 00088 _dbus_watch_new (DBusPollable fd, 00089 unsigned int flags, 00090 dbus_bool_t enabled, 00091 DBusWatchHandler handler, 00092 void *data, 00093 DBusFreeFunction free_data_function) 00094 { 00095 DBusWatch *watch; 00096 00097 #define VALID_WATCH_FLAGS (DBUS_WATCH_WRITABLE | DBUS_WATCH_READABLE) 00098 00099 _dbus_assert ((flags & VALID_WATCH_FLAGS) == flags); 00100 00101 watch = dbus_new0 (DBusWatch, 1); 00102 if (watch == NULL) 00103 return NULL; 00104 00105 watch->refcount = 1; 00106 watch->fd = fd; 00107 watch->flags = flags; 00108 watch->enabled = enabled; 00109 00110 watch->handler = handler; 00111 watch->handler_data = data; 00112 watch->free_handler_data_function = free_data_function; 00113 00114 return watch; 00115 } 00116 00123 DBusWatch * 00124 _dbus_watch_ref (DBusWatch *watch) 00125 { 00126 watch->refcount += 1; 00127 00128 return watch; 00129 } 00130 00137 void 00138 _dbus_watch_unref (DBusWatch *watch) 00139 { 00140 _dbus_assert (watch != NULL); 00141 _dbus_assert (watch->refcount > 0); 00142 00143 watch->refcount -= 1; 00144 if (watch->refcount == 0) 00145 { 00146 if (_dbus_pollable_is_valid (watch->fd)) 00147 _dbus_warn ("this watch should have been invalidated"); 00148 00149 dbus_watch_set_data (watch, NULL, NULL); /* call free_data_function */ 00150 00151 if (watch->free_handler_data_function) 00152 (* watch->free_handler_data_function) (watch->handler_data); 00153 00154 dbus_free (watch); 00155 } 00156 } 00157 00168 void 00169 _dbus_watch_invalidate (DBusWatch *watch) 00170 { 00171 _dbus_pollable_invalidate (&watch->fd); 00172 watch->flags = 0; 00173 } 00174 00184 void 00185 _dbus_watch_sanitize_condition (DBusWatch *watch, 00186 unsigned int *condition) 00187 { 00188 if (!(watch->flags & DBUS_WATCH_READABLE)) 00189 *condition &= ~DBUS_WATCH_READABLE; 00190 if (!(watch->flags & DBUS_WATCH_WRITABLE)) 00191 *condition &= ~DBUS_WATCH_WRITABLE; 00192 } 00193 00194 00214 struct DBusWatchList 00215 { 00216 DBusList *watches; 00218 DBusAddWatchFunction add_watch_function; 00219 DBusRemoveWatchFunction remove_watch_function; 00220 DBusWatchToggledFunction watch_toggled_function; 00221 void *watch_data; 00222 DBusFreeFunction watch_free_data_function; 00223 }; 00224 00231 DBusWatchList* 00232 _dbus_watch_list_new (void) 00233 { 00234 DBusWatchList *watch_list; 00235 00236 watch_list = dbus_new0 (DBusWatchList, 1); 00237 if (watch_list == NULL) 00238 return NULL; 00239 00240 return watch_list; 00241 } 00242 00248 void 00249 _dbus_watch_list_free (DBusWatchList *watch_list) 00250 { 00251 /* free watch_data and removes watches as a side effect */ 00252 _dbus_watch_list_set_functions (watch_list, 00253 NULL, NULL, NULL, NULL, NULL); 00254 _dbus_list_foreach (&watch_list->watches, 00255 (DBusForeachFunction) _dbus_watch_unref, 00256 NULL); 00257 _dbus_list_clear (&watch_list->watches); 00258 00259 dbus_free (watch_list); 00260 } 00261 00262 #ifdef DBUS_ENABLE_VERBOSE_MODE 00263 static const char* 00264 watch_flags_to_string (int flags) 00265 { 00266 const char *watch_type; 00267 00268 if ((flags & DBUS_WATCH_READABLE) && 00269 (flags & DBUS_WATCH_WRITABLE)) 00270 watch_type = "readwrite"; 00271 else if (flags & DBUS_WATCH_READABLE) 00272 watch_type = "read"; 00273 else if (flags & DBUS_WATCH_WRITABLE) 00274 watch_type = "write"; 00275 else 00276 watch_type = "not read or write"; 00277 return watch_type; 00278 } 00279 #endif /* DBUS_ENABLE_VERBOSE_MODE */ 00280 00295 dbus_bool_t 00296 _dbus_watch_list_set_functions (DBusWatchList *watch_list, 00297 DBusAddWatchFunction add_function, 00298 DBusRemoveWatchFunction remove_function, 00299 DBusWatchToggledFunction toggled_function, 00300 void *data, 00301 DBusFreeFunction free_data_function) 00302 { 00303 /* Add watches with the new watch function, failing on OOM */ 00304 if (add_function != NULL) 00305 { 00306 DBusList *link; 00307 00308 link = _dbus_list_get_first_link (&watch_list->watches); 00309 while (link != NULL) 00310 { 00311 DBusList *next = _dbus_list_get_next_link (&watch_list->watches, 00312 link); 00313 #ifdef DBUS_ENABLE_VERBOSE_MODE 00314 DBusWatch *watch = link->data; 00315 00316 _dbus_verbose ("Adding a %s watch on fd %" DBUS_POLLABLE_FORMAT " using newly-set add watch function\n", 00317 watch_flags_to_string (dbus_watch_get_flags (link->data)), 00318 _dbus_pollable_printable (watch->fd)); 00319 #endif 00320 00321 if (!(* add_function) (link->data, data)) 00322 { 00323 /* remove it all again and return FALSE */ 00324 DBusList *link2; 00325 00326 link2 = _dbus_list_get_first_link (&watch_list->watches); 00327 while (link2 != link) 00328 { 00329 DBusList *next = _dbus_list_get_next_link (&watch_list->watches, 00330 link2); 00331 #ifdef DBUS_ENABLE_VERBOSE_MODE 00332 DBusWatch *watch2 = link2->data; 00333 00334 _dbus_verbose ("Removing watch on fd %" DBUS_POLLABLE_FORMAT " using newly-set remove function because initial add failed\n", 00335 _dbus_pollable_printable (watch2->fd)); 00336 #endif 00337 00338 (* remove_function) (link2->data, data); 00339 00340 link2 = next; 00341 } 00342 00343 return FALSE; 00344 } 00345 00346 link = next; 00347 } 00348 } 00349 00350 /* Remove all current watches from previous watch handlers */ 00351 00352 if (watch_list->remove_watch_function != NULL) 00353 { 00354 _dbus_verbose ("Removing all pre-existing watches\n"); 00355 00356 _dbus_list_foreach (&watch_list->watches, 00357 (DBusForeachFunction) watch_list->remove_watch_function, 00358 watch_list->watch_data); 00359 } 00360 00361 if (watch_list->watch_free_data_function != NULL) 00362 (* watch_list->watch_free_data_function) (watch_list->watch_data); 00363 00364 watch_list->add_watch_function = add_function; 00365 watch_list->remove_watch_function = remove_function; 00366 watch_list->watch_toggled_function = toggled_function; 00367 watch_list->watch_data = data; 00368 watch_list->watch_free_data_function = free_data_function; 00369 00370 return TRUE; 00371 } 00372 00381 dbus_bool_t 00382 _dbus_watch_list_add_watch (DBusWatchList *watch_list, 00383 DBusWatch *watch) 00384 { 00385 if (!_dbus_list_append (&watch_list->watches, watch)) 00386 return FALSE; 00387 00388 _dbus_watch_ref (watch); 00389 00390 if (watch_list->add_watch_function != NULL) 00391 { 00392 _dbus_verbose ("Adding watch on fd %" DBUS_POLLABLE_FORMAT "\n", 00393 _dbus_pollable_printable (watch->fd)); 00394 00395 if (!(* watch_list->add_watch_function) (watch, 00396 watch_list->watch_data)) 00397 { 00398 _dbus_list_remove_last (&watch_list->watches, watch); 00399 _dbus_watch_unref (watch); 00400 return FALSE; 00401 } 00402 } 00403 00404 return TRUE; 00405 } 00406 00414 void 00415 _dbus_watch_list_remove_watch (DBusWatchList *watch_list, 00416 DBusWatch *watch) 00417 { 00418 if (!_dbus_list_remove (&watch_list->watches, watch)) 00419 _dbus_assert_not_reached ("Nonexistent watch was removed"); 00420 00421 if (watch_list->remove_watch_function != NULL) 00422 { 00423 _dbus_verbose ("Removing watch on fd %" DBUS_POLLABLE_FORMAT "\n", 00424 _dbus_pollable_printable (watch->fd)); 00425 00426 (* watch_list->remove_watch_function) (watch, 00427 watch_list->watch_data); 00428 } 00429 00430 _dbus_watch_unref (watch); 00431 } 00432 00441 void 00442 _dbus_watch_list_toggle_watch (DBusWatchList *watch_list, 00443 DBusWatch *watch, 00444 dbus_bool_t enabled) 00445 { 00446 enabled = !!enabled; 00447 00448 if (enabled == watch->enabled) 00449 return; 00450 00451 watch->enabled = enabled; 00452 00453 if (watch_list->watch_toggled_function != NULL) 00454 { 00455 _dbus_verbose ("Toggling watch %p on fd %" DBUS_POLLABLE_FORMAT " to %d\n", 00456 watch, 00457 _dbus_pollable_printable (watch->fd), 00458 watch->enabled); 00459 00460 (* watch_list->watch_toggled_function) (watch, 00461 watch_list->watch_data); 00462 } 00463 } 00464 00472 void 00473 _dbus_watch_list_toggle_all_watches (DBusWatchList *watch_list, 00474 dbus_bool_t enabled) 00475 { 00476 DBusList *link; 00477 00478 for (link = _dbus_list_get_first_link (&watch_list->watches); 00479 link != NULL; 00480 link = _dbus_list_get_next_link (&watch_list->watches, link)) 00481 { 00482 _dbus_watch_list_toggle_watch (watch_list, link->data, enabled); 00483 } 00484 } 00485 00498 void 00499 _dbus_watch_set_handler (DBusWatch *watch, 00500 DBusWatchHandler handler, 00501 void *data, 00502 DBusFreeFunction free_data_function) 00503 { 00504 if (watch->free_handler_data_function) 00505 (* watch->free_handler_data_function) (watch->handler_data); 00506 00507 watch->handler = handler; 00508 watch->handler_data = data; 00509 watch->free_handler_data_function = free_data_function; 00510 } 00511 00543 int 00544 dbus_watch_get_fd (DBusWatch *watch) 00545 { 00546 _dbus_return_val_if_fail (watch != NULL, -1); 00547 00548 return dbus_watch_get_unix_fd(watch); 00549 } 00550 00564 int 00565 dbus_watch_get_unix_fd (DBusWatch *watch) 00566 { 00567 _dbus_return_val_if_fail (watch != NULL, -1); 00568 00569 /* FIXME remove #ifdef and do this on a lower level 00570 * (watch should have set_socket and set_unix_fd and track 00571 * which it has, and the transport should provide the 00572 * appropriate watch type) 00573 */ 00574 #ifdef DBUS_UNIX 00575 return watch->fd; 00576 #else 00577 return dbus_watch_get_socket( watch ); 00578 #endif 00579 } 00580 00593 int 00594 dbus_watch_get_socket (DBusWatch *watch) 00595 { 00596 _dbus_return_val_if_fail (watch != NULL, -1); 00597 00598 #ifdef DBUS_UNIX 00599 return watch->fd; 00600 #else 00601 return _dbus_socket_get_int (watch->fd); 00602 #endif 00603 } 00604 00605 DBusSocket 00606 _dbus_watch_get_socket (DBusWatch *watch) 00607 { 00608 DBusSocket s; 00609 00610 _dbus_assert (watch != NULL); 00611 00612 #ifdef DBUS_UNIX 00613 s.fd = watch->fd; 00614 #else 00615 s = watch->fd; 00616 #endif 00617 00618 return s; 00619 } 00620 00621 DBusPollable 00622 _dbus_watch_get_pollable (DBusWatch *watch) 00623 { 00624 _dbus_assert (watch != NULL); 00625 00626 return watch->fd; 00627 } 00628 00642 unsigned int 00643 dbus_watch_get_flags (DBusWatch *watch) 00644 { 00645 _dbus_return_val_if_fail (watch != NULL, 0); 00646 _dbus_assert ((watch->flags & VALID_WATCH_FLAGS) == watch->flags); 00647 00648 return watch->flags; 00649 } 00650 00658 void* 00659 dbus_watch_get_data (DBusWatch *watch) 00660 { 00661 _dbus_return_val_if_fail (watch != NULL, NULL); 00662 00663 return watch->data; 00664 } 00665 00677 void 00678 dbus_watch_set_data (DBusWatch *watch, 00679 void *data, 00680 DBusFreeFunction free_data_function) 00681 { 00682 _dbus_return_if_fail (watch != NULL); 00683 00684 _dbus_verbose ("Setting watch fd %" DBUS_POLLABLE_FORMAT " data to data = %p function = %p from data = %p function = %p\n", 00685 _dbus_pollable_printable (watch->fd), 00686 data, free_data_function, watch->data, watch->free_data_function); 00687 00688 if (watch->free_data_function != NULL) 00689 (* watch->free_data_function) (watch->data); 00690 00691 watch->data = data; 00692 watch->free_data_function = free_data_function; 00693 } 00694 00702 dbus_bool_t 00703 dbus_watch_get_enabled (DBusWatch *watch) 00704 { 00705 _dbus_return_val_if_fail (watch != NULL, FALSE); 00706 00707 return watch->enabled; 00708 } 00709 00710 00733 dbus_bool_t 00734 dbus_watch_handle (DBusWatch *watch, 00735 unsigned int flags) 00736 { 00737 _dbus_return_val_if_fail (watch != NULL, FALSE); 00738 00739 #ifndef DBUS_DISABLE_CHECKS 00740 if (!_dbus_pollable_is_valid (watch->fd) || watch->flags == 0) 00741 { 00742 _dbus_warn_check_failed ("Watch is invalid, it should have been removed\n"); 00743 return TRUE; 00744 } 00745 #endif 00746 00747 _dbus_return_val_if_fail (_dbus_pollable_is_valid (watch->fd) /* fails if watch was removed */, TRUE); 00748 00749 _dbus_watch_sanitize_condition (watch, &flags); 00750 00751 if (flags == 0) 00752 { 00753 _dbus_verbose ("After sanitization, watch flags on fd %" DBUS_POLLABLE_FORMAT " were 0\n", 00754 _dbus_pollable_printable (watch->fd)); 00755 return TRUE; 00756 } 00757 else 00758 return (* watch->handler) (watch, flags, 00759 watch->handler_data); 00760 } 00761 00762