Ticket #46496: QDBusConnection-Merge-the-dispatch-and-the-watch-and.patch
File QDBusConnection-Merge-the-dispatch-and-the-watch-and.patch, 7.2 KB (added by RJVB (René Bertin), 10 years ago) |
---|
-
qtbase/src/dbus/qdbusconnection_p.h
From eb99c28861f5e841f306cfe8689627fe0e9bf2e8 Mon Sep 17 00:00:00 2001 From: Thiago Macieira <thiago.macieira@intel.com> Date: Tue, 28 Oct 2014 19:26:17 -0700 Subject: [PATCH 2/3] QDBusConnection: Merge the dispatch and the watch-and-timeout locks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't need two anymore because they now protect the same thing: the state of the DBusConnection. The difference existed when it was possible for two threads to access the DBusConnection at the same time: one doing dispatching and one doing something else. Unfortunately, even though DBusConnection supports this, QtDBus doesn't. From d47c05b1889bb4f06203bbc65f4660b8d0128954 (2008-10-08): Details: if we're removing a timer or a watcher from our list, there's a race condition: one thread (not the QDBusConnection thread) could be asking for the removal (which causes an event to be sent), then deletes the pointer. In the meantime, QDBusConnection will process the timers and socket notifiers and could end up calling lidbus-1 with deleted pointers. That commit fixed the race condition but introduced a deadlock. Task-number: QTBUG-42189 Change-Id: I034038f763cbad3a67398909defd31a23c27c965 Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@digia.com> Reviewed-by: Albert Astals Cid <albert.astals@canonical.com> Reviewed-by: Frederik Gladhorn <frederik.gladhorn@theqtcompany.com> --- src/dbus/qdbusconnection_p.h | 16 +++++----------- src/dbus/qdbusintegrator.cpp | 22 +++++++++++----------- src/dbus/qdbusthreaddebug_p.h | 7 ------- 3 files changed, 16 insertions(+), 29 deletions(-)
290 290 QStringList serverConnectionNames; 291 291 292 292 ConnectionMode mode; 293 QDBusConnectionInterface *busService; 293 294 294 // members accessed in unlocked mode (except for deletion)295 // connection and server provide their own locking mechanisms296 // busService doesn't have state to be changed295 // the dispatch lock protects everything related to the DBusConnection or DBusServer 296 // including the timeouts and watches 297 QMutex dispatchLock; 297 298 DBusConnection *connection; 298 299 DBusServer *server; 299 QDBusConnectionInterface *busService;300 301 // watchers and timeouts are accessed from any thread302 // but the corresponding timer and QSocketNotifier must be handled303 // only in the object's thread304 QMutex watchAndTimeoutLock;305 300 WatcherHash watchers; 306 301 TimeoutHash timeouts; 307 302 PendingTimeoutList timeoutsPendingAdd; 308 303 309 // members accessed through a lock 310 QMutex dispatchLock; 304 // the master lock protects our own internal state 311 305 QReadWriteLock lock; 312 306 QDBusError lastError; 313 307 -
qtbase/src/dbus/qdbusintegrator.cpp
155 155 if (!q_dbus_timeout_get_enabled(timeout)) 156 156 return true; 157 157 158 QDBus WatchAndTimeoutLocker locker(AddTimeoutAction, d);158 QDBusDispatchLocker locker(AddTimeoutAction, d); 159 159 if (QCoreApplication::instance() && QThread::currentThread() == d->thread()) { 160 160 // correct thread 161 161 return qDBusRealAddTimeout(d, timeout, q_dbus_timeout_get_interval(timeout)); … … 190 190 191 191 QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data); 192 192 193 QDBus WatchAndTimeoutLocker locker(RemoveTimeoutAction, d);193 QDBusDispatchLocker locker(RemoveTimeoutAction, d); 194 194 195 195 // is it pending addition? 196 196 QDBusConnectionPrivate::PendingTimeoutList::iterator pit = d->timeoutsPendingAdd.begin(); … … 263 263 { 264 264 QDBusConnectionPrivate::Watcher watcher; 265 265 266 QDBus WatchAndTimeoutLocker locker(AddWatchAction, d);266 QDBusDispatchLocker locker(AddWatchAction, d); 267 267 if (flags & DBUS_WATCH_READABLE) { 268 268 //qDebug("addReadWatch %d", fd); 269 269 watcher.watch = watch; … … 297 297 QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data); 298 298 int fd = q_dbus_watch_get_unix_fd(watch); 299 299 300 QDBus WatchAndTimeoutLocker locker(RemoveWatchAction, d);300 QDBusDispatchLocker locker(RemoveWatchAction, d); 301 301 QDBusConnectionPrivate::WatcherHash::iterator i = d->watchers.find(fd); 302 302 while (i != d->watchers.end() && i.key() == fd) { 303 303 if (i.value().watch == watch) { … … 341 341 342 342 static void qDBusRealToggleWatch(QDBusConnectionPrivate *d, DBusWatch *watch, int fd) 343 343 { 344 QDBus WatchAndTimeoutLocker locker(ToggleWatchAction, d);344 QDBusDispatchLocker locker(ToggleWatchAction, d); 345 345 346 346 QDBusConnectionPrivate::WatcherHash::iterator i = d->watchers.find(fd); 347 347 while (i != d->watchers.end() && i.key() == fd) { … … 1016 1016 extern bool qDBusInitThreads(); 1017 1017 1018 1018 QDBusConnectionPrivate::QDBusConnectionPrivate(QObject *p) 1019 : QObject(p), ref(1), capabilities(0), mode(InvalidMode), connection(0), server(0),busService(0),1020 watchAndTimeoutLock(QMutex::Recursive), dispatchLock(QMutex::Recursive),1019 : QObject(p), ref(1), capabilities(0), mode(InvalidMode), busService(0), 1020 dispatchLock(QMutex::Recursive), connection(0), server(0), 1021 1021 rootNode(QString(QLatin1Char('/'))), 1022 1022 anonymousAuthenticationAllowed(false) 1023 1023 { … … 1127 1127 void QDBusConnectionPrivate::timerEvent(QTimerEvent *e) 1128 1128 { 1129 1129 { 1130 QDBus WatchAndTimeoutLocker locker(TimerEventAction, this);1130 QDBusDispatchLocker locker(TimerEventAction, this); 1131 1131 DBusTimeout *timeout = timeouts.value(e->timerId(), 0); 1132 1132 if (timeout) 1133 1133 q_dbus_timeout_handle(timeout); … … 1146 1146 switch (ev->subtype) 1147 1147 { 1148 1148 case QDBusConnectionCallbackEvent::AddTimeout: { 1149 QDBus WatchAndTimeoutLocker locker(RealAddTimeoutAction, this);1149 QDBusDispatchLocker locker(RealAddTimeoutAction, this); 1150 1150 while (!timeoutsPendingAdd.isEmpty()) { 1151 1151 QPair<DBusTimeout *, int> entry = timeoutsPendingAdd.takeFirst(); 1152 1152 qDBusRealAddTimeout(this, entry.first, entry.second); … … 1182 1182 QVarLengthArray<DBusWatch *, 2> pendingWatches; 1183 1183 1184 1184 { 1185 QDBus WatchAndTimeoutLocker locker(SocketReadAction, this);1185 QDBusDispatchLocker locker(SocketReadAction, this); 1186 1186 WatcherHash::ConstIterator it = watchers.constFind(fd); 1187 1187 while (it != watchers.constEnd() && it.key() == fd) { 1188 1188 if (it->watch && it->read && it->read->isEnabled()) … … 1202 1202 QVarLengthArray<DBusWatch *, 2> pendingWatches; 1203 1203 1204 1204 { 1205 QDBus WatchAndTimeoutLocker locker(SocketWriteAction, this);1205 QDBusDispatchLocker locker(SocketWriteAction, this); 1206 1206 WatcherHash::ConstIterator it = watchers.constFind(fd); 1207 1207 while (it != watchers.constEnd() && it.key() == fd) { 1208 1208 if (it->watch && it->write && it->write->isEnabled()) -
qtbase/src/dbus/qdbusthreaddebug_p.h
207 207 { } 208 208 }; 209 209 210 struct QDBusWatchAndTimeoutLocker: QDBusMutexLocker211 {212 inline QDBusWatchAndTimeoutLocker(ThreadAction a, QDBusConnectionPrivate *s)213 : QDBusMutexLocker(a, s, &s->watchAndTimeoutLock)214 { }215 };216 217 210 #if QDBUS_THREAD_DEBUG 218 211 # define SEM_ACQUIRE(action, sem) \ 219 212 do { \