|
D-Bus
1.8.20
|
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 int 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 (int 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 (watch->fd != -1) 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 watch->fd = -1; 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 00314 _dbus_verbose ("Adding a %s watch on fd %d using newly-set add watch function\n", 00315 watch_flags_to_string (dbus_watch_get_flags (link->data)), 00316 dbus_watch_get_socket (link->data)); 00317 00318 if (!(* add_function) (link->data, data)) 00319 { 00320 /* remove it all again and return FALSE */ 00321 DBusList *link2; 00322 00323 link2 = _dbus_list_get_first_link (&watch_list->watches); 00324 while (link2 != link) 00325 { 00326 DBusList *next = _dbus_list_get_next_link (&watch_list->watches, 00327 link2); 00328 00329 _dbus_verbose ("Removing watch on fd %d using newly-set remove function because initial add failed\n", 00330 dbus_watch_get_socket (link2->data)); 00331 00332 (* remove_function) (link2->data, data); 00333 00334 link2 = next; 00335 } 00336 00337 return FALSE; 00338 } 00339 00340 link = next; 00341 } 00342 } 00343 00344 /* Remove all current watches from previous watch handlers */ 00345 00346 if (watch_list->remove_watch_function != NULL) 00347 { 00348 _dbus_verbose ("Removing all pre-existing watches\n"); 00349 00350 _dbus_list_foreach (&watch_list->watches, 00351 (DBusForeachFunction) watch_list->remove_watch_function, 00352 watch_list->watch_data); 00353 } 00354 00355 if (watch_list->watch_free_data_function != NULL) 00356 (* watch_list->watch_free_data_function) (watch_list->watch_data); 00357 00358 watch_list->add_watch_function = add_function; 00359 watch_list->remove_watch_function = remove_function; 00360 watch_list->watch_toggled_function = toggled_function; 00361 watch_list->watch_data = data; 00362 watch_list->watch_free_data_function = free_data_function; 00363 00364 return TRUE; 00365 } 00366 00375 dbus_bool_t 00376 _dbus_watch_list_add_watch (DBusWatchList *watch_list, 00377 DBusWatch *watch) 00378 { 00379 if (!_dbus_list_append (&watch_list->watches, watch)) 00380 return FALSE; 00381 00382 _dbus_watch_ref (watch); 00383 00384 if (watch_list->add_watch_function != NULL) 00385 { 00386 _dbus_verbose ("Adding watch on fd %d\n", 00387 dbus_watch_get_socket (watch)); 00388 00389 if (!(* watch_list->add_watch_function) (watch, 00390 watch_list->watch_data)) 00391 { 00392 _dbus_list_remove_last (&watch_list->watches, watch); 00393 _dbus_watch_unref (watch); 00394 return FALSE; 00395 } 00396 } 00397 00398 return TRUE; 00399 } 00400 00408 void 00409 _dbus_watch_list_remove_watch (DBusWatchList *watch_list, 00410 DBusWatch *watch) 00411 { 00412 if (!_dbus_list_remove (&watch_list->watches, watch)) 00413 _dbus_assert_not_reached ("Nonexistent watch was removed"); 00414 00415 if (watch_list->remove_watch_function != NULL) 00416 { 00417 _dbus_verbose ("Removing watch on fd %d\n", 00418 dbus_watch_get_socket (watch)); 00419 00420 (* watch_list->remove_watch_function) (watch, 00421 watch_list->watch_data); 00422 } 00423 00424 _dbus_watch_unref (watch); 00425 } 00426 00435 void 00436 _dbus_watch_list_toggle_watch (DBusWatchList *watch_list, 00437 DBusWatch *watch, 00438 dbus_bool_t enabled) 00439 { 00440 enabled = !!enabled; 00441 00442 if (enabled == watch->enabled) 00443 return; 00444 00445 watch->enabled = enabled; 00446 00447 if (watch_list->watch_toggled_function != NULL) 00448 { 00449 _dbus_verbose ("Toggling watch %p on fd %d to %d\n", 00450 watch, dbus_watch_get_socket (watch), watch->enabled); 00451 00452 (* watch_list->watch_toggled_function) (watch, 00453 watch_list->watch_data); 00454 } 00455 } 00456 00464 void 00465 _dbus_watch_list_toggle_all_watches (DBusWatchList *watch_list, 00466 dbus_bool_t enabled) 00467 { 00468 DBusList *link; 00469 00470 for (link = _dbus_list_get_first_link (&watch_list->watches); 00471 link != NULL; 00472 link = _dbus_list_get_next_link (&watch_list->watches, link)) 00473 { 00474 _dbus_watch_list_toggle_watch (watch_list, link->data, enabled); 00475 } 00476 } 00477 00490 void 00491 _dbus_watch_set_handler (DBusWatch *watch, 00492 DBusWatchHandler handler, 00493 void *data, 00494 DBusFreeFunction free_data_function) 00495 { 00496 if (watch->free_handler_data_function) 00497 (* watch->free_handler_data_function) (watch->handler_data); 00498 00499 watch->handler = handler; 00500 watch->handler_data = data; 00501 watch->free_handler_data_function = free_data_function; 00502 } 00503 00535 int 00536 dbus_watch_get_fd (DBusWatch *watch) 00537 { 00538 _dbus_return_val_if_fail (watch != NULL, -1); 00539 00540 return dbus_watch_get_unix_fd(watch); 00541 } 00542 00556 int 00557 dbus_watch_get_unix_fd (DBusWatch *watch) 00558 { 00559 _dbus_return_val_if_fail (watch != NULL, -1); 00560 00561 /* FIXME remove #ifdef and do this on a lower level 00562 * (watch should have set_socket and set_unix_fd and track 00563 * which it has, and the transport should provide the 00564 * appropriate watch type) 00565 */ 00566 #ifdef DBUS_UNIX 00567 return watch->fd; 00568 #else 00569 return dbus_watch_get_socket( watch ); 00570 #endif 00571 } 00572 00585 int 00586 dbus_watch_get_socket (DBusWatch *watch) 00587 { 00588 _dbus_return_val_if_fail (watch != NULL, -1); 00589 00590 return watch->fd; 00591 } 00592 00606 unsigned int 00607 dbus_watch_get_flags (DBusWatch *watch) 00608 { 00609 _dbus_return_val_if_fail (watch != NULL, 0); 00610 _dbus_assert ((watch->flags & VALID_WATCH_FLAGS) == watch->flags); 00611 00612 return watch->flags; 00613 } 00614 00622 void* 00623 dbus_watch_get_data (DBusWatch *watch) 00624 { 00625 _dbus_return_val_if_fail (watch != NULL, NULL); 00626 00627 return watch->data; 00628 } 00629 00641 void 00642 dbus_watch_set_data (DBusWatch *watch, 00643 void *data, 00644 DBusFreeFunction free_data_function) 00645 { 00646 _dbus_return_if_fail (watch != NULL); 00647 00648 _dbus_verbose ("Setting watch fd %d data to data = %p function = %p from data = %p function = %p\n", 00649 dbus_watch_get_socket (watch), 00650 data, free_data_function, watch->data, watch->free_data_function); 00651 00652 if (watch->free_data_function != NULL) 00653 (* watch->free_data_function) (watch->data); 00654 00655 watch->data = data; 00656 watch->free_data_function = free_data_function; 00657 } 00658 00666 dbus_bool_t 00667 dbus_watch_get_enabled (DBusWatch *watch) 00668 { 00669 _dbus_return_val_if_fail (watch != NULL, FALSE); 00670 00671 return watch->enabled; 00672 } 00673 00674 00697 dbus_bool_t 00698 dbus_watch_handle (DBusWatch *watch, 00699 unsigned int flags) 00700 { 00701 _dbus_return_val_if_fail (watch != NULL, FALSE); 00702 00703 #ifndef DBUS_DISABLE_CHECKS 00704 if (watch->fd < 0 || watch->flags == 0) 00705 { 00706 _dbus_warn_check_failed ("Watch is invalid, it should have been removed\n"); 00707 return TRUE; 00708 } 00709 #endif 00710 00711 _dbus_return_val_if_fail (watch->fd >= 0 /* fails if watch was removed */, TRUE); 00712 00713 _dbus_watch_sanitize_condition (watch, &flags); 00714 00715 if (flags == 0) 00716 { 00717 _dbus_verbose ("After sanitization, watch flags on fd %d were 0\n", 00718 watch->fd); 00719 return TRUE; 00720 } 00721 else 00722 return (* watch->handler) (watch, flags, 00723 watch->handler_data); 00724 } 00725 00726
1.7.6.1