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

Mitigate race conditions in Signal interrupt handling. #123

Merged
merged 13 commits into from Nov 27, 2016
Merged

Conversation

andersio
Copy link
Member

@andersio andersio commented Nov 25, 2016

Superseded #112.

Mitigated race conditions

  1. Contention window after the lock on interrupted is released, and before sendLock is released. It is racing against the interrupted event handling routine, if the interrupted event is sent on a different thread from the current sender.

  2. The retrieval of observers is racing against the interrupt event sending (1, 2). It is possible to have events delivered after interrupted event is delivered.

Implementation Notes

Is there any performance regression in event delivery?

Sure. The measured regression is to that in #122. Note that the PR includes no optimisation. There are a few optimizations I can think of that can always be done later.

Why don't you replace sendLock and terminated with Atomic<Bool>?

The fun fact is that even under -Owholemodule, I still managed to measure a hefty overhead (~20%) in using closures-based, non-copying Atomic.modify. Maybe the Atomic optimization patch would help though.

@andersio andersio force-pushed the interrupt-fix branch 4 times, most recently from 3741919 to 84085aa Compare November 25, 2016 21:27
let (signal, observer) = Signal<Int, NoError>.pipe()

var hasSlept = false
var events = [Event<Int, NoError>]()
Copy link
Member

Choose a reason for hiding this comment

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

The format we normally use is separating type and value: var events: [Event<Int, NoError>] = [].

Copy link
Member Author

Choose a reason for hiding this comment

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

I guess we'd need a set of coding guidelines then. Just did a search and found quite a few of [U]() 🙈

Copy link
Member

Choose a reason for hiding this comment

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

Okay never mind then!

var hasSlept = false
var events = [Event<Int, NoError>]()

let sema = DispatchSemaphore(value: 0)
Copy link
Member

Choose a reason for hiding this comment

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

No need to shorten this name (especially when sema has other meanings), just call if semaphore?

group.wait()

expect(events.count) == 2
expect(events.count >= 2 ? events[1].isTerminating : false) == true
Copy link
Member

Choose a reason for hiding this comment

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

This failure would be impossible to read. Can you separate the 2 checks with an if? That way it's possible to see what was checked and what the expectation was.

var isInterrupted = false
signal.observeInterrupted { counter.modify { $0 += 1 } }

let sema = DispatchSemaphore(value: 0)
Copy link
Member

Choose a reason for hiding this comment

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

Ditto

if !shouldDispose && !terminated && !isTerminating, let state = interruptedState {
sendLock.lock()

if !terminated {
Copy link
Member

Choose a reason for hiding this comment

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

This is already checked in the condition.

Copy link
Member Author

@andersio andersio Nov 27, 2016

Choose a reason for hiding this comment

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

It could be a false negative - since it is read outside the sendLock, it might race against the next event sender which might flip terminated to true. So we have to check it again once we acquire the lock.

Copy link
Member

Choose a reason for hiding this comment

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

That could use a comment then to make sure a future reader doesn't accidentally removed it.

Copy link
Member Author

Choose a reason for hiding this comment

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

7a73f82

Added before merging. 🎉

@andersio andersio merged commit dd015c3 into master Nov 27, 2016
@andersio andersio deleted the interrupt-fix branch November 27, 2016 20:56
@andersio andersio mentioned this pull request Nov 28, 2016
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

Successfully merging this pull request may close these issues.

None yet

2 participants