dbus-watch.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
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_fd (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_fd (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_fd (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_fd (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_fd (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 
00492 int
00493 dbus_watch_get_fd (DBusWatch *watch)
00494 {
00495   return watch->fd;
00496 }
00497 
00511 unsigned int
00512 dbus_watch_get_flags (DBusWatch *watch)
00513 {
00514   _dbus_assert ((watch->flags & VALID_WATCH_FLAGS) == watch->flags);
00515 
00516   return watch->flags;
00517 }
00518 
00526 void*
00527 dbus_watch_get_data (DBusWatch *watch)
00528 {
00529   return watch->data;
00530 }
00531 
00543 void
00544 dbus_watch_set_data (DBusWatch        *watch,
00545                      void             *data,
00546                      DBusFreeFunction  free_data_function)
00547 {
00548   _dbus_verbose ("Setting watch fd %d data to data = %p function = %p from data = %p function = %p\n",
00549                  dbus_watch_get_fd (watch),
00550                  data, free_data_function, watch->data, watch->free_data_function);
00551   
00552   if (watch->free_data_function != NULL)
00553     (* watch->free_data_function) (watch->data);
00554   
00555   watch->data = data;
00556   watch->free_data_function = free_data_function;
00557 }
00558 
00566 dbus_bool_t
00567 dbus_watch_get_enabled (DBusWatch *watch)
00568 {
00569   _dbus_assert (watch != NULL);
00570   return watch->enabled;
00571 }
00572 
00573 
00596 dbus_bool_t
00597 dbus_watch_handle (DBusWatch    *watch,
00598                    unsigned int  flags)
00599 {
00600 #ifndef DBUS_DISABLE_CHECKS
00601   if (watch->fd < 0 || watch->flags == 0)
00602     {
00603       _dbus_warn_check_failed ("%s: Watch is invalid, it should have been removed\n",
00604                                _DBUS_FUNCTION_NAME);
00605       return TRUE;
00606     }
00607 #endif
00608     
00609   _dbus_return_val_if_fail (watch->fd >= 0 /* fails if watch was removed */, TRUE);
00610   
00611   _dbus_watch_sanitize_condition (watch, &flags);
00612 
00613   if (flags == 0)
00614     {
00615       _dbus_verbose ("After sanitization, watch flags on fd %d were 0\n",
00616                      watch->fd);
00617       return TRUE;
00618     }
00619   else
00620     return (* watch->handler) (watch, flags,
00621                                watch->handler_data);
00622 }
00623 
00624 

Generated on Fri Sep 21 18:12:13 2007 for D-Bus by  doxygen 1.5.1