• 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 <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 

Generated on Fri Jul 11 2014 20:42:04 for D-Bus by  doxygen 1.7.1