D-Bus 1.6.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 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 00276 dbus_bool_t 00277 _dbus_watch_list_set_functions (DBusWatchList *watch_list, 00278 DBusAddWatchFunction add_function, 00279 DBusRemoveWatchFunction remove_function, 00280 DBusWatchToggledFunction toggled_function, 00281 void *data, 00282 DBusFreeFunction free_data_function) 00283 { 00284 /* Add watches with the new watch function, failing on OOM */ 00285 if (add_function != NULL) 00286 { 00287 DBusList *link; 00288 00289 link = _dbus_list_get_first_link (&watch_list->watches); 00290 while (link != NULL) 00291 { 00292 DBusList *next = _dbus_list_get_next_link (&watch_list->watches, 00293 link); 00294 00295 #ifdef DBUS_ENABLE_VERBOSE_MODE 00296 { 00297 const char *watch_type; 00298 int flags; 00299 00300 flags = dbus_watch_get_flags (link->data); 00301 if ((flags & DBUS_WATCH_READABLE) && 00302 (flags & DBUS_WATCH_WRITABLE)) 00303 watch_type = "readwrite"; 00304 else if (flags & DBUS_WATCH_READABLE) 00305 watch_type = "read"; 00306 else if (flags & DBUS_WATCH_WRITABLE) 00307 watch_type = "write"; 00308 else 00309 watch_type = "not read or write"; 00310 00311 _dbus_verbose ("Adding a %s watch on fd %d using newly-set add watch function\n", 00312 watch_type, 00313 dbus_watch_get_socket (link->data)); 00314 } 00315 #endif /* DBUS_ENABLE_VERBOSE_MODE */ 00316 00317 if (!(* add_function) (link->data, data)) 00318 { 00319 /* remove it all again and return FALSE */ 00320 DBusList *link2; 00321 00322 link2 = _dbus_list_get_first_link (&watch_list->watches); 00323 while (link2 != link) 00324 { 00325 DBusList *next = _dbus_list_get_next_link (&watch_list->watches, 00326 link2); 00327 00328 _dbus_verbose ("Removing watch on fd %d using newly-set remove function because initial add failed\n", 00329 dbus_watch_get_socket (link2->data)); 00330 00331 (* remove_function) (link2->data, data); 00332 00333 link2 = next; 00334 } 00335 00336 return FALSE; 00337 } 00338 00339 link = next; 00340 } 00341 } 00342 00343 /* Remove all current watches from previous watch handlers */ 00344 00345 if (watch_list->remove_watch_function != NULL) 00346 { 00347 _dbus_verbose ("Removing all pre-existing watches\n"); 00348 00349 _dbus_list_foreach (&watch_list->watches, 00350 (DBusForeachFunction) watch_list->remove_watch_function, 00351 watch_list->watch_data); 00352 } 00353 00354 if (watch_list->watch_free_data_function != NULL) 00355 (* watch_list->watch_free_data_function) (watch_list->watch_data); 00356 00357 watch_list->add_watch_function = add_function; 00358 watch_list->remove_watch_function = remove_function; 00359 watch_list->watch_toggled_function = toggled_function; 00360 watch_list->watch_data = data; 00361 watch_list->watch_free_data_function = free_data_function; 00362 00363 return TRUE; 00364 } 00365 00374 dbus_bool_t 00375 _dbus_watch_list_add_watch (DBusWatchList *watch_list, 00376 DBusWatch *watch) 00377 { 00378 if (!_dbus_list_append (&watch_list->watches, watch)) 00379 return FALSE; 00380 00381 _dbus_watch_ref (watch); 00382 00383 if (watch_list->add_watch_function != NULL) 00384 { 00385 _dbus_verbose ("Adding watch on fd %d\n", 00386 dbus_watch_get_socket (watch)); 00387 00388 if (!(* watch_list->add_watch_function) (watch, 00389 watch_list->watch_data)) 00390 { 00391 _dbus_list_remove_last (&watch_list->watches, watch); 00392 _dbus_watch_unref (watch); 00393 return FALSE; 00394 } 00395 } 00396 00397 return TRUE; 00398 } 00399 00407 void 00408 _dbus_watch_list_remove_watch (DBusWatchList *watch_list, 00409 DBusWatch *watch) 00410 { 00411 if (!_dbus_list_remove (&watch_list->watches, watch)) 00412 _dbus_assert_not_reached ("Nonexistent watch was removed"); 00413 00414 if (watch_list->remove_watch_function != NULL) 00415 { 00416 _dbus_verbose ("Removing watch on fd %d\n", 00417 dbus_watch_get_socket (watch)); 00418 00419 (* watch_list->remove_watch_function) (watch, 00420 watch_list->watch_data); 00421 } 00422 00423 _dbus_watch_unref (watch); 00424 } 00425 00434 void 00435 _dbus_watch_list_toggle_watch (DBusWatchList *watch_list, 00436 DBusWatch *watch, 00437 dbus_bool_t enabled) 00438 { 00439 enabled = !!enabled; 00440 00441 if (enabled == watch->enabled) 00442 return; 00443 00444 watch->enabled = enabled; 00445 00446 if (watch_list->watch_toggled_function != NULL) 00447 { 00448 _dbus_verbose ("Toggling watch %p on fd %d to %d\n", 00449 watch, dbus_watch_get_socket (watch), watch->enabled); 00450 00451 (* watch_list->watch_toggled_function) (watch, 00452 watch_list->watch_data); 00453 } 00454 } 00455 00468 void 00469 _dbus_watch_set_handler (DBusWatch *watch, 00470 DBusWatchHandler handler, 00471 void *data, 00472 DBusFreeFunction free_data_function) 00473 { 00474 if (watch->free_handler_data_function) 00475 (* watch->free_handler_data_function) (watch->handler_data); 00476 00477 watch->handler = handler; 00478 watch->handler_data = data; 00479 watch->free_handler_data_function = free_data_function; 00480 } 00481 00513 int 00514 dbus_watch_get_fd (DBusWatch *watch) 00515 { 00516 _dbus_return_val_if_fail (watch != NULL, -1); 00517 00518 return dbus_watch_get_unix_fd(watch); 00519 } 00520 00534 int 00535 dbus_watch_get_unix_fd (DBusWatch *watch) 00536 { 00537 _dbus_return_val_if_fail (watch != NULL, -1); 00538 00539 /* FIXME remove #ifdef and do this on a lower level 00540 * (watch should have set_socket and set_unix_fd and track 00541 * which it has, and the transport should provide the 00542 * appropriate watch type) 00543 */ 00544 #ifdef DBUS_UNIX 00545 return watch->fd; 00546 #else 00547 return dbus_watch_get_socket( watch ); 00548 #endif 00549 } 00550 00563 int 00564 dbus_watch_get_socket (DBusWatch *watch) 00565 { 00566 _dbus_return_val_if_fail (watch != NULL, -1); 00567 00568 return watch->fd; 00569 } 00570 00584 unsigned int 00585 dbus_watch_get_flags (DBusWatch *watch) 00586 { 00587 _dbus_return_val_if_fail (watch != NULL, 0); 00588 _dbus_assert ((watch->flags & VALID_WATCH_FLAGS) == watch->flags); 00589 00590 return watch->flags; 00591 } 00592 00600 void* 00601 dbus_watch_get_data (DBusWatch *watch) 00602 { 00603 _dbus_return_val_if_fail (watch != NULL, NULL); 00604 00605 return watch->data; 00606 } 00607 00619 void 00620 dbus_watch_set_data (DBusWatch *watch, 00621 void *data, 00622 DBusFreeFunction free_data_function) 00623 { 00624 _dbus_return_if_fail (watch != NULL); 00625 00626 _dbus_verbose ("Setting watch fd %d data to data = %p function = %p from data = %p function = %p\n", 00627 dbus_watch_get_socket (watch), 00628 data, free_data_function, watch->data, watch->free_data_function); 00629 00630 if (watch->free_data_function != NULL) 00631 (* watch->free_data_function) (watch->data); 00632 00633 watch->data = data; 00634 watch->free_data_function = free_data_function; 00635 } 00636 00644 dbus_bool_t 00645 dbus_watch_get_enabled (DBusWatch *watch) 00646 { 00647 _dbus_return_val_if_fail (watch != NULL, FALSE); 00648 00649 return watch->enabled; 00650 } 00651 00652 00675 dbus_bool_t 00676 dbus_watch_handle (DBusWatch *watch, 00677 unsigned int flags) 00678 { 00679 _dbus_return_val_if_fail (watch != NULL, FALSE); 00680 00681 #ifndef DBUS_DISABLE_CHECKS 00682 if (watch->fd < 0 || watch->flags == 0) 00683 { 00684 _dbus_warn_check_failed ("Watch is invalid, it should have been removed\n"); 00685 return TRUE; 00686 } 00687 #endif 00688 00689 _dbus_return_val_if_fail (watch->fd >= 0 /* fails if watch was removed */, TRUE); 00690 00691 _dbus_watch_sanitize_condition (watch, &flags); 00692 00693 if (flags == 0) 00694 { 00695 _dbus_verbose ("After sanitization, watch flags on fd %d were 0\n", 00696 watch->fd); 00697 return TRUE; 00698 } 00699 else 00700 return (* watch->handler) (watch, flags, 00701 watch->handler_data); 00702 } 00703 00704