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 2.0
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           _dbus_verbose ("Adding a watch on fd %d using newly-set add watch function\n",
00272                          dbus_watch_get_fd (link->data));
00273           
00274           if (!(* add_function) (link->data, data))
00275             {
00276               /* remove it all again and return FALSE */
00277               DBusList *link2;
00278               
00279               link2 = _dbus_list_get_first_link (&watch_list->watches);
00280               while (link2 != link)
00281                 {
00282                   DBusList *next = _dbus_list_get_next_link (&watch_list->watches,
00283                                                              link2);
00284                   
00285                   _dbus_verbose ("Removing watch on fd %d using newly-set remove function because initial add failed\n",
00286                                  dbus_watch_get_fd (link2->data));
00287                   
00288                   (* remove_function) (link2->data, data);
00289                   
00290                   link2 = next;
00291                 }
00292 
00293               return FALSE;
00294             }
00295       
00296           link = next;
00297         }
00298     }
00299   
00300   /* Remove all current watches from previous watch handlers */
00301 
00302   if (watch_list->remove_watch_function != NULL)
00303     {
00304       _dbus_verbose ("Removing all pre-existing watches\n");
00305       
00306       _dbus_list_foreach (&watch_list->watches,
00307                           (DBusForeachFunction) watch_list->remove_watch_function,
00308                           watch_list->watch_data);
00309     }
00310 
00311   if (watch_list->watch_free_data_function != NULL)
00312     (* watch_list->watch_free_data_function) (watch_list->watch_data);
00313   
00314   watch_list->add_watch_function = add_function;
00315   watch_list->remove_watch_function = remove_function;
00316   watch_list->watch_toggled_function = toggled_function;
00317   watch_list->watch_data = data;
00318   watch_list->watch_free_data_function = free_data_function;
00319 
00320   return TRUE;
00321 }
00322 
00331 dbus_bool_t
00332 _dbus_watch_list_add_watch (DBusWatchList *watch_list,
00333                             DBusWatch     *watch)
00334 {
00335   if (!_dbus_list_append (&watch_list->watches, watch))
00336     return FALSE;
00337   
00338   _dbus_watch_ref (watch);
00339 
00340   if (watch_list->add_watch_function != NULL)
00341     {
00342       _dbus_verbose ("Adding watch on fd %d\n",
00343                      dbus_watch_get_fd (watch));
00344       
00345       if (!(* watch_list->add_watch_function) (watch,
00346                                                watch_list->watch_data))
00347         {
00348           _dbus_list_remove_last (&watch_list->watches, watch);
00349           _dbus_watch_unref (watch);
00350           return FALSE;
00351         }
00352     }
00353   
00354   return TRUE;
00355 }
00356 
00364 void
00365 _dbus_watch_list_remove_watch  (DBusWatchList *watch_list,
00366                                 DBusWatch     *watch)
00367 {
00368   if (!_dbus_list_remove (&watch_list->watches, watch))
00369     _dbus_assert_not_reached ("Nonexistent watch was removed");
00370   
00371   if (watch_list->remove_watch_function != NULL)
00372     {
00373       _dbus_verbose ("Removing watch on fd %d\n",
00374                      dbus_watch_get_fd (watch));
00375       
00376       (* watch_list->remove_watch_function) (watch,
00377                                              watch_list->watch_data);
00378     }
00379   
00380   _dbus_watch_unref (watch);
00381 }
00382 
00391 void
00392 _dbus_watch_list_toggle_watch (DBusWatchList           *watch_list,
00393                                DBusWatch               *watch,
00394                                dbus_bool_t              enabled)
00395 {
00396   enabled = !!enabled;
00397   
00398   if (enabled == watch->enabled)
00399     return;
00400 
00401   watch->enabled = enabled;
00402   
00403   if (watch_list->watch_toggled_function != NULL)
00404     {
00405       _dbus_verbose ("Toggling watch on fd %d to %d\n",
00406                      dbus_watch_get_fd (watch), watch->enabled);
00407       
00408       (* watch_list->watch_toggled_function) (watch,
00409                                               watch_list->watch_data);
00410     }
00411 }
00412 
00425 void
00426 _dbus_watch_set_handler (DBusWatch        *watch,
00427                          DBusWatchHandler  handler,
00428                          void             *data,
00429                          DBusFreeFunction  free_data_function)
00430 {
00431   if (watch->free_handler_data_function)
00432     (* watch->free_handler_data_function) (watch->handler_data);
00433 
00434   watch->handler = handler;
00435   watch->handler_data = data;
00436   watch->free_handler_data_function = free_data_function;
00437 }
00438 
00467 int
00468 dbus_watch_get_fd (DBusWatch *watch)
00469 {
00470   return watch->fd;
00471 }
00472 
00486 unsigned int
00487 dbus_watch_get_flags (DBusWatch *watch)
00488 {
00489   _dbus_assert ((watch->flags & VALID_WATCH_FLAGS) == watch->flags);
00490 
00491   return watch->flags;
00492 }
00493 
00501 void*
00502 dbus_watch_get_data (DBusWatch *watch)
00503 {
00504   return watch->data;
00505 }
00506 
00518 void
00519 dbus_watch_set_data (DBusWatch        *watch,
00520                      void             *data,
00521                      DBusFreeFunction  free_data_function)
00522 {
00523   _dbus_verbose ("Setting watch fd %d data to data = %p function = %p from data = %p function = %p\n",
00524                  dbus_watch_get_fd (watch),
00525                  data, free_data_function, watch->data, watch->free_data_function);
00526   
00527   if (watch->free_data_function != NULL)
00528     (* watch->free_data_function) (watch->data);
00529   
00530   watch->data = data;
00531   watch->free_data_function = free_data_function;
00532 }
00533 
00541 dbus_bool_t
00542 dbus_watch_get_enabled (DBusWatch *watch)
00543 {
00544   _dbus_assert (watch != NULL);
00545   return watch->enabled;
00546 }
00547 
00548 
00571 dbus_bool_t
00572 dbus_watch_handle (DBusWatch    *watch,
00573                    unsigned int  flags)
00574 {
00575 #ifndef DBUS_DISABLE_CHECKS
00576   if (watch->fd < 0 || watch->flags == 0)
00577     {
00578       _dbus_warn ("%s: Watch is invalid, it should have been removed\n",
00579                   _DBUS_FUNCTION_NAME);
00580       return TRUE;
00581     }
00582 #endif
00583     
00584   _dbus_return_val_if_fail (watch->fd >= 0 /* fails if watch was removed */, TRUE);
00585   
00586   _dbus_watch_sanitize_condition (watch, &flags);
00587 
00588   if (flags == 0)
00589     {
00590       _dbus_verbose ("After sanitization, watch flags on fd %d were 0\n",
00591                      watch->fd);
00592       return TRUE;
00593     }
00594   else
00595     return (* watch->handler) (watch, flags,
00596                                watch->handler_data);
00597 }
00598 
00599 

Generated on Sun Mar 21 03:52:06 2004 for D-BUS by doxygen 1.3.6-20040222