Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash on SCRecordSession Line 161 #423

Open
byjoh opened this issue Jun 17, 2018 · 0 comments
Open

Crash on SCRecordSession Line 161 #423

byjoh opened this issue Jun 17, 2018 · 0 comments

Comments

@byjoh
Copy link

byjoh commented Jun 17, 2018

I have received multiple crash reports from various users over the last month related to this same issue (per Crashlytics: BUG IN CLIENT OF LIBDISPATCH: dispatch_sync called on queue already owned by current thread). All devices are running 11.3.1.

Crashed: me.corsin.SCRecorder.Audio
0  libdispatch.dylib              0x1841cec54 _dispatch_sync_wait + 604
1  SCRecorder                     0x10898df9c -[SCRecordSession dispatchSyncOnSessionQueue:] (SCRecordSession.m:161)
2  SCRecorder                     0x10898df9c -[SCRecordSession dispatchSyncOnSessionQueue:] (SCRecordSession.m:161)
3  SCRecorder                     0x10898fc80 -[SCRecordSession appendRecordSegmentUrl:info:error:completionHandler:] (SCRecordSession.m:491)
4  SCRecorder                     0x108990434 __56-[SCRecordSession endSegmentWithInfo:completionHandler:]_block_invoke.257 (SCRecordSession.m:523)
5  SCRecorder                     0x108990230 __56-[SCRecordSession endSegmentWithInfo:completionHandler:]_block_invoke_2 (SCRecordSession.m:525)
6  libdispatch.dylib              0x1841c0ae4 _dispatch_client_callout + 16
7  libdispatch.dylib              0x1841c9640 _dispatch_queue_barrier_sync_invoke_and_complete + 56
8  SCRecorder                     0x1089900b4 __56-[SCRecordSession endSegmentWithInfo:completionHandler:]_block_invoke (SCRecordSession.m:537)
9  SCRecorder                     0x10898df74 -[SCRecordSession dispatchSyncOnSessionQueue:] (SCRecordSession.m:159)
10 SCRecorder                     0x10898ffbc -[SCRecordSession endSegmentWithInfo:completionHandler:] (SCRecordSession.m:539)
11 SCRecorder                     0x1089849fc __20-[SCRecorder pause:]_block_invoke (SCRecorder.m:502)
12 libdispatch.dylib              0x1841c0b24 _dispatch_call_block_and_release + 24
13 libdispatch.dylib              0x1841c0ae4 _dispatch_client_callout + 16
14 libdispatch.dylib              0x1841caa38 _dispatch_queue_serial_drain$VARIANT$mp + 608
15 libdispatch.dylib              0x1841cb380 _dispatch_queue_invoke$VARIANT$mp + 336
16 libdispatch.dylib              0x1841cbd4c _dispatch_root_queue_drain_deferred_wlh$VARIANT$mp + 340
17 libdispatch.dylib              0x1841d411c _dispatch_workloop_worker_thread$VARIANT$mp + 668
18 libsystem_pthread.dylib        0x1844f3e70 _pthread_wqthread + 860
19 libsystem_pthread.dylib        0x1844f3b08 start_wqthread + 4

I believe what is happening is as described in this pseudocode

dispatch_sync(queueA, ^{
    dispatch_sync(queueB, ^{
        // dispatch_get_current_queue() is B, but A is blocked, 
        // so a dispatch_sync(A,b) will deadlock.
        dispatch_sync(queueA, ^{
            // some task
        });
    });
});

because if you start at the method line 5 in the stack trace

- (BOOL)endSegmentWithInfo:(NSDictionary *)info completionHandler:(void(^)(SCRecordSessionSegment *segment, NSError* error))completionHandler {
    __block BOOL success = NO;
    
    [self dispatchSyncOnSessionQueue:^{
        dispatch_sync(_audioQueue, ^{
            if (_recordSegmentReady) {
                _recordSegmentReady = NO;
                success = YES;
                
                AVAssetWriter *writer = _assetWriter;
                
                if (writer != nil) {
                    BOOL currentSegmentEmpty = (!_currentSegmentHasVideo && !_currentSegmentHasAudio);
                    
                    if (currentSegmentEmpty) {
                        [writer cancelWriting];
                        [self _destroyAssetWriter];
                        
                        [self removeFile:writer.outputURL];
                        
                        if (completionHandler != nil) {
                            dispatch_async(dispatch_get_main_queue(), ^{
                                completionHandler(nil, nil);
                            });
                        }
                    } else {
                        //                NSLog(@"Ending session at %fs", CMTimeGetSeconds(_currentSegmentDuration));
                        [writer endSessionAtSourceTime:CMTimeAdd(_currentSegmentDuration, _sessionStartTime)];

                        [writer finishWritingWithCompletionHandler: ^{
                            [self appendRecordSegmentUrl:writer.outputURL info:info error:writer.error completionHandler:completionHandler];
                        }];
                    }
                } else {
                    [_movieFileOutput stopRecording];
                }
            } else {
                dispatch_async(dispatch_get_main_queue(), ^{
                    if (completionHandler != nil) {
                        completionHandler(nil, [SCRecordSession createError:@"The current record segment is not ready for this operation"]);
                    }
                });
            }
        });
    }];
    
    return success;
}

this creates a similar nesting queue structure session queue -> audioQueue -> sessionQueue. I am not strong in this area though so might be going down the wrong path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant