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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 
00066 DBusWatch*
00067 _dbus_watch_new (int               fd,
00068                  unsigned int      flags,
00069                  dbus_bool_t       enabled,
00070                  DBusWatchHandler  handler,
00071                  void             *data,
00072                  DBusFreeFunction  free_data_function)
00073 {
00074   DBusWatch *watch;
00075 
00076 #define VALID_WATCH_FLAGS (DBUS_WATCH_WRITABLE | DBUS_WATCH_READABLE)
00077   
00078   _dbus_assert ((flags & VALID_WATCH_FLAGS) == flags);
00079   
00080   watch = dbus_new0 (DBusWatch, 1);
00081   if (watch == NULL)
00082     return NULL;
00083   
00084   watch->refcount = 1;
00085   watch->fd = fd;
00086   watch->flags = flags;
00087   watch->enabled = enabled;
00088 
00089   watch->handler = handler;
00090   watch->handler_data = data;
00091   watch->free_handler_data_function = free_data_function;
00092   
00093   return watch;
00094 }
00095 
00102 DBusWatch *
00103 _dbus_watch_ref (DBusWatch *watch)
00104 {
00105   watch->refcount += 1;
00106 
00107   return watch;
00108 }
00109 
00116 void
00117 _dbus_watch_unref (DBusWatch *watch)
00118 {
00119   _dbus_assert (watch != NULL);
00120   _dbus_assert (watch->refcount > 0);
00121 
00122   watch->refcount -= 1;
00123   if (watch->refcount == 0)
00124     {
00125       dbus_watch_set_data (watch, NULL, NULL); /* call free_data_function */
00126 
00127       if (watch->free_handler_data_function)
00128         (* watch->free_handler_data_function) (watch->handler_data);
00129       
00130       dbus_free (watch);
00131     }
00132 }
00133 
00144 void
00145 _dbus_watch_invalidate (DBusWatch *watch)
00146 {
00147   watch->fd = -1;
00148   watch->flags = 0;
00149 }
00150 
00160 void
00161 _dbus_watch_sanitize_condition (DBusWatch    *watch,
00162                                 unsigned int *condition)
00163 {
00164   if (!(watch->flags & DBUS_WATCH_READABLE))
00165     *condition &= ~DBUS_WATCH_READABLE;
00166   if (!(watch->flags & DBUS_WATCH_WRITABLE))
00167     *condition &= ~DBUS_WATCH_WRITABLE;
00168 }
00169 
00170 
00190 struct DBusWatchList
00191 {
00192   DBusList *watches;           
00194   DBusAddWatchFunction add_watch_function;    
00195   DBusRemoveWatchFunction remove_watch_function; 
00196   DBusWatchToggledFunction watch_toggled_function; 
00197   void *watch_data;                           
00198   DBusFreeFunction watch_free_data_function;  
00199 };
00200 
00207 DBusWatchList*
00208 _dbus_watch_list_new (void)
00209 {
00210   DBusWatchList *watch_list;
00211 
00212   watch_list = dbus_new0 (DBusWatchList, 1);
00213   if (watch_list == NULL)
00214     return NULL;
00215 
00216   return watch_list;
00217 }
00218 
00224 void
00225 _dbus_watch_list_free (DBusWatchList *watch_list)
00226 {
00227   /* free watch_data and removes watches as a side effect */
00228   _dbus_watch_list_set_functions (watch_list,
00229                                   NULL, NULL, NULL, NULL, NULL);
00230   _dbus_list_foreach (&watch_list->watches,
00231                       (DBusForeachFunction) _dbus_watch_unref,
00232                       NULL);
00233   _dbus_list_clear (&watch_list->watches);
00234 
00235   dbus_free (watch_list);
00236 }
00237 
00252 dbus_bool_t
00253 _dbus_watch_list_set_functions (DBusWatchList           *watch_list,
00254                                 DBusAddWatchFunction     add_function,
00255                                 DBusRemoveWatchFunction  remove_function,
00256                                 DBusWatchToggledFunction toggled_function,
00257                                 void                    *data,
00258                                 DBusFreeFunction         free_data_function)
00259 {
00260   /* Add watches with the new watch function, failing on OOM */
00261   if (add_function != NULL)
00262     {
00263       DBusList *link;
00264       
00265       link = _dbus_list_get_first_link (&watch_list->watches);
00266       while (link != NULL)
00267         {
00268           DBusList *next = _dbus_list_get_next_link (&watch_list->watches,
00269                                                      link);
00270 
00271 #ifdef DBUS_ENABLE_VERBOSE_MODE
00272           {
00273             const char *watch_type;
00274             int flags;
00275 
00276             flags = dbus_watch_get_flags (link->data);
00277             if ((flags & DBUS_WATCH_READABLE) &&
00278                 (flags & DBUS_WATCH_WRITABLE))
00279               watch_type = "readwrite";
00280             else if (flags & DBUS_WATCH_READABLE)
00281               watch_type = "read";
00282             else if (flags & DBUS_WATCH_WRITABLE)
00283               watch_type = "write";
00284             else
00285               watch_type = "not read or write";
00286             
00287             _dbus_verbose ("Adding a %s watch on fd %d using newly-set add watch function\n",
00288                            watch_type,
00289                            dbus_watch_get_socket (link->data));
00290           }
00291 #endif /* DBUS_ENABLE_VERBOSE_MODE */
00292           
00293           if (!(* add_function) (link->data, data))
00294             {
00295               /* remove it all again and return FALSE */
00296               DBusList *link2;
00297               
00298               link2 = _dbus_list_get_first_link (&watch_list->watches);
00299               while (link2 != link)
00300                 {
00301                   DBusList *next = _dbus_list_get_next_link (&watch_list->watches,
00302                                                              link2);
00303                   
00304                   _dbus_verbose ("Removing watch on fd %d using newly-set remove function because initial add failed\n",
00305                                  dbus_watch_get_socket (link2->data));
00306                   
00307                   (* remove_function) (link2->data, data);
00308                   
00309                   link2 = next;
00310                 }
00311 
00312               return FALSE;
00313             }
00314       
00315           link = next;
00316         }
00317     }
00318   
00319   /* Remove all current watches from previous watch handlers */
00320 
00321   if (watch_list->remove_watch_function != NULL)
00322     {
00323       _dbus_verbose ("Removing all pre-existing watches\n");
00324       
00325       _dbus_list_foreach (&watch_list->watches,
00326                           (DBusForeachFunction) watch_list->remove_watch_function,
00327                           watch_list->watch_data);
00328     }
00329 
00330   if (watch_list->watch_free_data_function != NULL)
00331     (* watch_list->watch_free_data_function) (watch_list->watch_data);
00332   
00333   watch_list->add_watch_function = add_function;
00334   watch_list->remove_watch_function = remove_function;
00335   watch_list->watch_toggled_function = toggled_function;
00336   watch_list->watch_data = data;
00337   watch_list->watch_free_data_function = free_data_function;
00338 
00339   return TRUE;
00340 }
00341 
00350 dbus_bool_t
00351 _dbus_watch_list_add_watch (DBusWatchList *watch_list,
00352                             DBusWatch     *watch)
00353 {
00354   if (!_dbus_list_append (&watch_list->watches, watch))
00355     return FALSE;
00356   
00357   _dbus_watch_ref (watch);
00358 
00359   if (watch_list->add_watch_function != NULL)
00360     {
00361       _dbus_verbose ("Adding watch on fd %d\n",
00362                      dbus_watch_get_socket (watch));
00363       
00364       if (!(* watch_list->add_watch_function) (watch,
00365                                                watch_list->watch_data))
00366         {
00367           _dbus_list_remove_last (&watch_list->watches, watch);
00368           _dbus_watch_unref (watch);
00369           return FALSE;
00370         }
00371     }
00372   
00373   return TRUE;
00374 }
00375 
00383 void
00384 _dbus_watch_list_remove_watch  (DBusWatchList *watch_list,
00385                                 DBusWatch     *watch)
00386 {
00387   if (!_dbus_list_remove (&watch_list->watches, watch))
00388     _dbus_assert_not_reached ("Nonexistent watch was removed");
00389   
00390   if (watch_list->remove_watch_function != NULL)
00391     {
00392       _dbus_verbose ("Removing watch on fd %d\n",
00393                      dbus_watch_get_socket (watch));
00394       
00395       (* watch_list->remove_watch_function) (watch,
00396                                              watch_list->watch_data);
00397     }
00398   
00399   _dbus_watch_unref (watch);
00400 }
00401 
00410 void
00411 _dbus_watch_list_toggle_watch (DBusWatchList           *watch_list,
00412                                DBusWatch               *watch,
00413                                dbus_bool_t              enabled)
00414 {
00415   enabled = !!enabled;
00416   
00417   if (enabled == watch->enabled)
00418     return;
00419 
00420   watch->enabled = enabled;
00421   
00422   if (watch_list->watch_toggled_function != NULL)
00423     {
00424       _dbus_verbose ("Toggling watch %p on fd %d to %d\n",
00425                      watch, dbus_watch_get_socket (watch), watch->enabled);
00426       
00427       (* watch_list->watch_toggled_function) (watch,
00428                                               watch_list->watch_data);
00429     }
00430 }
00431 
00444 void
00445 _dbus_watch_set_handler (DBusWatch        *watch,
00446                          DBusWatchHandler  handler,
00447                          void             *data,
00448                          DBusFreeFunction  free_data_function)
00449 {
00450   if (watch->free_handler_data_function)
00451     (* watch->free_handler_data_function) (watch->handler_data);
00452 
00453   watch->handler = handler;
00454   watch->handler_data = data;
00455   watch->free_handler_data_function = free_data_function;
00456 }
00457 
00489 int
00490 dbus_watch_get_fd (DBusWatch *watch)
00491 {
00492   return dbus_watch_get_unix_fd(watch);
00493 }
00494 
00508 int
00509 dbus_watch_get_unix_fd (DBusWatch *watch)
00510 {
00511   /* FIXME remove #ifdef and do this on a lower level
00512    * (watch should have set_socket and set_unix_fd and track
00513    * which it has, and the transport should provide the
00514    * appropriate watch type)
00515    */
00516 #ifdef DBUS_UNIX
00517   return watch->fd;
00518 #else
00519   return -1;
00520 #endif
00521 }
00522 
00535 int
00536 dbus_watch_get_socket (DBusWatch *watch)
00537 {
00538   return watch->fd;
00539 }
00540 
00554 unsigned int
00555 dbus_watch_get_flags (DBusWatch *watch)
00556 {
00557   _dbus_assert ((watch->flags & VALID_WATCH_FLAGS) == watch->flags);
00558 
00559   return watch->flags;
00560 }
00561 
00569 void*
00570 dbus_watch_get_data (DBusWatch *watch)
00571 {
00572   return watch->data;
00573 }
00574 
00586 void
00587 dbus_watch_set_data (DBusWatch        *watch,
00588                      void             *data,
00589                      DBusFreeFunction  free_data_function)
00590 {
00591   _dbus_verbose ("Setting watch fd %d data to data = %p function = %p from data = %p function = %p\n",
00592                  dbus_watch_get_socket (watch),
00593                  data, free_data_function, watch->data, watch->free_data_function);
00594   
00595   if (watch->free_data_function != NULL)
00596     (* watch->free_data_function) (watch->data);
00597   
00598   watch->data = data;
00599   watch->free_data_function = free_data_function;
00600 }
00601 
00609 dbus_bool_t
00610 dbus_watch_get_enabled (DBusWatch *watch)
00611 {
00612   _dbus_assert (watch != NULL);
00613   return watch->enabled;
00614 }
00615 
00616 
00639 dbus_bool_t
00640 dbus_watch_handle (DBusWatch    *watch,
00641                    unsigned int  flags)
00642 {
00643 #ifndef DBUS_DISABLE_CHECKS
00644   if (watch->fd < 0 || watch->flags == 0)
00645     {
00646       _dbus_warn_check_failed ("%s: Watch is invalid, it should have been removed\n",
00647                                _DBUS_FUNCTION_NAME);
00648       return TRUE;
00649     }
00650 #endif
00651     
00652   _dbus_return_val_if_fail (watch->fd >= 0 /* fails if watch was removed */, TRUE);
00653   
00654   _dbus_watch_sanitize_condition (watch, &flags);
00655 
00656   if (flags == 0)
00657     {
00658       _dbus_verbose ("After sanitization, watch flags on fd %d were 0\n",
00659                      watch->fd);
00660       return TRUE;
00661     }
00662   else
00663     return (* watch->handler) (watch, flags,
00664                                watch->handler_data);
00665 }
00666 
00667 

Generated on Thu Jan 22 16:37:06 2009 for D-Bus by  doxygen 1.5.1