[vlc-devel] [PATCH 6/9] VLCKit: fix a deadlock case in VLCEventManager
Florent Pillet
fpillet at gmail.com
Fri Jul 11 01:35:08 CEST 2014
There is a case of recursion over mutexed code when cancelling calls for an object that may itself dealloc other objects with pending events (this has been witnessed)
---
Sources/VLCEventManager.m | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/Sources/VLCEventManager.m b/Sources/VLCEventManager.m
index 31d11dd..8b4ab27 100644
--- a/Sources/VLCEventManager.m
+++ b/Sources/VLCEventManager.m
@@ -268,10 +268,19 @@ static void * EventDispatcherMainLoop(void * user_data)
pthread_mutex_lock([self queueLock]);
[_pendingMessagesLock lock];
+ // Keep a hold on the secondary objects and release them only AFTER we have released our locks to prevents deadlocks.
+ // i.e. dealloc'ing a VLCMediaPlayer that has pending messages with its VLCMedia as message object,
+ // and these references are the last ones to the VLCMedia, so releasing message->u.object would dealloc the VLCMedia which in
+ // turn would call -cancelCallToObject, effectively causing a deadlock.
+ NSMutableArray *secondaryObjects = [[NSMutableArray alloc] init];
+
for (NSInteger i = _messageQueue.count - 1; i >= 0; i--) {
message_t *message = _messageQueue[i];
- if (message.target == target)
- [_messageQueue removeObjectAtIndex:i];
+ if (message.target == target) {
+ if (message.object != nil)
+ [secondaryObjects addObject:message.object];
+ [_messageQueue removeObjectAtIndex:(NSUInteger) i];
+ }
}
// Remove all pending messages
@@ -280,12 +289,20 @@ static void * EventDispatcherMainLoop(void * user_data)
for (NSInteger i = [messages count] - 1; i >= 0; i--) {
message_t *message = messages[i];
- if (message.target == target)
+ if (message.target == target) {
+ if (message.object != nil)
+ [secondaryObjects addObject:message.object];
[messages removeObjectAtIndex:(NSUInteger) i];
+ }
}
[_pendingMessagesLock unlock];
pthread_mutex_unlock([self queueLock]);
+
+ // secondaryObjects will be disposed of now, but just to make sure that ARC doesn't
+ // dispose it earlier, play a little trick to keep it alive up to this point by calling a selector
+ // keeping the objects alive until the mutex has been unlocked is crucial to preventing recursion+deadlock
+ [secondaryObjects removeAllObjects];
}
- (void)addMessageToHandleOnMainThread:(message_t *)message
--
1.8.5.2 (Apple Git-48)
More information about the vlc-devel
mailing list