Overview
Comment: | OFNotificationCenter: Move posting out of the lock
This prevents a deadlock when modifying observers from a handler. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | notifications |
Files: | files | file ages | folders |
SHA3-256: |
93851ccd0f25e7778f8e6a51025d2dc4 |
User & Date: | js on 2021-10-31 18:02:13 |
Other Links: | branch diff | manifest | tags |
Context
2021-10-31
| ||
20:14 | OFNotificationCenter: Add support for blocks check-in: 108d360116 user: js tags: notifications | |
18:02 | OFNotificationCenter: Move posting out of the lock check-in: 93851ccd0f user: js tags: notifications | |
17:41 | Add OFNotificationCenter check-in: 611cde23ad user: js tags: notifications | |
Changes
Modified src/OFNotificationCenter.m from [c832dbfaa5] to [7d4ea0e843].
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" #import "OFNotificationCenter.h" #import "OFDictionary.h" #ifdef OF_HAVE_THREADS # import "OFMutex.h" #endif #import "OFSet.h" #import "OFString.h" @interface OFDefaultNotificationCenter: OFNotificationCenter @end | > | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" #import "OFNotificationCenter.h" #import "OFArray.h" #import "OFDictionary.h" #ifdef OF_HAVE_THREADS # import "OFMutex.h" #endif #import "OFSet.h" #import "OFString.h" @interface OFDefaultNotificationCenter: OFNotificationCenter @end @interface OFNotificationHandler: OFObject { @public id _observer; SEL _selector; unsigned long _selectorHash; id _object; } - (instancetype)initWithObserver: (id)observer selector: (SEL)selector object: (id)object; @end static OFNotificationCenter *defaultCenter; @implementation OFNotificationHandler - (instancetype)initWithObserver: (id)observer selector: (SEL)selector object: (id)object { self = [super init]; @try { |
︙ | ︙ | |||
72 73 74 75 76 77 78 | { [_observer release]; [_object release]; [super dealloc]; } | | | | | < | | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | { [_observer release]; [_object release]; [super dealloc]; } - (bool)isEqual: (OFNotificationHandler *)handler { if (![handler isKindOfClass: [OFNotificationHandler class]]) return false; if (![handler->_observer isEqual: _observer]) return false; if (!sel_isEqual(handler->_selector, _selector)) return false; if (handler->_object != _object && ![handler->_object isEqual: _object]) return false; return true; } - (unsigned long)hash { |
︙ | ︙ | |||
153 154 155 156 157 158 159 | - (void)addObserver: (id)observer selector: (SEL)selector name: (OFNotificationName)name object: (id)object { void *pool = objc_autoreleasePoolPush(); | < | > | < < | < < > > > > > | | < | < | < | < < < < < < < > > > > > > > > > > | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | - (void)addObserver: (id)observer selector: (SEL)selector name: (OFNotificationName)name object: (id)object { void *pool = objc_autoreleasePoolPush(); OFNotificationHandler *handler = [[[OFNotificationHandler alloc] initWithObserver: observer selector: selector object: object] autorelease]; #ifdef OF_HAVE_THREADS [_mutex lock]; @try { #endif OFMutableSet *notificationsForName = [_notifications objectForKey: name]; if (notificationsForName == nil) { notificationsForName = [OFMutableSet set]; [_notifications setObject: notificationsForName forKey: name]; } [notificationsForName addObject: handler]; #ifdef OF_HAVE_THREADS } @finally { [_mutex unlock]; } #endif objc_autoreleasePoolPop(pool); } - (void)removeObserver: (id)observer selector: (SEL)selector name: (OFNotificationName)name object: (id)object { void *pool = objc_autoreleasePoolPush(); OFNotificationHandler *handler = [[[OFNotificationHandler alloc] initWithObserver: observer selector: selector object: object] autorelease]; #ifdef OF_HAVE_THREADS [_mutex lock]; @try { #endif [[_notifications objectForKey: name] removeObject: handler]; #ifdef OF_HAVE_THREADS } @finally { [_mutex unlock]; } #endif objc_autoreleasePoolPop(pool); } - (void)postNotification: (OFNotification *)notification { void *pool = objc_autoreleasePoolPush(); OFMutableArray *matchedHandlers = [OFMutableArray array]; #ifdef OF_HAVE_THREADS [_mutex lock]; @try { #endif for (OFNotificationHandler *handler in [_notifications objectForKey: notification.name]) if (handler->_object == nil || handler->_object == notification.object) [matchedHandlers addObject: handler]; #ifdef OF_HAVE_THREADS } @finally { [_mutex unlock]; } #endif for (OFNotificationHandler *handler in matchedHandlers) { void (*callback)(id, SEL, OFNotification *) = (void (*)(id, SEL, OFNotification *)) [handler->_observer methodForSelector: handler->_selector]; callback(handler->_observer, handler->_selector, notification); } objc_autoreleasePoolPop(pool); } @end @implementation OFDefaultNotificationCenter - (instancetype)autorelease { return self; |
︙ | ︙ |