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

8347392: Thread-unsafe implementation of c.s.j.scene.control.skin.Utils #1691

Conversation

andy-goryachev-oracle
Copy link
Contributor

@andy-goryachev-oracle andy-goryachev-oracle commented Jan 30, 2025

Thread-safe and re-entrant implementation of Utils.

The new code still uses the static instances of Text and TextLayout for performance reasons, but adds a thread-safe mechanism to keep track of whether any of the instances is in use and when that happens, supplies a new instance instead. This solves both thread safety and re-entrancy.

/reviewers 2


Progress

  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue
  • Change must be properly reviewed (2 reviews required, with at least 1 Reviewer, 1 Author)

Issue

  • JDK-8347392: Thread-unsafe implementation of c.s.j.scene.control.skin.Utils (Bug - P4)

Reviewers

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jfx.git pull/1691/head:pull/1691
$ git checkout pull/1691

Update a local copy of the PR:
$ git checkout pull/1691
$ git pull https://git.openjdk.org/jfx.git pull/1691/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 1691

View PR using the GUI difftool:
$ git pr show -t 1691

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jfx/pull/1691.diff

Using Webrev

Link to Webrev Comment

@bridgekeeper
Copy link

bridgekeeper bot commented Jan 30, 2025

👋 Welcome back angorya! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk
Copy link

openjdk bot commented Jan 30, 2025

@andy-goryachev-oracle 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:

8347392: Thread-unsafe implementation of c.s.j.scene.control.skin.Utils

Reviewed-by: kcr, mstrauss

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 no new commits pushed to the master branch. If another commit should be pushed before you perform the /integrate command, your PR will be automatically rebased. If you prefer to avoid any potential automatic rebasing, please check the documentation for the /integrate command for further details.

➡️ To integrate this PR with the above commit message to the master branch, type /integrate in a new comment.

@andy-goryachev-oracle andy-goryachev-oracle changed the title 8347392.thread.safe.utils 8347392: Thread-unsafe implementation of c.s.j.scene.control.skin.Utils Jan 30, 2025
@openjdk
Copy link

openjdk bot commented Feb 3, 2025

⚠️ @andy-goryachev-oracle This pull request contains merges that bring in commits not present in the target repository. Since this is not a "merge style" pull request, these changes will be squashed when this pull request in integrated. If this is your intention, then please ignore this message. If you want to preserve the commit structure, you must change the title of this pull request to Merge <project>:<branch> where <project> is the name of another project in the OpenJDK organization (for example Merge jdk:master).

@openjdk
Copy link

openjdk bot commented Feb 6, 2025

@andy-goryachev-oracle
The total number of required reviews for this PR (including the jcheck configuration and the last /reviewers command) is now set to 2 (with at least 1 Reviewer, 1 Author).

@andy-goryachev-oracle andy-goryachev-oracle marked this pull request as ready for review February 6, 2025 00:04
@openjdk openjdk bot added the rfr Ready for review label Feb 6, 2025
@mlbridge
Copy link

mlbridge bot commented Feb 6, 2025

Webrevs

@kevinrushforth kevinrushforth self-requested a review February 6, 2025 19:44
@andy-goryachev-oracle
Copy link
Contributor Author

@kevinrushforth I'd suggest to take a look at this first, as it blocks some other fixes. thanks!

Copy link
Member

@kevinrushforth kevinrushforth left a comment

Choose a reason for hiding this comment

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

The fix looks good. My testing is good as well. The now-enabled tests fail pretty reliably for me on Windows without your fix and all pass with your fix.

I left a few minor questions / comments, but will approve as is.

Comment on lines -332 to 330
@Disabled("JDK-8347392") // FIX
@Test
public void hyperlink() {
Copy link
Member

Choose a reason for hiding this comment

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

Minor: setVisited(nextBoolean())?

@Disabled("JDK-8347392") // FIX
@Test
public void checkBox() {
Copy link
Member

Choose a reason for hiding this comment

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

Minor: this test calls setSelected(true). Would introducing randomness via setSelected(nextBoolean()) be useful here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

here and elsewhere, you are right

Comment on lines -264 to 263
@Disabled("JDK-8347392") // FIX
@Test
public void choiceBox() {
Copy link
Member

Choose a reason for hiding this comment

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

Minor: select random item?

@mstr2
Copy link
Collaborator

mstr2 commented Feb 7, 2025

What's the rationale for using a borrow pattern here, instead of simply synchronizing access to the object in question? I don't think we use such a pattern anywhere else. Do you expect heavy contention?

@andy-goryachev-oracle
Copy link
Contributor Author

What's the rationale for using a borrow pattern here, instead of simply synchronizing access to the object in question?

A very good question!

This pattern seemed to be the most applicable here: the solution needs to be both thread-safe and reentrant, with the expectation that in most cases the simple scenario happens where the static instance is used.

We actually use that pattern using synchronization, see GlyphLayout::getInstance() for example. I think the use of AtomicBoolean is far better, so I took the same approach in #1667 .

Is there a specific scenario that would not work or cause issues?

@kevinrushforth
Copy link
Member

To add a little more to what Andy said, I think there are three main approaches that could have been used here:

  1. Remove the static fields and always allocate a new object each time it is needed.
  2. Keep the static fields for the common case where there is only one thread (typically the JavaFX application thread); check and allocate a new object if the static fields are already in use
  3. Replace the static fields with ThreadLocalStorage

There might be other solutions, but we don't want anything too complicated. Andy decided to go with 2.

@openjdk openjdk bot added the ready Ready to be integrated label Feb 7, 2025
@andy-goryachev-oracle
Copy link
Contributor Author

Hmmm, to further make a point: options 2 and 3 may not be re-entrant, so they probably won't work.

We haven't encounter this re-entrancy issue, but I suppose it might be possible to have a text component embedded in another text component (e.g. a TextArea embedded inside a RichTextArea for some reason). Even if the access happens within the FX application thread, the inner layout might clobber the outer one.

Thank you for a good discussion though!

@kevinrushforth
Copy link
Member

Hmmm, to further make a point: options 2 and 3 may not be re-entrant, so they probably won't work.

Your solution is basically what I meant by option 2. The way you did it, always using the return value of a method that will return a "safe" instance to use, is reentrant. You are right that a simple approach to option 3 would not be reentrant.

I like the solution you chose.

@andy-goryachev-oracle
Copy link
Contributor Author

Your solution is basically what I meant by option 2.

right. "only one thread" threw me off, sorry.

@andy-goryachev-oracle
Copy link
Contributor Author

/integrate

@openjdk
Copy link

openjdk bot commented Feb 7, 2025

Going to push as commit 2cf9779.
Since your change was applied there has been 1 commit pushed to the master branch:

  • 5cdbae2: 8333275: ComboBox: adding an item from editor changes editor text

Your commit was automatically rebased without conflicts.

@openjdk openjdk bot added the integrated Pull request has been integrated label Feb 7, 2025
@openjdk openjdk bot closed this Feb 7, 2025
@openjdk openjdk bot removed ready Ready to be integrated rfr Ready for review labels Feb 7, 2025
@openjdk
Copy link

openjdk bot commented Feb 7, 2025

@andy-goryachev-oracle Pushed as commit 2cf9779.

💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored.

@andy-goryachev-oracle andy-goryachev-oracle deleted the 8347392.thread.safe.utils branch February 7, 2025 18:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
integrated Pull request has been integrated
Development

Successfully merging this pull request may close these issues.

3 participants