• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List

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 "dbus-internals.h"
00025 #include "dbus-watch.h"
00026 #include "dbus-list.h"
00027 
00039 struct DBusWatch
00040 {
00041   int refcount;                        
00042   int fd;                              
00043   unsigned int flags;                  
00045   DBusWatchHandler handler;                    
00046   void *handler_data;                          
00047   DBusFreeFunction free_handler_data_function; 
00049   void *data;                          
00050   DBusFreeFunction free_data_function; 
00051   unsigned int enabled : 1;            
00052 };
00053 
00054 dbus_bool_t
00055 _dbus_watch_get_enabled (DBusWatch *watch)
00056 {
00057   return watch->enabled;
00058 }
00059 
00072 DBusWatch*
00073 _dbus_watch_new (int               fd,
00074                  unsigned int      flags,
00075                  dbus_bool_t       enabled,
00076                  DBusWatchHandler  handler,
00077                  void             *data,
00078                  DBusFreeFunction  free_data_function)
00079 {
00080   DBusWatch *watch;
00081 
00082 #define VALID_WATCH_FLAGS (DBUS_WATCH_WRITABLE | DBUS_WATCH_READABLE)
00083   
00084   _dbus_assert ((flags & VALID_WATCH_FLAGS) == flags);
00085   
00086   watch = dbus_new0 (DBusWatch, 1);
00087   if (watch == NULL)
00088     return NULL;
00089   
00090   watch->refcount = 1;
00091   watch->fd = fd;
00092   watch->flags = flags;
00093   watch->enabled = enabled;
00094 
00095   watch->handler = handler;
00096   watch->handler_data = data;
00097   watch->free_handler_data_function = free_data_function;
00098   
00099   return watch;
00100 }
00101 
00108 DBusWatch *
00109 _dbus_watch_ref (DBusWatch *watch)
00110 {
00111   watch->refcount += 1;
00112 
00113   return watch;
00114 }
00115 
00122 void
00123 _dbus_watch_unref (DBusWatch *watch)
00124 {
00125   _dbus_assert (watch != NULL);
00126   _dbus_assert (watch->refcount > 0);
00127 
00128   watch->refcount -= 1;
00129   if (watch->refcount == 0)
00130     {
00131       dbus_watch_set_data (watch, NULL, NULL); /* call free_data_function */
00132 
00133       if (watch->free_handler_data_function)
00134         (* watch->free_handler_data_function) (watch->handler_data);
00135       
00136       dbus_free (watch);
00137     }
00138 }
00139 
00150 void
00151 _dbus_watch_invalidate (DBusWatch *watch)
00152 {
00153   watch->fd = -1;
00154   watch->flags = 0;
00155 }
00156 
00166 void
00167 _dbus_watch_sanitize_condition (DBusWatch    *watch,
00168                                 unsigned int *condition)
00169 {
00170   if (!(watch->flags & DBUS_WATCH_READABLE))
00171     *condition &= ~DBUS_WATCH_READABLE;
00172   if (!(watch->flags & DBUS_WATCH_WRITABLE))
00173     *condition &= ~DBUS_WATCH_WRITABLE;
00174 }
00175 
00176 
00196 struct DBusWatchList
00197 {
00198   DBusList *watches;           
00200   DBusAddWatchFunction add_watch_function;    
00201   DBusRemoveWatchFunction remove_watch_function; 
00202   DBusWatchToggledFunction watch_toggled_function; 
00203   void *watch_data;                           
00204   DBusFreeFunction watch_free_data_function;  
00205 };
00206 
00213 DBusWatchList*
00214 _dbus_watch_list_new (void)
00215 {
00216   DBusWatchList *watch_list;
00217 
00218   watch_list = dbus_new0 (DBusWatchList, 1);
00219   if (watch_list == NULL)
00220     return NULL;
00221 
00222   return watch_list;
00223 }
00224 
00230 void
00231 _dbus_watch_list_free (DBusWatchList *watch_list)
00232 {
00233   /* free watch_data and removes watches as a side effect */
00234   _dbus_watch_list_set_functions (watch_list,
00235                                   NULL, NULL, NULL, NULL, NULL);
00236   _dbus_list_foreach (&watch_list->watches,
00237                       (DBusForeachFunction) _dbus_watch_unref,
00238                       NULL);
00239   _dbus_list_clear (&watch_list->watches);
00240 
00241   dbus_free (watch_list);
00242 }
00243 
00258 dbus_bool_t
00259 _dbus_watch_list_set_functions (DBusWatchList           *watch_list,
00260                                 DBusAddWatchFunction     add_function,
00261                                 DBusRemoveWatchFunction  remove_function,
00262                                 DBusWatchToggledFunction toggled_function,
00263                                 void                    *data,
00264                                 DBusFreeFunction         free_data_function)
00265 {
00266   /* Add watches with the new watch function, failing on OOM */
00267   if (add_function != NULL)
00268     {
00269       DBusList *link;
00270       
00271       link = _dbus_list_get_first_link (&watch_list->watches);
00272       while (link != NULL)
00273         {
00274           DBusList *next = _dbus_list_get_next_link (&watch_list->watches,
00275                                                      link);
00276 
00277 #ifdef DBUS_ENABLE_VERBOSE_MODE
00278           {
00279             const char *watch_type;
00280             int flags;
00281 
00282             flags = dbus_watch_get_flags (link->data);
00283             if ((flags & DBUS_WATCH_READABLE) &&
00284                 (flags & DBUS_WATCH_WRITABLE))
00285               watch_type = "readwrite";
00286             else if (flags & DBUS_WATCH_READABLE)
00287               watch_type = "read";
00288             else if (flags & DBUS_WATCH_WRITABLE)
00289               watch_type = "write";
00290             else
00291               watch_type = "not read or write";
00292             
00293             _dbus_verbose ("Adding a %s watch on fd %d using newly-set add watch function\n",
00294                            watch_type,
00295                            dbus_watch_get_socket (link->data));
00296           }
00297 #endif /* DBUS_ENABLE_VERBOSE_MODE */
00298           
00299           if (!(* add_function) (link->data, data))
00300             {
00301               /* remove it all again and return FALSE */
00302               DBusList *link2;
00303               
00304               link2 = _dbus_list_get_first_link (&watch_list->watches);
00305               while (link2 != link)
00306                 {
00307                   DBusList *next = _dbus_list_get_next_link (&watch_list->watches,
00308                                                              link2);
00309                   
00310                   _dbus_verbose ("Removing watch on fd %d using newly-set remove function because initial add failed\n",
00311                                  dbus_watch_get_socket (link2->data));
00312                   
00313                   (* remove_function) (link2->data, data);
00314                   
00315                   link2 = next;
00316                 }
00317 
00318               return FALSE;
00319             }
00320       
00321           link = next;
00322         }
00323     }
00324   
00325   /* Remove all current watches from previous watch handlers */
00326 
00327   if (watch_list->remove_watch_function != NULL)
00328     {
00329       _dbus_verbose ("Removing all pre-existing watches\n");
00330       
00331       _dbus_list_foreach (&watch_list->watches,
00332                           (DBusForeachFunction) watch_list->remove_watch_function,
00333                           watch_list->watch_data);
00334     }
00335 
00336   if (watch_list->watch_free_data_function != NULL)
00337     (* watch_list->watch_free_data_function) (watch_list->watch_data);
00338   
00339   watch_list->add_watch_function = add_function;
00340   watch_list->remove_watch_function = remove_function;
00341   watch_list->watch_toggled_function = toggled_function;
00342   watch_list->watch_data = data;
00343   watch_list->watch_free_data_function = free_data_function;
00344 
00345   return TRUE;
00346 }
00347 
00356 dbus_bool_t
00357 _dbus_watch_list_add_watch (DBusWatchList *watch_list,
00358                             DBusWatch     *watch)
00359 {
00360   if (!_dbus_list_append (&watch_list->watches, watch))
00361     return FALSE;
00362   
00363   _dbus_watch_ref (watch);
00364 
00365   if (watch_list->add_watch_function != NULL)
00366     {
00367       _dbus_verbose ("Adding watch on fd %d\n",
00368                      dbus_watch_get_socket (watch));
00369       
00370       if (!(* watch_list->add_watch_function) (watch,
00371                                                watch_list->watch_data))
00372         {
00373           _dbus_list_remove_last (&watch_list->watches, watch);
00374           _dbus_watch_unref (watch);
00375           return FALSE;
00376         }
00377     }
00378   
00379   return TRUE;
00380 }
00381 
00389 void
00390 _dbus_watch_list_remove_watch  (DBusWatchList *watch_list,
00391                                 DBusWatch     *watch)
00392 {
00393   if (!_dbus_list_remove (&watch_list->watches, watch))
00394     _dbus_assert_not_reached ("Nonexistent watch was removed");
00395   
00396   if (watch_list->remove_watch_function != NULL)
00397     {
00398       _dbus_verbose ("Removing watch on fd %d\n",
00399                      dbus_watch_get_socket (watch));
00400       
00401       (* watch_list->remove_watch_function) (watch,
00402                                              watch_list->watch_data);
00403     }
00404   
00405   _dbus_watch_unref (watch);
00406 }
00407 
00416 void
00417 _dbus_watch_list_toggle_watch (DBusWatchList           *watch_list,
00418                                DBusWatch               *watch,
00419                                dbus_bool_t              enabled)
00420 {
00421   enabled = !!enabled;
00422   
00423   if (enabled == watch->enabled)
00424     return;
00425 
00426   watch->enabled = enabled;
00427   
00428   if (watch_list->watch_toggled_function != NULL)
00429     {
00430       _dbus_verbose ("Toggling watch %p on fd %d to %d\n",
00431                      watch, dbus_watch_get_socket (watch), watch->enabled);
00432       
00433       (* watch_list->watch_toggled_function) (watch,
00434                                               watch_list->watch_data);
00435     }
00436 }
00437 
00445 void
00446 _dbus_watch_list_toggle_all_watches (DBusWatchList           *watch_list,
00447                                      dbus_bool_t              enabled)
00448 {
00449   DBusList *link;
00450 
00451   for (link = _dbus_list_get_first_link (&watch_list->watches);
00452        link != NULL;
00453        link = _dbus_list_get_next_link (&watch_list->watches, link))
00454     {
00455       _dbus_watch_list_toggle_watch (watch_list, link->data, enabled);
00456     }
00457 }
00458 
00471 void
00472 _dbus_watch_set_handler (DBusWatch        *watch,
00473                          DBusWatchHandler  handler,
00474                          void             *data,
00475                          DBusFreeFunction  free_data_function)
00476 {
00477   if (watch->free_handler_data_function)
00478     (* watch->free_handler_data_function) (watch->handler_data);
00479 
00480   watch->handler = handler;
00481   watch->handler_data = data;
00482   watch->free_handler_data_function = free_data_function;
00483 }
00484 
00516 int
00517 dbus_watch_get_fd (DBusWatch *watch)
00518 {
00519   return dbus_watch_get_unix_fd(watch);
00520 }
00521 
00535 int
00536 dbus_watch_get_unix_fd (DBusWatch *watch)
00537 {
00538   /* FIXME remove #ifdef and do this on a lower level
00539    * (watch should have set_socket and set_unix_fd and track
00540    * which it has, and the transport should provide the
00541    * appropriate watch type)
00542    */
00543 #ifdef DBUS_UNIX
00544   return watch->fd;
00545 #else
00546   return -1;
00547 #endif
00548 }
00549 
00562 int
00563 dbus_watch_get_socket (DBusWatch *watch)
00564 {
00565   return watch->fd;
00566 }
00567 
00581 unsigned int
00582 dbus_watch_get_flags (DBusWatch *watch)
00583 {
00584   _dbus_assert ((watch->flags & VALID_WATCH_FLAGS) == watch->flags);
00585 
00586   return watch->flags;
00587 }
00588 
00596 void*
00597 dbus_watch_get_data (DBusWatch *watch)
00598 {
00599   return watch->data;
00600 }
00601 
00613 void
00614 dbus_watch_set_data (DBusWatch        *watch,
00615                      void             *data,
00616                      DBusFreeFunction  free_data_function)
00617 {
00618   _dbus_verbose ("Setting watch fd %d data to data = %p function = %p from data = %p function = %p\n",
00619                  dbus_watch_get_socket (watch),
00620                  data, free_data_function, watch->data, watch->free_data_function);
00621   
00622   if (watch->free_data_function != NULL)
00623     (* watch->free_data_function) (watch->data);
00624   
00625   watch->data = data;
00626   watch->free_data_function = free_data_function;
00627 }
00628 
00636 dbus_bool_t
00637 dbus_watch_get_enabled (DBusWatch *watch)
00638 {
00639   _dbus_assert (watch != NULL);
00640   return watch->enabled;
00641 }
00642 
00643 
00666 dbus_bool_t
00667 dbus_watch_handle (DBusWatch    *watch,
00668                    unsigned int  flags)
00669 {
00670 #ifndef DBUS_DISABLE_CHECKS
00671   if (watch->fd < 0 || watch->flags == 0)
00672     {
00673       _dbus_warn_check_failed ("%s: Watch is invalid, it should have been removed\n",
00674                                _DBUS_FUNCTION_NAME);
00675       return TRUE;
00676     }
00677 #endif
00678     
00679   _dbus_return_val_if_fail (watch->fd >= 0 /* fails if watch was removed */, TRUE);
00680   
00681   _dbus_watch_sanitize_condition (watch, &flags);
00682 
00683   if (flags == 0)
00684     {
00685       _dbus_verbose ("After sanitization, watch flags on fd %d were 0\n",
00686                      watch->fd);
00687       return TRUE;
00688     }
00689   else
00690     return (* watch->handler) (watch, flags,
00691                                watch->handler_data);
00692 }
00693 
00694 

Generated on Wed Nov 19 2014 17:15:21 for D-Bus by  doxygen 1.7.1