Skip to content

Deadlock when checking isDataAvailable and performing Query #11

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

Closed
lkraider opened this issue Aug 14, 2015 · 41 comments
Closed

Deadlock when checking isDataAvailable and performing Query #11

lkraider opened this issue Aug 14, 2015 · 41 comments

Comments

@lkraider
Copy link

While trying to findObjectsInBackgroundWithBlock and checking isDataAvailable, the following can occur:

Main Thread:
#0  0x00000001984530c0 in __psynch_mutexwait ()
#1  0x00000001984ed494 in _pthread_mutex_lock ()
#2  0x00000001002a8f78 in -[PFObject state] at /Users/nlutsenko/src/parse/ios-client/Parse/PFObject.m:2047
#3  0x00000001002aab20 in -[PFObject isDataAvailable] at /Users/nlutsenko/src/parse/ios-client/Parse/PFObject.m:2341
...


Internal Parse NSOperationQueue Serial Thread:
#0  0x00000001984530c0 in __psynch_mutexwait ()
#1  0x00000001984ed494 in _pthread_mutex_lock ()
#2  0x00000001002a523c in -[PFObject(Private) _mergeAfterFetchWithResult:decoder:completeData:] at /Users/nlutsenko/src/parse/ios-client/Parse/PFObject.m:1587
...
#22 0x00000001002a12ac in +[PFObject(Private) _objectFromDictionary:defaultClassName:selectedKeys:] at /Users/nlutsenko/src/parse/ios-client/Parse/PFObject.m:1041
#23 0x00000001002c9724 in __78-[PFQueryController findObjectsAsyncForQueryState:withCancellationToken:user:]_block_invoke26 at /Users/nlutsenko/src/parse/ios-client/Parse/Internal/Query/Controller/PFQueryController.m:84
...
#59 0x00000001002f9db8 in -[PFTaskHTTPRequestOperation _operationDidFinish] at /Users/nlutsenko/src/parse/ios-client/Parse/Internal/HTTPRequest/PFTaskHTTPRequestOperation.m:51
#60 0x000000010028d16c in -[PFCommandNetworkOperation _operationDidFinish] at /Users/nlutsenko/src/parse/ios-client/Parse/Internal/HTTPRequest/PFCommandNetworkOperation.m:78
...
----------
Enqueued from Background Thread:
...
#3  0x00000001002de250 in -[PFRESTCommandRunner _runCommandAsync:withCancellationToken:] at /Users/nlutsenko/src/parse/ios-client/Parse/Internal/Commands/PFRESTCommandRunner.m:168
...
#7  0x00000001002c9398 in __78-[PFQueryController findObjectsAsyncForQueryState:withCancellationToken:user:]_block_invoke at /Users/nlutsenko/src/parse/ios-client/Parse/Internal/Query/Controller/PFQueryController.m:64
...
----------
Enqueued from Main Thread:
#0  0x0000000100743d50 in _dispatch_async_f_slow ()
#1  0x000000010030cf88 in -[BFExecutor execute:] at /Users/chrisp/src/ios-sdk-3/Bolts-IOS/Bolts/Common/BFExecutor.m:109
...
#19 0x00000001002bfaf8 in -[PFQuery findObjectsInBackgroundWithBlock:] at /Users/nlutsenko/src/parse/ios-client/Parse/PFQuery.m:806

@lkraider lkraider changed the title Deadlock when checking isDataAvailable and performin Query Deadlock when checking isDataAvailable and performing Query Aug 14, 2015
@nlutsenko nlutsenko self-assigned this Aug 14, 2015
@nlutsenko
Copy link
Contributor

Hey @lkraider, thanks for the report.
Stack trace is super helpful... I'll look into this one.

@nlutsenko
Copy link
Contributor

Can you also please check if you are running into the same issue on the latest SDK? 1.8.0.
There is quite a bit of things that changed since 1.7.5, specifically around these methods and how queries work.

@lkraider
Copy link
Author

Just checking with 1.8.0, still getting deadlocks where two threads try to access [PFObject objectId] (in this case, one thread access local datastorage (parse.sqlite.db.queue serial thread), another loading from network (NSOperationQueue serial thread)).

@nlutsenko
Copy link
Contributor

Thanks.
Any chance you have a repro project or a code snippet for this?
I've looked into the issue in the meantime and while stack trace is helpful (would be awesome to get one from 1.8.0 as well), specifically in this case it's somewhat hard to track it down, as I think it depends on the schema of your object (child objects if any, as well as fields on the object).

@lkraider
Copy link
Author

Adding a new trace (3 threads deadlock):

Thread 1 Queue : com.apple.main-thread (serial)
#0  0x00000001984530c0 in __psynch_mutexwait ()
#1  0x00000001984ed494 in _pthread_mutex_lock ()
#2  0x00000001002a6198 in -[PFObject _state] ()
#3  0x00000001002a7b90 in -[PFObject isDataAvailable] ()
...



Thread 11 Queue : NSOperationQueue :: NSOperation (serial)
#0  0x00000001984530c0 in __psynch_mutexwait ()
#1  0x00000001984ed494 in _pthread_mutex_lock ()
#2  0x00000001002a6198 in -[PFObject _state] ()
#3  0x00000001002a63f8 in -[PFObject objectId] ()
#4  0x00000001002e99c8 in -[PFPointerOrLocalIdObjectEncoder encodeParseObject:] ()
...
#8  0x00000001002e7804 in +[PFJSONCacheItem cacheFromObject:] ()
...
#35 0x00000001002f4660 in __80-[PFCloudCodeController callCloudCodeFunctionAsync:withParameters:sessionToken:]_block_invoke_2 ()
...



Thread 37 Queue : com.parse.sqlite.db.queue (serial)
#0  0x00000001984530c0 in __psynch_mutexwait ()
#1  0x00000001984ed494 in _pthread_mutex_lock ()
#2  0x00000001002a6198 in -[PFObject _state] ()
#3  0x00000001002a63f8 in -[PFObject objectId] ()
#4  0x00000001002e9f30 in -[PFOfflineObjectEncoder encodeParseObject:] ()
...
#7  0x0000000100296aec in __59-[PFObjectState dictionaryRepresentationWithObjectEncoder:]_block_invoke ()
...
#10 0x0000000100296a50 in -[PFObjectState dictionaryRepresentationWithObjectEncoder:] ()
#11 0x000000010029fe90 in -[PFObject(Private) RESTDictionaryWithObjectEncoder:operationSetUUIDs:state:operationSetQueue:] ()
#12 0x000000010029fdb8 in -[PFObject(Private) RESTDictionaryWithObjectEncoder:operationSetUUIDs:] ()
#13 0x0000000100308e94 in __54-[PFOfflineStore saveObjectLocallyAsync:key:database:]_block_invoke261 ()
...
----------
Enqueued from com.parse.sqlite.db.queue (Thread 37) (serial)
...
#6  0x000000010031061c in -[PFSQLiteDatabase executeSQLAsync:withArgumentsInArray:] ()
#7  0x000000010030db50 in -[PFOfflineStore getOrCreateUUIDAsyncForObject:database:] ()
...
----------
Enqueued from com.parse.sqlite.db.queue (Thread 37) (serial)
...
#6  0x000000010031048c in -[PFSQLiteDatabase executeQueryAsync:withArgumentsInArray:] ()
#7  0x000000010030699c in -[PFOfflineStore fetchObjectLocallyAsync:database:] ()
#8  0x00000001003081ec in -[PFOfflineStore saveObjectLocallyAsync:withChildren:database:] ()
#9  0x0000000100307f84 in -[PFOfflineStore saveObjectLocallyAsync:includeChildren:database:] ()
...
----------
Enqueued from com.parse.sqlite.db.queue (Thread 37) (serial)
...
#6  0x000000010031061c in -[PFSQLiteDatabase executeSQLAsync:withArgumentsInArray:] ()
#7  0x000000010030ed64 in __60-[PFOfflineStore _performDatabaseTransactionAsyncWithBlock:]_block_invoke ()
#8  0x000000010030f064 in __58-[PFOfflineStore _performDatabaseOperationAsyncWithBlock:]_block_invoke ()
...
#16 0x00000001002ac7f4 in __56-[PFSQLiteDatabaseController openDatabaseWithNameAsync:]_block_invoke_2 ()
...
----------
Enqueued from com.apple.root.default-qos (Thread 11) (serial)
...
#6  0x000000010030f900 in -[PFSQLiteDatabase openAsync] ()
#7  0x00000001002ac65c in __56-[PFSQLiteDatabaseController openDatabaseWithNameAsync:]_block_invoke ()
...
----------
Enqueued from com.parse.asynctaskqueue.sync (Thread 35) (serial)
...
#6  0x00000001002817b8 in __28-[PFAsyncTaskQueue enqueue:]_block_invoke ()
...
----------
Enqueued from com.parse.object.pin.cache (Thread 0) (serial)
...
#1  0x000000010028171c in -[PFAsyncTaskQueue enqueue:] ()
#2  0x00000001002ac558 in -[PFSQLiteDatabaseController openDatabaseWithNameAsync:] ()
#3  0x000000010030ef74 in -[PFOfflineStore _performDatabaseOperationAsyncWithBlock:] ()
#4  0x0000000100309758 in -[PFOfflineStore findAsyncForQueryState:user:pin:isCount:] ()
#5  0x0000000100309450 in -[PFOfflineStore findAsyncForQueryState:user:pin:] ()
#6  0x00000001002e3df8 in __46-[PFPinningObjectStore fetchPinAsyncWithName:]_block_invoke_2 ()
...
#13 0x00000001002e3c84 in __46-[PFPinningObjectStore fetchPinAsyncWithName:]_block_invoke ()
...
----------
Enqueued from com.apple.main-thread (Thread 1) (serial)
...
#6  0x00000001002e3b1c in -[PFPinningObjectStore fetchPinAsyncWithName:] ()
#7  0x00000001002e4a14 in -[PFPinningObjectStore unpinAllObjectsAsyncWithPinName:] ()
#8  0x00000001002ab83c in +[PFObject unpinAllObjectsInBackgroundWithName:] ()
#9  0x00000001002ab78c in +[PFObject unpinAllObjectsInBackgroundWithName:block:] ()
...


@parse-github-bot
Copy link

This issue has not been updated for 7 days. If you have additional information to help pinpoint this issue as an SDK bug, please comment on this issue. We will close this issue in 7 days if no additional information is provided. Thank you for your feedback.

@nlutsenko
Copy link
Contributor

@lkraider, thanks for the stack trace. I am marking this as needs investigation, so it won't get automatically closed.
From the stack trace - it looks like after #102 is merged in - the problem is going to be resolved.
Feel free to check out the branch attached to it and let me know if it works for you in the meantime.

@lkraider
Copy link
Author

I am testing with that branch, I am now getting a deadlock with 100% CPU usage from a call on the main thread ending in PFPropertyInfo:

Thread 1 Queue : com.parse.object.subclassing.data.access (serial)
#0  in OSAtomicCompareAndSwap64Barrier ()
#1  in pthread_rwlock_unlock ()
#2  in property_copyAttributeValue ()
#3  in safeStringWithPropertyAttributeValue at Parse/Internal/PropertyInfo/PFPropertyInfo.m:19
#4  in -[PFPropertyInfo initWithClass:name:associationType:] at Parse/Internal/PropertyInfo/PFPropertyInfo.m:74
#5  in -[PFPropertyInfo initWithClass:name:] at Parse/Internal/PropertyInfo/PFPropertyInfo.m:47
#6  in +[PFPropertyInfo propertyInfoWithClass:name:] at Parse/Internal/PropertyInfo/PFPropertyInfo.m:123
#7  in -[PFObjectSubclassInfo _rawPropertyInfoForSelector:] at Parse/Internal/Object/Subclassing/PFObjectSubclassInfo.m:187
#8  in __61-[PFObjectSubclassInfo forwardingMethodSignatureForSelector:]_block_invoke at Parse/Internal/Object/Subclassing/PFObjectSubclassInfo.m:126
#9  in _dispatch_client_callout ()
#10 in _dispatch_barrier_sync_f_invoke ()
#11 in -[PFObjectSubclassInfo forwardingMethodSignatureForSelector:] at Parse/Internal/Object/Subclassing/PFObjectSubclassInfo.m:120
#12 in -[PFObjectSubclassingController forwardingMethodSignatureForSelector:ofClass:] at Parse/Internal/Object/Subclassing/PFObjectSubclassingController.m:175
#13 in +[PFObject resolveInstanceMethod:] at Parse/PFObject.m:2405
#14 in _class_resolveInstanceMethod(objc_class*, objc_selector*, objc_object*) ()
#15 in lookUpImpOrForward ()
#16 in _objc_msgSend_uncached_impcache ()

I am not sure where the other lock is coming from. This is from an property access in a PFObject subclass, example calling code in AppDelegate:

assertMainThread();
[[Crashlytics sharedInstance] setUserIdentifier:[UserManager sharedInstance].user.objectId];
[[Crashlytics sharedInstance] setUserName:[UserManager sharedInstance].user.name];
[[Crashlytics sharedInstance] setUserEmail:[UserManager sharedInstance].user.email]; // <-- deadlock here

Deadlock happens in the last line.

@nlutsenko
Copy link
Contributor

Deadlock usually involves more than a single thread, a chance you can attach stack trace for all of them?

@richardjrossiii
Copy link
Contributor

@lkraider Can you try with the latest master? #129 has improved the performance significantly with PFPropertyInfo.

@lkraider
Copy link
Author

Created another situation, the full stack trace is here:
https://gist.github.com/lkraider/4accac93b273136f0c3b

Branch is nlutsenko.containers. I will be able to try the master branch next week.

@nlutsenko
Copy link
Contributor

This doesn't seem to be related at all to deadlocks, but rather as @richardjrossiii pointed out to #129 that was landed on master.
I've just rebased that branch on the master, so it contains both removed mutable containers and the fix from today.

@lkraider
Copy link
Author

The master version got rid of the atomic spinlock problem, here is a backtrace of the deadlock I am getting now which is again a 3 thread deadlock:
https://gist.github.com/lkraider/c82aeff713bf375ebf05

This is using the local storage for queries also.

@richardjrossiii
Copy link
Contributor

@lkraider Thanks for the awesome stack-trace! If this happens again, can we also get the stack-trace emitted by doing thread backtrace all in lldb? It will provide us with information on the arguments that every stack frame was called with, which will help in determining which objects are deadlocking.

@lkraider
Copy link
Author

Here is one with the thread backtrace all frames:
https://gist.github.com/lkraider/dece1757ab6c4cb1651d

I could find the same object on two threads.

@lkraider
Copy link
Author

I updated the gist, it seems the lock orders are like this:
ParentObject->ChildObject
ChildObject->ParentObject

And somehow this causes the deadlock of one cycle waiting for the other.

@richardjrossiii
Copy link
Contributor

Thanks for the super awesome backtrace.

One more request, if you would oblige me. I have created a new branch richardross.synchronized.deadlock, which includes @nlutsenko's mutable container patch, which will add every time we use @synchronized into your stack trace as well as what object it's on (when using thread backtrace all).

This should make it really easy to see which objects are being locked from where.

@lkraider
Copy link
Author

lkraider commented Sep 2, 2015

It seems something broke in this branch, I am not getting any PFQuery results for findObjectsInBackgroundWithBlock while countObjectsInBackgroundWithBlock seems to work (for the same query).

Both NSArray and NSError are nil in the result block.

I am getting in the logs when calling getObjectInBackgroundWithId:

[Error]: No results matched the query. (Code: 101, Version: 1.8.2)

Any idea why PFQuery would be broken?

@rudywen
Copy link

rudywen commented Sep 11, 2015

I'm also running into the same problem, any updates on this issue?

@rdbayer
Copy link

rdbayer commented Sep 21, 2015

I want to bump the priority of this. We are also experiencing a deadlock in our app which is an absolutely showstopper for being able to ship. I'm not 100% sure if it's the same issue as this (I don't see isDataAvailable called in the stack trace), but I'm attaching it to this task, and am pasting the full backtrace below.

I want to again emphasize what a massive problem this is. Deadlock is actually even worse than a crash in terms of user experience, and is absolutely breaking for our app. We will need to switch to another framework than Parse (despite the expensive switching cost) if this cannot be resolved.

@rdbayer
Copy link

rdbayer commented Sep 21, 2015

Here is the full backtrace:

(lldb) bt all
* thread #1: tid = 0xa07aae, 0x000000010f4df166 libsystem_kernel.dylib`__psynch_mutexwait + 10, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  * frame #0: 0x000000010f4df166 libsystem_kernel.dylib`__psynch_mutexwait + 10
    frame #1: 0x000000010f50e78a libsystem_pthread.dylib`_pthread_mutex_lock + 480
    frame #2: 0x000000010aaf0f98 Breakaway`-[PFObject objectForKey:](self=0x00007f8e5cd3da50, _cmd=, key=) + 57 at PFObject.m:2555
    frame #3: 0x000000010aaf4736 Breakaway`__34+[PFObject resolveInstanceMethod:]_block_invoke1160(.block_descriptor=0x00007f8e5cd527c0, self=) + 39 at PFObject.m:2844
    frame #4: 0x000000010a923818 Breakaway`Breakaway.MissionViewDescriptionCell.configureCellForMissionController (missionController=0x00007f8e5a5608d0, self=0x00007f8e5f76b230)(Breakaway.MissionViewController) -> Breakaway.MissionViewDescriptionCell + 200 at MissionViewDescriptionCell.swift:29
    frame #5: 0x000000010a881bc8 Breakaway`Breakaway.MissionViewController.tableView (tableView=0x00007f8e5a8b8800, indexPath=0x00007f8e5a5f3130, self=0x00007f8e5a5608d0)(ObjectiveC.UITableView, cellForRowAtIndexPath : ObjectiveC.NSIndexPath) -> ObjectiveC.UITableViewCell + 376 at MissionViewController.swift:660
    frame #6: 0x000000010a8822df Breakaway`@objc Breakaway.MissionViewController.tableView (Breakaway.MissionViewController)(ObjectiveC.UITableView, cellForRowAtIndexPath : ObjectiveC.NSIndexPath) -> ObjectiveC.UITableViewCell + 79 at MissionViewController.swift:0
    frame #7: 0x000000010a8811bf Breakaway`Breakaway.MissionViewController.tableView (tableView=0x00007f8e5a8b8800, indexPath=0x00007f8e5a5f3130, self=0x00007f8e5a5608d0)(ObjectiveC.UITableView, heightForRowAtIndexPath : ObjectiveC.NSIndexPath) -> CoreGraphics.CGFloat + 223 at MissionViewController.swift:642
    frame #8: 0x000000010a881a3f Breakaway`@objc Breakaway.MissionViewController.tableView (Breakaway.MissionViewController)(ObjectiveC.UITableView, heightForRowAtIndexPath : ObjectiveC.NSIndexPath) -> CoreGraphics.CGFloat + 79 at MissionViewController.swift:0
    frame #9: 0x000000010d0c52ab UIKit`__66-[UISectionRowData refreshWithSection:tableView:tableViewRowData:]_block_invoke + 302
    frame #10: 0x000000010d0c493e UIKit`-[UISectionRowData refreshWithSection:tableView:tableViewRowData:] + 4125
    frame #11: 0x000000010d0c7299 UIKit`-[UITableViewRowData ensureAllSectionsAreValid] + 109
    frame #12: 0x000000010cf14c86 UIKit`-[UITableView _endCellAnimationsWithContext:] + 505
    frame #13: 0x000000010a887b14 Breakaway`Breakaway.MissionViewController.(self=0x00007f8e5a5608d0, index=0xc000000000000096) -> (Swift.Optional) -> ()).(closure #1) + 260 at MissionViewController.swift:473
    frame #14: 0x000000010a7feb97 Breakaway`reabstraction thunk helper from @callee_owned () -> (@unowned ()) to @callee_unowned @objc_block () -> (@unowned ()) + 39 at PushNotification.swift:0
    frame #15: 0x000000010a8a43c3 Breakaway`reabstraction thunk helper from @callee_unowned @objc_block () -> (@unowned ()) to @callee_owned () -> (@unowned ()) + 19 at UIViewExtensions.swift:0
    frame #16: 0x000000010a8a3269 Breakaway`static ext.Breakaway.ObjectiveC.UIView.suspendAnimationsForBlock (block=, self=)(() -> ()) -> () + 105 at UIViewExtensions.swift:41
    frame #17: 0x000000010a8a3333 Breakaway`@objc static ext.Breakaway.ObjectiveC.UIView.suspendAnimationsForBlock (ObjectiveC.UIView.Type)(() -> ()) -> () + 115 at UIViewExtensions.swift:0
    frame #18: 0x000000010a875532 Breakaway`Breakaway.MissionViewController.stepInfoUpdated (stepInfo=Some, self=0x00007f8e5a5608d0)(Swift.Optional) -> () + 4786 at MissionViewController.swift:474
    frame #19: 0x000000010a87e50e Breakaway`protocol witness for Breakaway.StepEventViewDelegate.stepInfoUpdated (Breakaway.StepEventViewDelegate.Self)(Swift.Optional) -> () in conformance Breakaway.MissionViewController : Breakaway.StepEventViewDelegate in Breakaway + 110 at MissionViewController.swift:460
    frame #20: 0x000000010a91d3dd Breakaway`Breakaway.StepEventView.(tappedButton=0x00007f8e5f8f6310, otherButton=0x00007f8e5f8f3630, resultIndex=Worked, self=0x00007f8e5f76f660) (Breakaway.StepEventView)(ObjectiveC.UIButton, otherButton : ObjectiveC.UIButton, resultIndex : Breakaway.StepEventResult) -> () + 6589 at StepEventView.swift:203
    frame #21: 0x000000010a919ccc Breakaway`Breakaway.StepEventView.workedButtonTapped (self=0x00007f8e5f76f660)() -> () + 364 at StepEventView.swift:108
    frame #22: 0x000000010a919d02 Breakaway`@objc Breakaway.StepEventView.workedButtonTapped (Breakaway.StepEventView)() -> () + 34 at StepEventView.swift:0
    frame #23: 0x000000010ce3bd62 UIKit`-[UIApplication sendAction:to:from:forEvent:] + 75
    frame #24: 0x000000010cf4d50a UIKit`-[UIControl _sendActionsForEvents:withEvent:] + 467
    frame #25: 0x000000010cf4c8d9 UIKit`-[UIControl touchesEnded:withEvent:] + 522
    frame #26: 0x000000010ce88958 UIKit`-[UIWindow _sendTouchesForEvent:] + 735
    frame #27: 0x000000010ce89282 UIKit`-[UIWindow sendEvent:] + 682
    frame #28: 0x000000010ce4f541 UIKit`-[UIApplication sendEvent:] + 246
    frame #29: 0x000000010ce5ccdc UIKit`_UIApplicationHandleEventFromQueueEvent + 18265
    frame #30: 0x000000010ce3759c UIKit`_UIApplicationHandleEventQueue + 2066
    frame #31: 0x000000010c4cf431 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    frame #32: 0x000000010c4c52fd CoreFoundation`__CFRunLoopDoSources0 + 269
    frame #33: 0x000000010c4c4934 CoreFoundation`__CFRunLoopRun + 868
    frame #34: 0x000000010c4c4366 CoreFoundation`CFRunLoopRunSpecific + 470
    frame #35: 0x000000010ec35a3e GraphicsServices`GSEventRunModal + 161
    frame #36: 0x000000010ce3a8c0 UIKit`UIApplicationMain + 1282
    frame #37: 0x000000010a8a1917 Breakaway`main + 135 at AppDelegate.swift:15
    frame #38: 0x000000010f1d7145 libdyld.dylib`start + 1
    frame #39: 0x000000010f1d7145 libdyld.dylib`start + 1
  thread #2: tid = 0xa07ad7, 0x000000010f4e0232 libsystem_kernel.dylib`kevent64 + 10, queue = 'com.apple.libdispatch-manager'
    frame #0: 0x000000010f4e0232 libsystem_kernel.dylib`kevent64 + 10
    frame #1: 0x000000010f19276c libdispatch.dylib`_dispatch_mgr_invoke + 247
    frame #2: 0x000000010f192511 libdispatch.dylib`_dispatch_mgr_thread + 54
  thread #4: tid = 0xa07ad9, 0x000000010f4df166 libsystem_kernel.dylib`__psynch_mutexwait + 10, queue = 'com.apple.root.default-qos'
    frame #0: 0x000000010f4df166 libsystem_kernel.dylib`__psynch_mutexwait + 10
    frame #1: 0x000000010f50e78a libsystem_pthread.dylib`_pthread_mutex_lock + 480
    frame #2: 0x000000010aaed780 Breakaway`-[PFObject state](self=0x00007f8e5cd490f0, _cmd=) + 32 at PFObject.m:2047
    frame #3: 0x000000010aaeda22 Breakaway`-[PFObject objectId](self=, _cmd=) + 24 at PFObject.m:2075
    frame #4: 0x000000010ab2d673 Breakaway`-[PFPointerOrLocalIdObjectEncoder encodeParseObject:](self=, _cmd=, object=0x00007f8e5cd490f0) + 65 at PFEncoder.m:144
    frame #5: 0x000000010ab2cdc4 Breakaway`-[PFEncoder encodeObject:](self=, _cmd=, object=) + 113 at PFEncoder.m:35
    frame #6: 0x000000010ab2d29f Breakaway`-[PFEncoder encodeObject:](self=0x00007f8e5a671ca0, _cmd=, object=) + 1356 at PFEncoder.m:86
    frame #7: 0x000000010ab2bdf2 Breakaway`-[PFJSONCacheItem initWithObject:](self=, _cmd=, object=) + 126 at PFInternalUtils.m:333
    frame #8: 0x000000010ab2bf70 Breakaway`+[PFJSONCacheItem cacheFromObject:](self=, _cmd=, object=) + 69 at PFInternalUtils.m:345
    frame #9: 0x000000010aae5148 Breakaway`-[PFObject(self=0x00007f8e5cd4ff00, _cmd=, object=, key=) checkForChangesToMutableContainer:forKey:] + 207 at PFObject.m:916
    frame #10: 0x000000010aae5414 Breakaway`__55-[PFObject(.block_descriptor=0x000000011b9e67d8, key=, obj=, stop=) checkForChangesToMutableContainers]_block_invoke + 146 at PFObject.m:935
    frame #11: 0x000000010c50fcd5 CoreFoundation`__65-[__NSDictionaryI enumerateKeysAndObjectsWithOptions:usingBlock:]_block_invoke + 85
    frame #12: 0x000000010c50fbec CoreFoundation`-[__NSDictionaryI enumerateKeysAndObjectsWithOptions:usingBlock:] + 236
    frame #13: 0x000000010aae531b Breakaway`-[PFObject(self=, _cmd=) checkForChangesToMutableContainers] + 236 at PFObject.m:933
    frame #14: 0x000000010aae4b06 Breakaway`-[PFObject(self=0x00007f8e5cd4ff00, _cmd=, considerChildren=false) isDirty:] + 65 at PFObject.m:860
    frame #15: 0x000000010aae0ecd Breakaway`+[PFObject(self=, _cmd=, node=, dirtyChildren=, dirtyFiles=, seen=, seenNew=0x00007f8e5a521b00) collectDirtyChildren:children:files:seen:seenNew:] + 1422 at PFObject.m:433
    frame #16: 0x000000010aae0ab2 Breakaway`+[PFObject(self=, _cmd=, node=, dirtyChildren=, dirtyFiles=, seen=, seenNew=0x00007f8e5a521b00) collectDirtyChildren:children:files:seen:seenNew:] + 371 at PFObject.m:375
    frame #17: 0x000000010aae0fac Breakaway`__70+[PFObject(.block_descriptor=, key=, obj=, stop=) collectDirtyChildren:children:files:seen:seenNew:]_block_invoke + 51 at PFObject.m:384
    frame #18: 0x000000010c4db656 CoreFoundation`__65-[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:]_block_invoke + 102
    frame #19: 0x000000010c4db55c CoreFoundation`-[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:] + 204
    frame #20: 0x000000010aae0be7 Breakaway`+[PFObject(self=, _cmd=, node=, dirtyChildren=, dirtyFiles=, seen=, seenNew=0x00007f8e5a521b00) collectDirtyChildren:children:files:seen:seenNew:] + 680 at PFObject.m:383
    frame #21: 0x000000010aae0ebb Breakaway`+[PFObject(self=, _cmd=, node=, dirtyChildren=, dirtyFiles=, seen=, seenNew=0x00007f8e5a521b00) collectDirtyChildren:children:files:seen:seenNew:] + 1404 at PFObject.m:427
    frame #22: 0x000000010aae0fac Breakaway`__70+[PFObject(.block_descriptor=, key=, obj=, stop=) collectDirtyChildren:children:files:seen:seenNew:]_block_invoke + 51 at PFObject.m:384
    frame #23: 0x000000010c4db656 CoreFoundation`__65-[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:]_block_invoke + 102
    frame #24: 0x000000010c4db55c CoreFoundation`-[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:] + 204
    frame #25: 0x000000010aae0be7 Breakaway`+[PFObject(self=, _cmd=, node=, dirtyChildren=, dirtyFiles=, seen=, seenNew=0x00007f8e5a521b00) collectDirtyChildren:children:files:seen:seenNew:] + 680 at PFObject.m:383
    frame #26: 0x000000010aae0ebb Breakaway`+[PFObject(self=, _cmd=, node=, dirtyChildren=, dirtyFiles=, seen=, seenNew=0x00007f8e5a521b00) collectDirtyChildren:children:files:seen:seenNew:] + 1404 at PFObject.m:427
    frame #27: 0x000000010aae0fac Breakaway`__70+[PFObject(.block_descriptor=, key=, obj=, stop=) collectDirtyChildren:children:files:seen:seenNew:]_block_invoke + 51 at PFObject.m:384
    frame #28: 0x000000010c4db656 CoreFoundation`__65-[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:]_block_invoke + 102
    frame #29: 0x000000010c4db55c CoreFoundation`-[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:] + 204
    frame #30: 0x000000010aae0be7 Breakaway`+[PFObject(self=, _cmd=, node=, dirtyChildren=, dirtyFiles=, seen=, seenNew=0x00007f8e5a521b00) collectDirtyChildren:children:files:seen:seenNew:] + 680 at PFObject.m:383
    frame #31: 0x000000010aae0ebb Breakaway`+[PFObject(self=, _cmd=, node=, dirtyChildren=, dirtyFiles=, seen=, seenNew=0x00007f8e5a521b00) collectDirtyChildren:children:files:seen:seenNew:] + 1404 at PFObject.m:427
    frame #32: 0x000000010aae10e6 Breakaway`+[PFObject(self=, _cmd=, child=, dirtyChildren=, dirtyFiles=) collectDirtyChildren:children:files:] + 179 at PFObject.m:451
    frame #33: 0x000000010aae4324 Breakaway`__72+[PFObject(.block_descriptor=0x00007f8e5fa0ac20) _enqueueSaveEventuallyChildrenOfObject:currentUser:]_block_invoke + 142 at PFObject.m:781
    frame #34: 0x000000010a95de89 Breakaway`__55-[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke_2(.block_descriptor=0x000000011b9e7b48) + 86 at BFTask.m:334
    frame #35: 0x000000010a95f03c Breakaway`__29+[BFExecutor defaultExecutor]_block_invoke_2(.block_descriptor=, block=) + 331 at BFExecutor.m:45
    frame #36: 0x000000010a95f563 Breakaway`-[BFExecutor execute:](self=, _cmd=, block=) + 65 at BFExecutor.m:109
    frame #37: 0x000000010a95de09 Breakaway`__55-[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke(.block_descriptor=0x00007f8e5fa15b60) + 138 at BFTask.m:326
    frame #38: 0x000000010a95dc7a Breakaway`-[BFTask continueWithExecutor:block:cancellationToken:](self=, _cmd=, executor=, block=, cancellationToken=) + 311 at BFTask.m:377
    frame #39: 0x000000010a95db1d Breakaway`-[BFTask continueWithExecutor:withBlock:](self=, _cmd=, executor=, block=) + 53 at BFTask.m:316
    frame #40: 0x000000010a95d169 Breakaway`+[BFTask taskFromExecutor:withBlock:](self=, _cmd=, executor=, block=) + 100 at BFTask.m:173
    frame #41: 0x000000010aae4253 Breakaway`+[PFObject(self=, _cmd=, object=, currentUser=) _enqueueSaveEventuallyChildrenOfObject:currentUser:] + 183 at PFObject.m:778
    frame #42: 0x000000010aae7ded Breakaway`__56-[PFObject(.block_descriptor=0x00007f8e5a475130, task=) _enqueueSaveEventuallyWithChildren:]_block_invoke_2 + 242 at PFObject.m:1360
    frame #43: 0x000000010a95de89 Breakaway`__55-[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke_2(.block_descriptor=0x00007f8e5f92e610) + 86 at BFTask.m:334
    frame #44: 0x000000010f184186 libdispatch.dylib`_dispatch_call_block_and_release + 12
    frame #45: 0x000000010f1a3614 libdispatch.dylib`_dispatch_client_callout + 8
    frame #46: 0x000000010f18d552 libdispatch.dylib`_dispatch_root_queue_drain + 1768
    frame #47: 0x000000010f18eb17 libdispatch.dylib`_dispatch_worker_thread3 + 111
    frame #48: 0x000000010f510637 libsystem_pthread.dylib`_pthread_wqthread + 729
    frame #49: 0x000000010f50e40d libsystem_pthread.dylib`start_wqthread + 13
  thread #8: tid = 0xa07ae3, 0x000000010f4df166 libsystem_kernel.dylib`__psynch_mutexwait + 10, queue = 'com.apple.root.default-qos'
    frame #0: 0x000000010f4df166 libsystem_kernel.dylib`__psynch_mutexwait + 10
    frame #1: 0x000000010f50e78a libsystem_pthread.dylib`_pthread_mutex_lock + 480
    frame #2: 0x000000010aaed780 Breakaway`-[PFObject state](self=0x00007f8e5cd4ff00, _cmd=) + 32 at PFObject.m:2047
    frame #3: 0x000000010aaeda22 Breakaway`-[PFObject objectId](self=, _cmd=) + 24 at PFObject.m:2075
    frame #4: 0x000000010ab2db5f Breakaway`-[PFOfflineObjectEncoder encodeParseObject:](self=0x00007f8e5f909aa0, _cmd=, object=) + 65 at PFEncoder.m:210
    frame #5: 0x000000010ab2cdc4 Breakaway`-[PFEncoder encodeObject:](self=, _cmd=, object=) + 113 at PFEncoder.m:35
    frame #6: 0x000000010aae6f0d Breakaway`__71-[PFObject(.block_descriptor=0x000000011c094b40, key=, obj=, stop=) RESTDictionaryWithObjectEncoder:operationSetUUIDs:]_block_invoke + 60 at PFObject.m:1174
    frame #7: 0x000000010c4db656 CoreFoundation`__65-[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:]_block_invoke + 102
    frame #8: 0x000000010c4db55c CoreFoundation`-[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:] + 204
    frame #9: 0x000000010aae69e4 Breakaway`-[PFObject(self=0x00007f8e5cd490f0, _cmd=, objectEncoder=, operationSetUUIDs=0x000000011c094c38) RESTDictionaryWithObjectEncoder:operationSetUUIDs:] + 404 at PFObject.m:1173
    frame #10: 0x000000010aad1a48 Breakaway`__54-[PFOfflineStore saveObjectLocallyAsync:key:database:]_block_invoke255(.block_descriptor=0x00007f8e5f909150, task=) + 140 at PFOfflineStore.m:384
    frame #11: 0x000000010a95e58c Breakaway`__62-[BFTask continueWithExecutor:successBlock:cancellationToken:]_block_invoke(.block_descriptor=0x00007f8e5f909660, task=) + 83 at BFTask.m:408
    frame #12: 0x000000010a95de89 Breakaway`__55-[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke_2(.block_descriptor=0x000000011c094d68) + 86 at BFTask.m:334
    frame #13: 0x000000010a95f03c Breakaway`__29+[BFExecutor defaultExecutor]_block_invoke_2(.block_descriptor=, block=) + 331 at BFExecutor.m:45
    frame #14: 0x000000010a95f563 Breakaway`-[BFExecutor execute:](self=, _cmd=, block=) + 65 at BFExecutor.m:109
    frame #15: 0x000000010a95de09 Breakaway`__55-[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke(.block_descriptor=0x00007f8e5a48c610) + 138 at BFTask.m:326
    frame #16: 0x000000010a95dc7a Breakaway`-[BFTask continueWithExecutor:block:cancellationToken:](self=, _cmd=, executor=, block=, cancellationToken=) + 311 at BFTask.m:377
    frame #17: 0x000000010a95e4f8 Breakaway`-[BFTask continueWithExecutor:successBlock:cancellationToken:](self=0x00007f8e5f9094a0, _cmd=, executor=, block=, cancellationToken=) + 201 at BFTask.m:404
    frame #18: 0x000000010a95e63b Breakaway`-[BFTask continueWithSuccessBlock:](self=, _cmd=, block=) + 92 at BFTask.m:414
    frame #19: 0x000000010aad16bc Breakaway`-[PFOfflineStore saveObjectLocallyAsync:key:database:](self=, _cmd=, object=, key=, database=) + 656 at PFOfflineStore.m:374
    frame #20: 0x000000010aad12f0 Breakaway`__63-[PFOfflineStore saveObjectLocallyAsync:withChildren:database:]_block_invoke234(.block_descriptor=0x00007f8e5f9061d0, task=) + 292 at PFOfflineStore.m:357
    frame #21: 0x000000010a95e58c Breakaway`__62-[BFTask continueWithExecutor:successBlock:cancellationToken:]_block_invoke(.block_descriptor=0x00007f8e5f9061a0, task=) + 83 at BFTask.m:408
    frame #22: 0x000000010a95de89 Breakaway`__55-[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke_2(.block_descriptor=0x000000011c095308) + 86 at BFTask.m:334
    frame #23: 0x000000010a95f03c Breakaway`__29+[BFExecutor defaultExecutor]_block_invoke_2(.block_descriptor=, block=) + 331 at BFExecutor.m:45
    frame #24: 0x000000010a95f563 Breakaway`-[BFExecutor execute:](self=, _cmd=, block=) + 65 at BFExecutor.m:109
    frame #25: 0x000000010a95de09 Breakaway`__55-[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke(.block_descriptor=0x00007f8e5f905f10) + 138 at BFTask.m:326
    frame #26: 0x000000010a95dc7a Breakaway`-[BFTask continueWithExecutor:block:cancellationToken:](self=, _cmd=, executor=, block=, cancellationToken=) + 311 at BFTask.m:377
    frame #27: 0x000000010a95e4f8 Breakaway`-[BFTask continueWithExecutor:successBlock:cancellationToken:](self=0x00007f8e5f905a90, _cmd=, executor=, block=, cancellationToken=) + 201 at BFTask.m:404
    frame #28: 0x000000010a95e63b Breakaway`-[BFTask continueWithSuccessBlock:](self=, _cmd=, block=) + 92 at BFTask.m:414
    frame #29: 0x000000010aad0ebd Breakaway`-[PFOfflineStore saveObjectLocallyAsync:withChildren:database:](self=0x00007f8e5a57ab50, _cmd=, object=, children=, database=) + 1182 at PFOfflineStore.m:338
    frame #30: 0x000000010aad0958 Breakaway`-[PFOfflineStore saveObjectLocallyAsync:includeChildren:database:](self=0x00007f8e5a57ab50, _cmd=, object=, includeChildren=, database=) + 236 at PFOfflineStore.m:315
    frame #31: 0x000000010a95e58c Breakaway`__62-[BFTask continueWithExecutor:successBlock:cancellationToken:]_block_invoke(.block_descriptor=0x00007f8e5fb087b0, task=) + 83 at BFTask.m:408
    frame #32: 0x000000010a95de89 Breakaway`__55-[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke_2(.block_descriptor=0x000000011c095858) + 86 at BFTask.m:334
    frame #33: 0x000000010a95f03c Breakaway`__29+[BFExecutor defaultExecutor]_block_invoke_2(.block_descriptor=, block=) + 331 at BFExecutor.m:45
    frame #34: 0x000000010a95f563 Breakaway`-[BFExecutor execute:](self=, _cmd=, block=) + 65 at BFExecutor.m:109
    frame #35: 0x000000010a95de09 Breakaway`__55-[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke(.block_descriptor=0x00007f8e5fb2cc80) + 138 at BFTask.m:326
    frame #36: 0x000000010a95dc7a Breakaway`-[BFTask continueWithExecutor:block:cancellationToken:](self=, _cmd=, executor=, block=, cancellationToken=) + 311 at BFTask.m:377
    frame #37: 0x000000010a95e4f8 Breakaway`-[BFTask continueWithExecutor:successBlock:cancellationToken:](self=0x00007f8e5a67fbf0, _cmd=, executor=, block=, cancellationToken=) + 201 at BFTask.m:404
    frame #38: 0x000000010a95e63b Breakaway`-[BFTask continueWithSuccessBlock:](self=, _cmd=, block=) + 92 at BFTask.m:414
    frame #39: 0x000000010aad7bd0 Breakaway`__60-[PFOfflineStore _performDatabaseTransactionAsyncWithBlock:]_block_invoke(.block_descriptor=0x00007f8e5a487f60, database=) + 158 at PFOfflineStore.m:1001
    frame #40: 0x000000010a95de89 Breakaway`__55-[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke_2(.block_descriptor=0x000000011c095b88) + 86 at BFTask.m:334
    frame #41: 0x000000010a95f03c Breakaway`__29+[BFExecutor defaultExecutor]_block_invoke_2(.block_descriptor=, block=) + 331 at BFExecutor.m:45
    frame #42: 0x000000010a95f563 Breakaway`-[BFExecutor execute:](self=, _cmd=, block=) + 65 at BFExecutor.m:109
    frame #43: 0x000000010a95de09 Breakaway`__55-[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke(.block_descriptor=0x00007f8e5f9212f0) + 138 at BFTask.m:326
    frame #44: 0x000000010a95da1c Breakaway`-[BFTask runContinuations](self=0x00007f8e5f933dc0, _cmd=) + 396 at BFTask.m:306
    frame #45: 0x000000010a95d2d2 Breakaway`-[BFTask trySetResult:](self=, _cmd=, result=) + 151 at BFTask.m:198
    frame #46: 0x000000010a95d20d Breakaway`-[BFTask setResult:](self=, _cmd=, result=) + 17 at BFTask.m:185
    frame #47: 0x000000010a956c80 Breakaway`-[BFTaskCompletionSource setResult:](self=, _cmd=, result=) + 79 at BFTaskCompletionSource.m:52
    frame #48: 0x000000010a95e12b Breakaway`__55-[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke_3(.block_descriptor=, task=) + 285 at BFTask.m:350
    frame #49: 0x000000010a95df37 Breakaway`__55-[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke_2(.block_descriptor=) + 260 at BFTask.m:358
    frame #50: 0x000000010f184186 libdispatch.dylib`_dispatch_call_block_and_release + 12
    frame #51: 0x000000010f1a3614 libdispatch.dylib`_dispatch_client_callout + 8
    frame #52: 0x000000010f18d552 libdispatch.dylib`_dispatch_root_queue_drain + 1768
    frame #53: 0x000000010f18eb17 libdispatch.dylib`_dispatch_worker_thread3 + 111
    frame #54: 0x000000010f510637 libsystem_pthread.dylib`_pthread_wqthread + 729
    frame #55: 0x000000010f50e40d libsystem_pthread.dylib`start_wqthread + 13
  thread #9: tid = 0xa07ae7, 0x000000010f4da4de libsystem_kernel.dylib`mach_msg_trap + 10, name = 'com.apple.NSURLConnectionLoader'
    frame #0: 0x000000010f4da4de libsystem_kernel.dylib`mach_msg_trap + 10
    frame #1: 0x000000010f4d964f libsystem_kernel.dylib`mach_msg + 55
    frame #2: 0x000000010c4c5624 CoreFoundation`__CFRunLoopServiceMachPort + 212
    frame #3: 0x000000010c4c4ad7 CoreFoundation`__CFRunLoopRun + 1287
    frame #4: 0x000000010c4c4366 CoreFoundation`CFRunLoopRunSpecific + 470
    frame #5: 0x000000010b659e8d CFNetwork`+[NSURLConnection(Loader) _resourceLoadLoop:] + 434
    frame #6: 0x000000010c9d809d Foundation`__NSThread__main__ + 1194
    frame #7: 0x000000010f510268 libsystem_pthread.dylib`_pthread_body + 131
    frame #8: 0x000000010f5101e5 libsystem_pthread.dylib`_pthread_start + 176
    frame #9: 0x000000010f50e41d libsystem_pthread.dylib`thread_start + 13
  thread #12: tid = 0xa07af2, 0x000000010f4df94a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #0: 0x000000010f4df94a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010f5106c3 libsystem_pthread.dylib`_pthread_wqthread + 869
    frame #2: 0x000000010f50e40d libsystem_pthread.dylib`start_wqthread + 13
  thread #13: tid = 0xa07af3, 0x000000010f4df94a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #0: 0x000000010f4df94a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010f5106c3 libsystem_pthread.dylib`_pthread_wqthread + 869
    frame #2: 0x000000010f50e40d libsystem_pthread.dylib`start_wqthread + 13
  thread #16: tid = 0xa07afd, 0x000000010f4df3fa libsystem_kernel.dylib`__select + 10, name = 'com.apple.CFSocket.private'
    frame #0: 0x000000010f4df3fa libsystem_kernel.dylib`__select + 10
    frame #1: 0x000000010c50a9ba CoreFoundation`__CFSocketManager + 730
    frame #2: 0x000000010f510268 libsystem_pthread.dylib`_pthread_body + 131
    frame #3: 0x000000010f5101e5 libsystem_pthread.dylib`_pthread_start + 176
    frame #4: 0x000000010f50e41d libsystem_pthread.dylib`thread_start + 13
(lldb)

@richardjrossiii
Copy link
Contributor

Thank you for the stack trace. It definitely helps us track this down.

Our current line of thinking is that this deadlock is related to our mutable containers feature, which we're looking to remove in release 1.9.0.

To see if this is actually the problem, would you mind testing with our beta branch with this feature disabled? You can update your podfile as such:

pod 'Parse', :git => 'https://github.com/ParsePlatform/Parse-SDK-iOS-OSX.git', :branch => 'nlutsenko.containers'

If this doesn't fix it, and this deadlock is easily reproduced, would you be open to (privately) giving me a copy of your project?

We're really having a hard time figuring out exactly what causes this from just the stack traces, as this is asynchronous code which is super hard to debug. Concrete code examples would help greatly.

@rdbayer
Copy link

rdbayer commented Sep 22, 2015

Thanks, Richard. Yes, I have a project which reproduces it fairly consistently. What's the best way for me to comment privately in this format, or otherwise get it to you?

For testing the above, I'm unfamiliar with Podfiles, is there another easy way for me to download from this branch in pure git?

@richardjrossiii
Copy link
Contributor

If you have it in a private github org, you could temporarily add me as a readonly member to the organization. Otherwise, you could email it to me at [email protected].

To do this with 'pure git' its fairly simple, you should be able to git clone the repo, git checkout nlutsenko.containers branch, follow the build instructions in the README to generate the .framework files for you.

richardjrossiii added a commit that referenced this issue Sep 23, 2015
By no longer holding a lock while recursing, we allow other threads who may be waiting on the current object to progress before iterating to children of the object, solving some of the deadlocks that we've seen in issues #11, #61, and #299.

This does not necessarily fix the above issues, as we probably still have similar deadlocks elsewhere in the codebase.

cc @grantland
@rudywen
Copy link

rudywen commented Oct 14, 2015

I am still seeing this deadlock issue after upgrading to Parse Release 1.9.0. In my app, I can reproduce it by deleting, reinstalling the app, then signing into an existing account. The app begins to download some PFFiles for images and videos, then gets into this exact same deadlock. This is blocking our release, can someone from Parse provide an update on this issue?

richardjrossiii added a commit that referenced this issue Oct 16, 2015
We didn't actually need to hold the lock here, and if we did, another thread could have acquired these locks in another order, causing a deadlock.

Should help to fix #398, #11, and a few others.
richardjrossiii added a commit that referenced this issue Oct 16, 2015
We didn't actually need to hold the lock here, and if we did, another thread could have acquired these locks in another order, causing a deadlock.

Should help to fix #398, #11, and a few others.
@kevflynn
Copy link

Still seeing a lot of deadlocking as well - let me know if a trace posting will help

@dtaitz
Copy link

dtaitz commented Oct 21, 2015

I am seeing deadlock with PFUser when I try the below code for the "Push Notifications: Using Advanced Targeting" section from the Parse iOS Guide.

// Associate the device with a user
PFInstallation *installation = [PFInstallation currentInstallation];
installation[@"user"] = [PFUser currentUser];
[installation saveInBackground];

If another thread tries to access [PFUser currentUser] while this is occurring, I get deadlock. I was able to move this part of the code to make the issue minimal, but I thought I would point out when it happens.

@al-zonke
Copy link

I think @lkraider was right about cycle relations (ParentObject->ChildObject, ChildObject->ParentObject)
I have deadlock time to time, but before I added cycle relation, I had no problems.

@al-zonke
Copy link

As I understood, problems occurs when you load 2 linked objects in background simultaneously.
After loading they try to traverse through hierarchy and will block themselves.

I have relation Child<->Parent. And try to load several children in background simultaneously.
Here is my call stack (same for several threads)

#0  __psynch_mutexwait
#1  _pthread_mutex_lock_wait
#2  _pthread_mutex_lock_slow
#3  recursive_mutex_tt<false>::lock()
#4  objc_sync_enter
#5  -[PFObject allKeys]
#6  +[PFInternalUtils traverseObject:usingBlock:seenObjects:]
#7  +[PFInternalUtils traverseObject:usingBlock:seenObjects:]_block_invoke
#8  -[__NSArrayM enumerateObjectsWithOptions:usingBlock:]_block_invoke ()
#9  -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] ()
#10 +[PFInternalUtils traverseObject:usingBlock:seenObjects:]
#11 +[PFInternalUtils traverseObject:usingBlock:seenObjects:]
#12 +[PFInternalUtils traverseObject:usingBlock:seenObjects:]_block_invoke161
#13 -[__NSDictionaryI enumerateKeysAndObjectsWithOptions:usingBlock:]_block_invoke ()
#14 -[__NSDictionaryI enumerateKeysAndObjectsWithOptions:usingBlock:] ()
#15 +[PFInternalUtils traverseObject:usingBlock:seenObjects:]
#16 +[PFInternalUtils traverseObject:usingBlock:]
#17 -[PFObject(Private) _collectFetchedObjects]
#18 -[PFObjectController processFetchResultAsync:forObject:]_block_invoke
#19 +[BFTask taskFromExecutor:withBlock:]_block_invoke
#20 -[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke_2
#21 _dispatch_call_block_and_release
#22 _dispatch_root_queue_drain
#23 _dispatch_worker_thread3
#24 _pthread_wqthread
#25 start_wqthread

On #17 Child object (child1) locks himself and starts to traverse. On #5 it will rich other Child (child2) and try to lock it. If child2 makes same, we will have deadlock. And actually we have it :)

@lkraider
Copy link
Author

Hey, I think you should read this blog post, might give ideas ;D
http://blog.parse.com/learn/thread-safety-basics-on-iosos-x/

@richardjrossiii
Copy link
Contributor

@lkraider You know, I should really have a talk with that person sometime, he seems really brilliant! :)

@christianpbrink
Copy link

I'm seeing this too. Probably old news, but it isn't an issue on 1.9.1.

@nlutsenko
Copy link
Contributor

@christianpbrink Just to make sure, is it a problem on the latest one (1.11.0), but wasn't in 1.9.1? Or is ultimately fixed for you?

@christianpbrink
Copy link

It was not a problem on 1.9.1 but today I tried upgrading to 1.11.0 and did
a double-take when our app kept freezing soon after startup. I downgraded
to 1.10.0 and it's a problem there too.

I'm looking at a simple workaround where I thread all PFFile.dataAvailable
calls through a serial queue and cache the results in a thread-safe
object. Assuming this PFFile.dataAvailable thing is the only source of
deadlocks, I think the work won't be too bad.

On Tue, Dec 22, 2015 at 7:59 PM, Nikita Lutsenko [email protected]
wrote:

@christianpbrink https://github.com/christianpbrink Just to make sure,
is it a problem on the latest one (1.11.0), but wasn't in 1.9.1? Or is
ultimately fixed for you?


Reply to this email directly or view it on GitHub
#11 (comment)
.

@nlutsenko
Copy link
Contributor

Ok, could you open another issue for this if you can get us a repro case? I will look into it right away.

@christianpbrink
Copy link

I doubt I am going to design a case – time crunch leading up to Christmas.
Sorry.

On Tuesday, December 22, 2015, Nikita Lutsenko [email protected]
wrote:

Ok, could you open another issue for this if you can get us a repro case?
I will look into it right away.


Reply to this email directly or view it on GitHub
#11 (comment)
.

Sent from my iPhone

@Lyricalpanda
Copy link

This issue is present on 1.9.1, 1.11.0, and 1.12.0 for me as well.

@TomWFox
Copy link
Contributor

TomWFox commented Mar 8, 2019

It seems this issue has since been fixed, the 2018 referenced is a mistake, so I think we can close this - @parse-community/ios-osx

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