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

Fix #640 #644

Merged
merged 4 commits into from
Nov 16, 2017
Merged

Fix #640 #644

merged 4 commits into from
Nov 16, 2017

Conversation

ricardopereira
Copy link
Contributor

@ricardopereira ricardopereira commented Nov 9, 2017

@ricardopereira ricardopereira self-assigned this Nov 9, 2017
@ricardopereira
Copy link
Contributor Author

d6353e1 test raises a EXC_BAD_INSTRUCTION in [ARTRealtimeChannel unsubscribe] because of a _dispatch_barrier_sync_f_slow :

screen shot 2017-11-09 at 19 27 31

@tcard
Copy link
Contributor

tcard commented Nov 9, 2017

@ricardopereira This is expected. You can't call unsubscribe from an internalEventEmitter, since a internalEventEmitter works exclusively within the internal queue, already holding the lock.

I'll comment on the issue what I think the problem is.

@ricardopereira
Copy link
Contributor Author

(3e1bd48) Another try to reproduce the issue but no success.

@tcard
Copy link
Contributor

tcard commented Nov 10, 2017

@ricardopereira No, that's for dispatching to the internal queue when the user is in the user (main) queue. This is the other way around, from the internal queue we need to dispatch to the user queue. And this needs to happen for internal event emitters too, at least those that potentially hold references to user objects.

@ricardopereira
Copy link
Contributor Author

This is the other way around, from the internal queue we need to dispatch to the user queue.

@tcard But we are already doing that by encapsulating each user callback with our implementation which dispatches the callback to the user queue:

    if (cb) {
        void (^userCallback)(ARTMessage *__art_nullable m) = cb;
        cb = ^(ARTMessage *__art_nullable m) {
            ART_EXITING_ABLY_CODE(_realtime.rest);
            dispatch_async(_userQueue, ^{
                userCallback(m);
            });
        };
    }

@tcard
Copy link
Contributor

tcard commented Nov 10, 2017

@ricardopereira Right, and that's perfect, but what I didn't anticipate is that there's another way of executing user code from our internal queue: by causing some of their object's reference counts to drop to zero, hence automatically calling their dealloc method. Which is exactly what happened at #640.

When off is called, we drop the reference to a callback, and that callback may be holding references to other objects, and those objects may have a dealloc method. Hence, dropping references to user callbacks must be executed in the user queue, not in our internal queue.

@@ -1355,7 +1355,7 @@ class RealtimeClient: QuickSpec {
}

// Possible issue of https://github.com/ably/ably-ios/issues/640
fit("should dispatch in user queue") {
xit("should dispatch in user queue") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be fixed.

@@ -1328,6 +1328,56 @@ class RealtimeClient: QuickSpec {
expect(result).to(equal(expectedOrder))
}

// Possible issue of https://github.com/ably/ably-ios/issues/640
xit("should unlock queue when the timer ends") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove this one, the other reproduces the issue more clearly from a user persoective without meddling with the internal emitter.

}

let foo = Foo()
foo.close()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, does this really reproduce the issue? I think if you call close here, then it will remove the listener you add at init but since you still have a reference to the created object its deinit won't be called, and when you drop the reference just after, since you already removed the listener, its deinit's unsubscribe will just do nothing.

I think deinit should just call unsubscribe directly; we don't need close.

Please confirm this reproduces the issue by commenting out the dispatch_async in removeListener and making sure this test then fails, and stops failing if you put it back.

Copy link
Contributor Author

@ricardopereira ricardopereira Nov 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, does this really reproduce the issue?

I think so but it always pass. I'll change the code with your points. Thanks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It always passes d0b8aeb

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we ask the client to test using the branch?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ricardopereira Yes, but we also need to have a test that actually reproduces the problem. Maybe instead of self we can reference a different object, then make sure we drop the other reference to it before dropping the reference to foo?

@ricardopereira
Copy link
Contributor Author

Success!

screen shot 2017-11-16 at 17 10 13

Copy link
Contributor

@tcard tcard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice :)

@ricardopereira ricardopereira changed the title WIP: Fix #640 Fix #640 Nov 16, 2017
@ricardopereira
Copy link
Contributor Author

Squashed.

@ricardopereira ricardopereira merged commit a7b67c6 into master Nov 16, 2017
@ricardopereira ricardopereira deleted the fix-640 branch November 16, 2017 17:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants