Main Page | Modules | Data Structures | File List | Data Fields | Related Pages

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 1.2
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 
00101 void
00102 _dbus_watch_ref (DBusWatch *watch)
00103 {
00104   watch->refcount += 1;
00105 }
00106 
00113 void
00114 _dbus_watch_unref (DBusWatch *watch)
00115 {
00116   _dbus_assert (watch != NULL);
00117   _dbus_assert (watch->refcount > 0);
00118 
00119   watch->refcount -= 1;
00120   if (watch->refcount == 0)
00121     {
00122       dbus_watch_set_data (watch, NULL, NULL); /* call free_data_function */
00123 
00124       if (watch->free_handler_data_function)
00125         (* watch->free_handler_data_function) (watch->handler_data);
00126       
00127       dbus_free (watch);
00128     }
00129 }
00130 
00141 void
00142 _dbus_watch_invalidate (DBusWatch *watch)
00143 {
00144   watch->fd = -1;
00145   watch->flags = 0;
00146 }
00147 
00157 void
00158 _dbus_watch_sanitize_condition (DBusWatch    *watch,
00159                                 unsigned int *condition)
00160 {
00161   if (!(watch->flags & DBUS_WATCH_READABLE))
00162     *condition &= ~DBUS_WATCH_READABLE;
00163   if (!(watch->flags & DBUS_WATCH_WRITABLE))
00164     *condition &= ~DBUS_WATCH_WRITABLE;
00165 }
00166 
00167 
00187 struct DBusWatchList
00188 {
00189   DBusList *watches;           
00191   DBusAddWatchFunction add_watch_function;    
00192   DBusRemoveWatchFunction remove_watch_function; 
00193   DBusWatchToggledFunction watch_toggled_function; 
00194   void *watch_data;                           
00195   DBusFreeFunction watch_free_data_function;  
00196 };
00197 
00204 DBusWatchList*
00205 _dbus_watch_list_new (void)
00206 {
00207   DBusWatchList *watch_list;
00208 
00209   watch_list = dbus_new0 (DBusWatchList, 1);
00210   if (watch_list == NULL)
00211     return NULL;
00212 
00213   return watch_list;
00214 }
00215 
00221 void
00222 _dbus_watch_list_free (DBusWatchList *watch_list)
00223 {
00224   /* free watch_data and removes watches as a side effect */
00225   _dbus_watch_list_set_functions (watch_list,
00226                                   NULL, NULL, NULL, NULL, NULL);
00227   _dbus_list_foreach (&watch_list->watches,
00228                       (DBusForeachFunction) _dbus_watch_unref,
00229                       NULL);
00230   _dbus_list_clear (&watch_list->watches);
00231 
00232   dbus_free (watch_list);
00233 }
00234 
00249 dbus_bool_t
00250 _dbus_watch_list_set_functions (DBusWatchList           *watch_list,
00251                                 DBusAddWatchFunction     add_function,
00252                                 DBusRemoveWatchFunction  remove_function,
00253                                 DBusWatchToggledFunction toggled_function,
00254                                 void                    *data,
00255                                 DBusFreeFunction         free_data_function)
00256 {
00257   /* Add watches with the new watch function, failing on OOM */
00258   if (add_function != NULL)
00259     {
00260       DBusList *link;
00261       
00262       link = _dbus_list_get_first_link (&watch_list->watches);
00263       while (link != NULL)
00264         {
00265           DBusList *next = _dbus_list_get_next_link (&watch_list->watches,
00266                                                      link);
00267 
00268           _dbus_verbose ("Adding a watch on fd %d using newly-set add watch function\n",
00269                          dbus_watch_get_fd (link->data));
00270           
00271           if (!(* add_function) (link->data, data))
00272             {
00273               /* remove it all again and return FALSE */
00274               DBusList *link2;
00275               
00276               link2 = _dbus_list_get_first_link (&watch_list->watches);
00277               while (link2 != link)
00278                 {
00279                   DBusList *next = _dbus_list_get_next_link (&watch_list->watches,
00280                                                              link2);
00281                   
00282                   _dbus_verbose ("Removing watch on fd %d using newly-set remove function because initial add failed\n",
00283                                  dbus_watch_get_fd (link2->data));
00284                   
00285                   (* remove_function) (link2->data, data);
00286                   
00287                   link2 = next;
00288                 }
00289 
00290               return FALSE;
00291             }
00292       
00293           link = next;
00294         }
00295     }
00296   
00297   /* Remove all current watches from previous watch handlers */
00298 
00299   if (watch_list->remove_watch_function != NULL)
00300     {
00301       _dbus_verbose ("Removing all pre-existing watches\n");
00302       
00303       _dbus_list_foreach (&watch_list->watches,
00304                           (DBusForeachFunction) watch_list->remove_watch_function,
00305                           watch_list->watch_data);
00306     }
00307 
00308   if (watch_list->watch_free_data_function != NULL)
00309     (* watch_list->watch_free_data_function) (watch_list->watch_data);
00310   
00311   watch_list->add_watch_function = add_function;
00312   watch_list->remove_watch_function = remove_function;
00313   watch_list->watch_toggled_function = toggled_function;
00314   watch_list->watch_data = data;
00315   watch_list->watch_free_data_function = free_data_function;
00316 
00317   return TRUE;
00318 }
00319 
00328 dbus_bool_t
00329 _dbus_watch_list_add_watch (DBusWatchList *watch_list,
00330                             DBusWatch     *watch)
00331 {
00332   if (!_dbus_list_append (&watch_list->watches, watch))
00333     return FALSE;
00334   
00335   _dbus_watch_ref (watch);
00336 
00337   if (watch_list->add_watch_function != NULL)
00338     {
00339       _dbus_verbose ("Adding watch on fd %d\n",
00340                      dbus_watch_get_fd (watch));
00341       
00342       if (!(* watch_list->add_watch_function) (watch,
00343                                                watch_list->watch_data))
00344         {
00345           _dbus_list_remove_last (&watch_list->watches, watch);
00346           _dbus_watch_unref (watch);
00347           return FALSE;
00348         }
00349     }
00350   
00351   return TRUE;
00352 }
00353 
00361 void
00362 _dbus_watch_list_remove_watch  (DBusWatchList *watch_list,
00363                                 DBusWatch     *watch)
00364 {
00365   if (!_dbus_list_remove (&watch_list->watches, watch))
00366     _dbus_assert_not_reached ("Nonexistent watch was removed");
00367   
00368   if (watch_list->remove_watch_function != NULL)
00369     {
00370       _dbus_verbose ("Removing watch on fd %d\n",
00371                      dbus_watch_get_fd (watch));
00372       
00373       (* watch_list->remove_watch_function) (watch,
00374                                              watch_list->watch_data);
00375     }
00376   
00377   _dbus_watch_unref (watch);
00378 }
00379 
00388 void
00389 _dbus_watch_list_toggle_watch (DBusWatchList           *watch_list,
00390                                DBusWatch               *watch,
00391                                dbus_bool_t              enabled)
00392 {
00393   enabled = !!enabled;
00394   
00395   if (enabled == watch->enabled)
00396     return;
00397 
00398   watch->enabled = enabled;
00399   
00400   if (watch_list->watch_toggled_function != NULL)
00401     {
00402       _dbus_verbose ("Toggling watch on fd %d to %d\n",
00403                      dbus_watch_get_fd (watch), watch->enabled);
00404       
00405       (* watch_list->watch_toggled_function) (watch,
00406                                               watch_list->watch_data);
00407     }
00408 }
00409 
00422 void
00423 _dbus_watch_set_handler (DBusWatch        *watch,
00424                          DBusWatchHandler  handler,
00425                          void             *data,
00426                          DBusFreeFunction  free_data_function)
00427 {
00428   if (watch->free_handler_data_function)
00429     (* watch->free_handler_data_function) (watch->handler_data);
00430 
00431   watch->handler = handler;
00432   watch->handler_data = data;
00433   watch->free_handler_data_function = free_data_function;
00434 }
00435 
00464 int
00465 dbus_watch_get_fd (DBusWatch *watch)
00466 {
00467   return watch->fd;
00468 }
00469 
00483 unsigned int
00484 dbus_watch_get_flags (DBusWatch *watch)
00485 {
00486   _dbus_assert ((watch->flags & VALID_WATCH_FLAGS) == watch->flags);
00487 
00488   return watch->flags;
00489 }
00490 
00498 void*
00499 dbus_watch_get_data (DBusWatch *watch)
00500 {
00501   return watch->data;
00502 }
00503 
00515 void
00516 dbus_watch_set_data (DBusWatch        *watch,
00517                      void             *data,
00518                      DBusFreeFunction  free_data_function)
00519 {
00520   _dbus_verbose ("Setting watch fd %d data to data = %p function = %p from data = %p function = %p\n",
00521                  dbus_watch_get_fd (watch),
00522                  data, free_data_function, watch->data, watch->free_data_function);
00523   
00524   if (watch->free_data_function != NULL)
00525     (* watch->free_data_function) (watch->data);
00526   
00527   watch->data = data;
00528   watch->free_data_function = free_data_function;
00529 }
00530 
00538 dbus_bool_t
00539 dbus_watch_get_enabled (DBusWatch *watch)
00540 {
00541   _dbus_assert (watch != NULL);
00542   return watch->enabled;
00543 }
00544 
00545 
00568 dbus_bool_t
00569 dbus_watch_handle (DBusWatch    *watch,
00570                    unsigned int  flags)
00571 {
00572 #ifndef DBUS_DISABLE_CHECKS
00573   if (watch->fd < 0 || watch->flags == 0)
00574     {
00575       _dbus_warn ("%s: Watch is invalid, it should have been removed\n",
00576                   _DBUS_FUNCTION_NAME);
00577       return TRUE;
00578     }
00579 #endif
00580     
00581   _dbus_return_val_if_fail (watch->fd >= 0 /* fails if watch was removed */, TRUE);
00582   
00583   _dbus_watch_sanitize_condition (watch, &flags);
00584 
00585   if (flags == 0)
00586     {
00587       _dbus_verbose ("After sanitization, watch flags on fd %d were 0\n",
00588                      watch->fd);
00589       return TRUE;
00590     }
00591   else
00592     return (* watch->handler) (watch, flags,
00593                                watch->handler_data);
00594 }
00595 
00596 

Generated on Tue Feb 10 18:14:09 2004 for D-BUS by doxygen 1.3.5