-
Notifications
You must be signed in to change notification settings - Fork 6.1k
8266421: Deadlock in Sound System #4141
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
Conversation
|
👋 Welcome back serb! A progress list of the required criteria for merging this PR into |
|
/remove label 2d |
|
@mrserb Unknown command |
|
/label remove 2d |
|
@mrserb |
Webrevs
|
| if (this.started != started) { | ||
| this.started = started; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I doubt that this type of synchronization may help something - the fields are volatile and we use sendEvents flag after synchronization block, so I removed it as well. Any thoughts?
These fields are volatile, but the comparison and assignment is not atomic.
So I believe it is possible the case when we will have sendEvents == true in two threads, hence we will send a duplicate event.
So we probably might want to use AtomicBoolean if you want to get rid of synchronized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could make sense only if the "sendEvents" flag will be used under some kind of synchronization as well, otherwise, it is possible to get sendEvents=true twice, it was not changed after this fix:
synchronized (this) {
if (this.started != started) {
this.started = started;
sendEvents = true;
}
}
<<< here the other thread could set "started" to the opposite state and we post events twice.
if (sendEvents) {
.....
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The case with setting opposite state you are describing is a different one. We will post two different events like start and stop.
I am talking about calling setStarted() with same parameter from different threads.
For example we have two threads T1 and T2 calling setStarted(true).
Before the fix only one of thread will set sendEvents to true due to synchronized block.
After the fix following is possible:
// this.started == false, started == true
if (this.started != started) { //T1 passed this check
// <<<<< at this moment T2 checks the statement above
this.started = started; // T1 and T2 assigns same new value to this.started
sendEvents = true; // both threads sets sendEvents to true.
}
// sending two start events.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My example was about the thread-safety of the method, after synchronized block, the other thread may change the state, then post event, and then this thread will post event. So we will post the event twice in the wrong order. So this method as-is is not thread-safe, we should not call it in parallel. I'll post data for its usage here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- The changes in the AbstractDataLine.setActive() are fine, we do not post events there.
- The changes in the AbstractDataLine.setStarted() are used and syncronised:
used in AbstractDataLine:343- the setEOM() dead unused non-public method
used in AbstractDataLine:205 - syncronised on synchronized(mixer); Also dead code, the setStarted() is never executed, since the line is stopped already a few lines above in the implStop();
used in DirectAudioDevice:533 - synchronized on synchronized(lock) and synchronized(mixer)
used in DirectAudioDevice:560 - synchronized on synchronized(lock) and synchronized(mixer)
used in DirectAudioDevice:707 - synchronized on synchronized(lock)
used in DirectAudioDevice:932 - synchronized on synchronized(lock) - The changes in the AbstractLine.setOpen() are used and synchronised:
used in AbstractDataLine:118 - syncronised on synchronized(mixer);
used in AbstractDataLine:374 - syncronised on synchronized(mixer);
used in AbstractMixer:288 - syncronised on this;
used in AbstractMixer:377 - syncronised on this;
used in PortMixer:277 - syncronised on synchronized(mixer);
used in PortMixer:293 - syncronised on synchronized(mixer);
So every object uses its own high-level synchronization when it calls the methods in question.
| System.out.println("Thread " + thread + " Play " | ||
| + System.currentTimeMillis() % 100000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This println spams a lot.
It took a ~1 second less to complete the test when these lines are commented(~8s vs ~9s, I believe it will took more on slower machines).
So we probably could comment out these lines to reduce test execution time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test is updated.
|
@mrserb This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be: You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 230 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
|
/integrate |
|
@mrserb Since your change was applied there have been 270 commits pushed to the
Your commit was automatically rebased without conflicts. Pushed as commit f6f82c3. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
In the fix for JDK-8207150 I have updated the synchronization of some code paths under one "lock", before that code was synchronized only on some threads and missing on others. Old review:
http://mail.openjdk.java.net/pipermail/sound-dev/2018-August/000650.html
That fix introduced this order of locks: "lock"->"synchronized(this)", I have checked other places and did not found where we use the opposite order. Unfortunately, one such place exists in the private subclass DirectClip.
I have checked both usages of synchronized which caused deadlock:
I doubt that this type of synchronization may help something - the fields are volatile and we use sendEvents flag after synchronisation block, so I removed it as well. Any thoughts?
Progress
Issue
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.java.net/jdk pull/4141/head:pull/4141$ git checkout pull/4141Update a local copy of the PR:
$ git checkout pull/4141$ git pull https://git.openjdk.java.net/jdk pull/4141/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 4141View PR using the GUI difftool:
$ git pr show -t 4141Using diff file
Download this PR as a diff file:
https://git.openjdk.java.net/jdk/pull/4141.diff