On Mon, 13 May 2024 21:14:26 GMT, Stuart Marks <sma...@openjdk.org> wrote:
> Hm, I don't think we want to add any synchronized blocks within a shutdown > hook. If a thread is blocked reading from the console, it will hold readLock; > if the JVM is then shut down using a signal, it will run shutdown hooks, and > this hook will block awaiting readLock. This can deadlock the shutdown > completely. > > To ensure proper memory visibility, maybe consider making `restoreEcho` be > volatile. It turns out it's not that hard to imagine. Thanks for helping me imagine it, Stuart. I think that we should add the most straightforward test to demonstrate that the `restoreEcho` logic (or the lack of it) has an observable effect. If we fail to do that, it might mean that the `restoreEcho` logic is not needed and that the rest of this message is probably irrelevant. The test should be added not in a separate PR for [8332161] -- a bug which Naoto has just filed -- but in this PR, and then we should `/issue add 8332161`. Since we now have established that [concurrency] is possible, we should find an adequate concurrent solution. I can imagine that the proposed `volatile`-based solution may fall short in the following scenario. Thread 1 reaches the line marked by `*`. Let's assume that immediately before executing that line `restoreEcho` is `false` and echo is on: public char[] readPassword(String fmt, Object ... args) { char[] passwd = null; synchronized (writeLock) { synchronized(readLock) { installShutdownHook(); try { restoreEcho = echo(false); // * } catch (IOException x) { throw new IOError(x); } IOError ioe = null; try { if (!fmt.isEmpty()) pw.format(fmt, args); passwd = readline(true); } catch (IOException x) { ioe = new IOError(x); } finally { try { if (restoreEcho) // ** restoreEcho = echo(true); } catch (IOException x) { ... Thread 1 executes `echo(false)`, which returns `true`. `true` is not yet written into `restoreEcho`. Meanwhile, thread 2 (the hook thread) is about to execute the line marked by `***`: public void run() { try { if (restoreEcho) { // *** echo(true); } } catch (IOException x) { } } Thread 2 sees `restoreEcho` is `false` and skips `echo(true)`. If thread 1 then ceases to exist (remember, we're shutting down) before it reaches the line marked by `**`in the `finally` block, the console echo will remain off. [8332161]: https://bugs.openjdk.org/browse/JDK-8332161 [concurrency]: https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/lang/Runtime.html#shutdown ------------- PR Comment: https://git.openjdk.org/jdk/pull/19184#issuecomment-2109779741