D-Bus
1.10.12
|
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_ENABLE_EMBEDDED_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 DBusPollable 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 (!_dbus_pollable_equals (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 %" DBUS_POLLABLE_FORMAT " to %p, %d en/%d res/%d alloc\n", 00146 _dbus_pollable_printable (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 DBusPollable 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 (_dbus_pollable_equals (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 DBusPollable 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 (_dbus_pollable_equals (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 DBusPollable 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 %" DBUS_POLLABLE_FORMAT " from %p, %d en/%d res/%d alloc\n", 00221 _dbus_pollable_printable (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 */