D-Bus  1.10.12
dbus-watch.c
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