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 
00036 struct DBusWatch
00037 {
00038   int refcount;                        
00039   int fd;                              
00040   unsigned int flags;                  
00042   DBusWatchHandler handler;                    
00043   void *handler_data;                          
00044   DBusFreeFunction free_handler_data_function; 
00046   void *data;                          
00047   DBusFreeFunction free_data_function; 
00048   unsigned int enabled : 1;            
00049 };
00050 
00063 DBusWatch*
00064 _dbus_watch_new (int               fd,
00065                  unsigned int      flags,
00066                  dbus_bool_t       enabled,
00067                  DBusWatchHandler  handler,
00068                  void             *data,
00069                  DBusFreeFunction  free_data_function)
00070 {
00071   DBusWatch *watch;
00072 
00073 #define VALID_WATCH_FLAGS (DBUS_WATCH_WRITABLE | DBUS_WATCH_READABLE)
00074   
00075   _dbus_assert ((flags & VALID_WATCH_FLAGS) == flags);
00076   
00077   watch = dbus_new0 (DBusWatch, 1);
00078   if (watch == NULL)
00079     return NULL;
00080   
00081   watch->refcount = 1;
00082   watch->fd = fd;
00083   watch->flags = flags;
00084   watch->enabled = enabled;
00085 
00086   watch->handler = handler;
00087   watch->handler_data = data;
00088   watch->free_handler_data_function = free_data_function;
00089   
00090   return watch;
00091 }
00092 
00098 void
00099 _dbus_watch_ref (DBusWatch *watch)
00100 {
00101   watch->refcount += 1;
00102 }
00103 
00110 void
00111 _dbus_watch_unref (DBusWatch *watch)
00112 {
00113   _dbus_assert (watch != NULL);
00114   _dbus_assert (watch->refcount > 0);
00115 
00116   watch->refcount -= 1;
00117   if (watch->refcount == 0)
00118     {
00119       dbus_watch_set_data (watch, NULL, NULL); /* call free_data_function */
00120 
00121       if (watch->free_handler_data_function)
00122         (* watch->free_handler_data_function) (watch->handler_data);
00123       
00124       dbus_free (watch);
00125     }
00126 }
00127 
00138 void
00139 _dbus_watch_invalidate (DBusWatch *watch)
00140 {
00141   watch->fd = -1;
00142   watch->flags = 0;
00143 }
00144 
00154 void
00155 _dbus_watch_sanitize_condition (DBusWatch    *watch,
00156                                 unsigned int *condition)
00157 {
00158   if (!(watch->flags & DBUS_WATCH_READABLE))
00159     *condition &= ~DBUS_WATCH_READABLE;
00160   if (!(watch->flags & DBUS_WATCH_WRITABLE))
00161     *condition &= ~DBUS_WATCH_WRITABLE;
00162 }
00163 
00164 
00184 struct DBusWatchList
00185 {
00186   DBusList *watches;           
00188   DBusAddWatchFunction add_watch_function;    
00189   DBusRemoveWatchFunction remove_watch_function; 
00190   DBusWatchToggledFunction watch_toggled_function; 
00191   void *watch_data;                           
00192   DBusFreeFunction watch_free_data_function;  
00193 };
00194 
00201 DBusWatchList*
00202 _dbus_watch_list_new (void)
00203 {
00204   DBusWatchList *watch_list;
00205 
00206   watch_list = dbus_new0 (DBusWatchList, 1);
00207   if (watch_list == NULL)
00208     return NULL;
00209 
00210   return watch_list;
00211 }
00212 
00218 void
00219 _dbus_watch_list_free (DBusWatchList *watch_list)
00220 {
00221   /* free watch_data and removes watches as a side effect */
00222   _dbus_watch_list_set_functions (watch_list,
00223                                   NULL, NULL, NULL, NULL, NULL);
00224   _dbus_list_foreach (&watch_list->watches,
00225                       (DBusForeachFunction) _dbus_watch_unref,
00226                       NULL);
00227   _dbus_list_clear (&watch_list->watches);
00228 
00229   dbus_free (watch_list);
00230 }
00231 
00246 dbus_bool_t
00247 _dbus_watch_list_set_functions (DBusWatchList           *watch_list,
00248                                 DBusAddWatchFunction     add_function,
00249                                 DBusRemoveWatchFunction  remove_function,
00250                                 DBusWatchToggledFunction toggled_function,
00251                                 void                    *data,
00252                                 DBusFreeFunction         free_data_function)
00253 {
00254   /* Add watches with the new watch function, failing on OOM */
00255   if (add_function != NULL)
00256     {
00257       DBusList *link;
00258       
00259       link = _dbus_list_get_first_link (&watch_list->watches);
00260       while (link != NULL)
00261         {
00262           DBusList *next = _dbus_list_get_next_link (&watch_list->watches,
00263                                                      link);
00264 
00265           _dbus_verbose ("Adding a watch on fd %d using newly-set add watch function\n",
00266                          dbus_watch_get_fd (link->data));
00267           
00268           if (!(* add_function) (link->data, data))
00269             {
00270               /* remove it all again and return FALSE */
00271               DBusList *link2;
00272               
00273               link2 = _dbus_list_get_first_link (&watch_list->watches);
00274               while (link2 != link)
00275                 {
00276                   DBusList *next = _dbus_list_get_next_link (&watch_list->watches,
00277                                                              link2);
00278                   
00279                   _dbus_verbose ("Removing watch on fd %d using newly-set remove function because initial add failed\n",
00280                                  dbus_watch_get_fd (link2->data));
00281                   
00282                   (* remove_function) (link2->data, data);
00283                   
00284                   link2 = next;
00285                 }
00286 
00287               return FALSE;
00288             }
00289       
00290           link = next;
00291         }
00292     }
00293   
00294   /* Remove all current watches from previous watch handlers */
00295 
00296   if (watch_list->remove_watch_function != NULL)
00297     {
00298       _dbus_verbose ("Removing all pre-existing watches\n");
00299       
00300       _dbus_list_foreach (&watch_list->watches,
00301                           (DBusForeachFunction) watch_list->remove_watch_function,
00302                           watch_list->watch_data);
00303     }
00304 
00305   if (watch_list->watch_free_data_function != NULL)
00306     (* watch_list->watch_free_data_function) (watch_list->watch_data);
00307   
00308   watch_list->add_watch_function = add_function;
00309   watch_list->remove_watch_function = remove_function;
00310   watch_list->watch_toggled_function = toggled_function;
00311   watch_list->watch_data = data;
00312   watch_list->watch_free_data_function = free_data_function;
00313 
00314   return TRUE;
00315 }
00316 
00325 dbus_bool_t
00326 _dbus_watch_list_add_watch (DBusWatchList *watch_list,
00327                             DBusWatch     *watch)
00328 {
00329   if (!_dbus_list_append (&watch_list->watches, watch))
00330     return FALSE;
00331   
00332   _dbus_watch_ref (watch);
00333 
00334   if (watch_list->add_watch_function != NULL)
00335     {
00336       _dbus_verbose ("Adding watch on fd %d\n",
00337                      dbus_watch_get_fd (watch));
00338       
00339       if (!(* watch_list->add_watch_function) (watch,
00340                                                watch_list->watch_data))
00341         {
00342           _dbus_list_remove_last (&watch_list->watches, watch);
00343           _dbus_watch_unref (watch);
00344           return FALSE;
00345         }
00346     }
00347   
00348   return TRUE;
00349 }
00350 
00358 void
00359 _dbus_watch_list_remove_watch  (DBusWatchList *watch_list,
00360                                 DBusWatch     *watch)
00361 {
00362   if (!_dbus_list_remove (&watch_list->watches, watch))
00363     _dbus_assert_not_reached ("Nonexistent watch was removed");
00364   
00365   if (watch_list->remove_watch_function != NULL)
00366     {
00367       _dbus_verbose ("Removing watch on fd %d\n",
00368                      dbus_watch_get_fd (watch));
00369       
00370       (* watch_list->remove_watch_function) (watch,
00371                                              watch_list->watch_data);
00372     }
00373   
00374   _dbus_watch_unref (watch);
00375 }
00376 
00385 void
00386 _dbus_watch_list_toggle_watch (DBusWatchList           *watch_list,
00387                                DBusWatch               *watch,
00388                                dbus_bool_t              enabled)
00389 {
00390   enabled = !!enabled;
00391   
00392   if (enabled == watch->enabled)
00393     return;
00394 
00395   watch->enabled = enabled;
00396   
00397   if (watch_list->watch_toggled_function != NULL)
00398     {
00399       _dbus_verbose ("Toggling watch on fd %d to %d\n",
00400                      dbus_watch_get_fd (watch), watch->enabled);
00401       
00402       (* watch_list->watch_toggled_function) (watch,
00403                                               watch_list->watch_data);
00404     }
00405 }
00406 
00419 void
00420 _dbus_watch_set_handler (DBusWatch        *watch,
00421                          DBusWatchHandler  handler,
00422                          void             *data,
00423                          DBusFreeFunction  free_data_function)
00424 {
00425   if (watch->free_handler_data_function)
00426     (* watch->free_handler_data_function) (watch->handler_data);
00427 
00428   watch->handler = handler;
00429   watch->handler_data = data;
00430   watch->free_handler_data_function = free_data_function;
00431 }
00432 
00461 int
00462 dbus_watch_get_fd (DBusWatch *watch)
00463 {
00464   return watch->fd;
00465 }
00466 
00480 unsigned int
00481 dbus_watch_get_flags (DBusWatch *watch)
00482 {
00483   _dbus_assert ((watch->flags & VALID_WATCH_FLAGS) == watch->flags);
00484 
00485   return watch->flags;
00486 }
00487 
00495 void*
00496 dbus_watch_get_data (DBusWatch *watch)
00497 {
00498   return watch->data;
00499 }
00500 
00512 void
00513 dbus_watch_set_data (DBusWatch        *watch,
00514                      void             *data,
00515                      DBusFreeFunction  free_data_function)
00516 {
00517   _dbus_verbose ("Setting watch fd %d data to data = %p function = %p from data = %p function = %p\n",
00518                  dbus_watch_get_fd (watch),
00519                  data, free_data_function, watch->data, watch->free_data_function);
00520   
00521   if (watch->free_data_function != NULL)
00522     (* watch->free_data_function) (watch->data);
00523   
00524   watch->data = data;
00525   watch->free_data_function = free_data_function;
00526 }
00527 
00535 dbus_bool_t
00536 dbus_watch_get_enabled (DBusWatch *watch)
00537 {
00538   _dbus_assert (watch != NULL);
00539   return watch->enabled;
00540 }
00541 
00542 
00565 dbus_bool_t
00566 dbus_watch_handle (DBusWatch    *watch,
00567                    unsigned int  flags)
00568 {
00569 #ifndef DBUS_DISABLE_CHECKS
00570   if (watch->fd < 0 || watch->flags == 0)
00571     {
00572       _dbus_warn ("%s: Watch is invalid, it should have been removed\n",
00573                   _DBUS_FUNCTION_NAME);
00574       return TRUE;
00575     }
00576 #endif
00577     
00578   _dbus_return_val_if_fail (watch->fd >= 0 /* fails if watch was removed */, TRUE);
00579   
00580   _dbus_watch_sanitize_condition (watch, &flags);
00581 
00582   if (flags == 0)
00583     {
00584       _dbus_verbose ("After sanitization, watch flags on fd %d were 0\n",
00585                      watch->fd);
00586       return TRUE;
00587     }
00588   else
00589     return (* watch->handler) (watch, flags,
00590                                watch->handler_data);
00591 }
00592 
00593 

Generated on Wed Oct 22 14:05:05 2003 for D-BUS by doxygen1.3-rc3