D-Bus  1.6.8
dbus-socket-set-poll.c
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-socket-set-poll.c - a socket set implemented via _dbus_poll
00003  *
00004  * Copyright © 2011 Nokia Corporation
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., 51 Franklin Street, Fifth Floor, Boston,
00021  * MA  02110-1301  USA
00022  *
00023  */
00024 
00025 #include <config.h>
00026 #include "dbus-socket-set.h"
00027 
00028 #include <dbus/dbus-internals.h>
00029 #include <dbus/dbus-list.h>
00030 #include <dbus/dbus-sysdeps.h>
00031 #include <dbus/dbus-watch.h>
00032 
00033 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00034 
00035 typedef struct {
00036     DBusSocketSet      parent;
00037     DBusPollFD        *fds;
00038     int                n_fds;
00039     int                n_reserved;
00040     int                n_allocated;
00041 } DBusSocketSetPoll;
00042 
00043 #define REALLOC_INCREMENT 8
00044 #define MINIMUM_SIZE 8
00045 
00046 /* If we're in the regression tests, force reallocation to happen sooner */
00047 #ifdef DBUS_BUILD_TESTS
00048 #define DEFAULT_SIZE_HINT 1
00049 #else
00050 #define DEFAULT_SIZE_HINT MINIMUM_SIZE
00051 #endif
00052 
00053 static inline DBusSocketSetPoll *
00054 socket_set_poll_cast (DBusSocketSet *set)
00055 {
00056   _dbus_assert (set->cls == &_dbus_socket_set_poll_class);
00057   return (DBusSocketSetPoll *) set;
00058 }
00059 
00060 /* this is safe to call on a partially-allocated socket set */
00061 static void
00062 socket_set_poll_free (DBusSocketSet *set)
00063 {
00064   DBusSocketSetPoll *self = socket_set_poll_cast (set);
00065 
00066   dbus_free (self->fds);
00067   dbus_free (self);
00068   _dbus_verbose ("freed socket set %p\n", self);
00069 }
00070 
00071 DBusSocketSet *
00072 _dbus_socket_set_poll_new (int size_hint)
00073 {
00074   DBusSocketSetPoll *ret;
00075 
00076   if (size_hint <= 0)
00077     size_hint = DEFAULT_SIZE_HINT;
00078 
00079   ret = dbus_new0 (DBusSocketSetPoll, 1);
00080 
00081   if (ret == NULL)
00082     return NULL;
00083 
00084   ret->parent.cls = &_dbus_socket_set_poll_class;
00085   ret->n_fds = 0;
00086   ret->n_allocated = size_hint;
00087 
00088   ret->fds = dbus_new0 (DBusPollFD, size_hint);
00089 
00090   if (ret->fds == NULL)
00091     {
00092       /* socket_set_poll_free specifically supports half-constructed
00093        * socket sets */
00094       socket_set_poll_free ((DBusSocketSet *) ret);
00095       return NULL;
00096     }
00097 
00098   _dbus_verbose ("new socket set at %p\n", ret);
00099   return (DBusSocketSet *) ret;
00100 }
00101 
00102 static short
00103 watch_flags_to_poll_events (unsigned int flags)
00104 {
00105   short events = 0;
00106 
00107   if (flags & DBUS_WATCH_READABLE)
00108     events |= _DBUS_POLLIN;
00109   if (flags & DBUS_WATCH_WRITABLE)
00110     events |= _DBUS_POLLOUT;
00111 
00112   return events;
00113 }
00114 
00115 static dbus_bool_t
00116 socket_set_poll_add (DBusSocketSet  *set,
00117                      int             fd,
00118                      unsigned int    flags,
00119                      dbus_bool_t     enabled)
00120 {
00121   DBusSocketSetPoll *self = socket_set_poll_cast (set);
00122 #ifndef DBUS_DISABLE_ASSERT
00123   int i;
00124 
00125   for (i = 0; i < self->n_fds; i++)
00126     _dbus_assert (self->fds[i].fd != fd);
00127 #endif
00128 
00129   if (self->n_reserved >= self->n_allocated)
00130     {
00131       DBusPollFD *new_fds = dbus_realloc (self->fds,
00132           sizeof (DBusPollFD) * (self->n_allocated + REALLOC_INCREMENT));
00133 
00134       _dbus_verbose ("inflating set %p from %d en/%d res/%d alloc to %d\n",
00135                      self, self->n_fds, self->n_reserved, self->n_allocated,
00136                      self->n_allocated + REALLOC_INCREMENT);
00137 
00138       if (new_fds == NULL)
00139         return FALSE;
00140 
00141       self->fds = new_fds;
00142       self->n_allocated += REALLOC_INCREMENT;
00143     }
00144 
00145   _dbus_verbose ("before adding fd %d to %p, %d en/%d res/%d alloc\n",
00146                  fd, self, self->n_fds, self->n_reserved, self->n_allocated);
00147   _dbus_assert (self->n_reserved >= self->n_fds);
00148   _dbus_assert (self->n_allocated > self->n_reserved);
00149 
00150   self->n_reserved++;
00151 
00152   if (enabled)
00153     {
00154       self->fds[self->n_fds].fd = fd;
00155       self->fds[self->n_fds].events = watch_flags_to_poll_events (flags);
00156       self->n_fds++;
00157     }
00158 
00159   return TRUE;
00160 }
00161 
00162 static void
00163 socket_set_poll_enable (DBusSocketSet *set,
00164                         int            fd,
00165                         unsigned int   flags)
00166 {
00167   DBusSocketSetPoll *self = socket_set_poll_cast (set);
00168   int i;
00169 
00170   for (i = 0; i < self->n_fds; i++)
00171     {
00172       if (self->fds[i].fd == fd)
00173         {
00174           self->fds[i].events = watch_flags_to_poll_events (flags);
00175           return;
00176         }
00177     }
00178 
00179   /* we allocated space when the socket was added */
00180   _dbus_assert (self->n_fds < self->n_reserved);
00181   _dbus_assert (self->n_reserved <= self->n_allocated);
00182 
00183   self->fds[self->n_fds].fd = fd;
00184   self->fds[self->n_fds].events = watch_flags_to_poll_events (flags);
00185   self->n_fds++;
00186 }
00187 
00188 static void
00189 socket_set_poll_disable (DBusSocketSet *set,
00190                          int            fd)
00191 {
00192   DBusSocketSetPoll *self = socket_set_poll_cast (set);
00193   int i;
00194 
00195   for (i = 0; i < self->n_fds; i++)
00196     {
00197       if (self->fds[i].fd == fd)
00198         {
00199           if (i != self->n_fds - 1)
00200             {
00201               self->fds[i].fd = self->fds[self->n_fds - 1].fd;
00202               self->fds[i].events = self->fds[self->n_fds - 1].events;
00203             }
00204 
00205           self->n_fds--;
00206           return;
00207         }
00208     }
00209 }
00210 
00211 static void
00212 socket_set_poll_remove (DBusSocketSet *set,
00213                         int            fd)
00214 {
00215   DBusSocketSetPoll *self = socket_set_poll_cast (set);
00216 
00217   socket_set_poll_disable (set, fd);
00218   self->n_reserved--;
00219 
00220   _dbus_verbose ("after removing fd %d from %p, %d en/%d res/%d alloc\n",
00221                  fd, self, self->n_fds, self->n_reserved, self->n_allocated);
00222   _dbus_assert (self->n_fds <= self->n_reserved);
00223   _dbus_assert (self->n_reserved <= self->n_allocated);
00224 
00225   if (self->n_reserved + MINIMUM_SIZE < self->n_allocated / 2)
00226     {
00227       /* Our array is twice as big as it needs to be - deflate it until it's
00228        * only slightly larger than the number reserved. */
00229       DBusPollFD *new_fds = dbus_realloc (self->fds,
00230           sizeof (DBusPollFD) * (self->n_reserved + MINIMUM_SIZE));
00231 
00232       _dbus_verbose ("before deflating %p, %d en/%d res/%d alloc\n",
00233                      self, self->n_fds, self->n_reserved, self->n_allocated);
00234 
00235       if (_DBUS_UNLIKELY (new_fds == NULL))
00236         {
00237           /* Weird. Oh well, never mind, the too-big array is untouched */
00238           return;
00239         }
00240 
00241       self->fds = new_fds;
00242       self->n_allocated = self->n_reserved;
00243     }
00244 }
00245 
00246 static unsigned int
00247 watch_flags_from_poll_revents (short revents)
00248 {
00249   unsigned int condition = 0;
00250 
00251   if (revents & _DBUS_POLLIN)
00252     condition |= DBUS_WATCH_READABLE;
00253   if (revents & _DBUS_POLLOUT)
00254     condition |= DBUS_WATCH_WRITABLE;
00255   if (revents & _DBUS_POLLHUP)
00256     condition |= DBUS_WATCH_HANGUP;
00257   if (revents & _DBUS_POLLERR)
00258     condition |= DBUS_WATCH_ERROR;
00259 
00260   if (_DBUS_UNLIKELY (revents & _DBUS_POLLNVAL))
00261     condition |= _DBUS_WATCH_NVAL;
00262 
00263   return condition;
00264 }
00265 
00268 static int
00269 socket_set_poll_poll (DBusSocketSet   *set,
00270                       DBusSocketEvent *revents,
00271                       int              max_events,
00272                       int              timeout_ms)
00273 {
00274   DBusSocketSetPoll *self = socket_set_poll_cast (set);
00275   int i;
00276   int n_events;
00277   int n_ready;
00278 
00279   _dbus_assert (max_events > 0);
00280 
00281   for (i = 0; i < self->n_fds; i++)
00282     self->fds[i].revents = 0;
00283 
00284   n_ready = _dbus_poll (self->fds, self->n_fds, timeout_ms);
00285 
00286   if (n_ready <= 0)
00287     return n_ready;
00288 
00289   n_events = 0;
00290 
00291   for (i = 0; i < self->n_fds; i++)
00292     {
00293       if (self->fds[i].revents != 0)
00294         {
00295           revents[n_events].fd = self->fds[i].fd;
00296           revents[n_events].flags = watch_flags_from_poll_revents (self->fds[i].revents);
00297 
00298           n_events += 1;
00299 
00300           /* We ignore events beyond max_events because we have nowhere to
00301            * put them. _dbus_poll is level-triggered, so we'll just be told
00302            * about them next time round the main loop anyway. */
00303           if (n_events == max_events)
00304             return n_events;
00305         }
00306     }
00307 
00308   return n_events;
00309 }
00310 
00311 DBusSocketSetClass _dbus_socket_set_poll_class = {
00312     socket_set_poll_free,
00313     socket_set_poll_add,
00314     socket_set_poll_remove,
00315     socket_set_poll_enable,
00316     socket_set_poll_disable,
00317     socket_set_poll_poll
00318 };
00319 
00320 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */