In doing the recent changes I applied knowledge of how the ConnectorImpl 
and its defaultArguments are used to decide on what is necessary from a 
threading perspective. I also am only considering the "listening" 
concurrency issue, at this stage, and was not considering making all the 
jdi classes thread-safe. The defaultArguments is constructed at 
GenericListenerConnector constructor time, and not changed from there. The 
whole ConnectorImpl implementation is basically to wrapper a 
TransportService with a set of "default arguments" set at object 
construction. This design affects what is necessary from a threading 
perspective for the Connector instance:

 - ConnectorImpl::toString iterates over the values in defaultArguments, I 
assume this will require synchronization
=> Not necessary as defaultArguments does not change after construction

- ConnectorImpl.trueString and falseString are initialized lazily without 
synchronization. It might be okay but a comment to explain why. Ditto for 
the lazily initialization of the messages field in getString.
=> "messages" is an instance variable initialized at constructor time only
=> true/falseString are static, they probably should be a kin to the 
"messages", but since they are just "immutable" Strings I don't think it's 
an issue as-is

- All but the "value" field in the Connector.Argument implementations 
should be final. It might be that the value fields need to volatile (needs 
more study).
=> Again I didn't see the essential need for this given the 
defaultArguments are constructed and not modified, including the "value" 
field. From the perspective of callers obtaining a copy-of the 
defaultArguments to set their own values, I saw that then as being a 
"thread-safety" concern of that calling code. 

- GenericListeningConnector fields should be final. You can also 
initialize listenMap with new ConcurrentHashMap<>() .
=> Isn't this just optimization not relevant to the "bug" in question?

- GenericListeningConnector.accept needs further analysis, at least for 
the case where the debugger hasn't called startListening.
=> I did think through the accept() method logic, and the compatibility 
start/stopListening if needed looks fine to me


I must agree that retro-fitting thread safety when not design from the 
start is difficult. So I therefore question the testcase, the spec doesn't 
state it is thread-safe, so why have we written testcases assuming it? 
Given the JDWP/JDI spec does it lends itself for a user to naturally 
assume having multiple threads listening on the SocketListen Connector is 
a reasonable usecase? How would a debugger font-end UI handle it? I'm not 
experienced enough with JDI, but my natural thought is it could be 
reasonable to have a "front-end" listening on multiple TargetVM's and 
handling them in a multi-threaded manner....? 

Should we re-target this as a CSR request instead? and re-implement.

Cheers
Andrew

Andrew Leonard
Java Runtimes Development
IBM Hursley
IBM United Kingdom Ltd
internet email: andrew_m_leon...@uk.ibm.com 




From:   Alan Bateman <alan.bate...@oracle.com>
To:     Andrew Leonard <andrew_m_leon...@uk.ibm.com>
Cc:     serviceability-dev@openjdk.java.net
Date:   14/06/2019 09:27
Subject:        Re: RFR JDK-8225474: JDI connector accept fails "Address 
already in use" with concurrent listeners



On 13/06/2019 20:18, Andrew Leonard wrote:
Thanks Alex, good spot. 
I have done all the changes now with the latest updates, and have 
performed some stress tests on xLinux, Win64 and Mac64, all successful. 

Please can I get reviews and sponsor for webrev.04: 
http://cr.openjdk.java.net/~aleonard/8225474/webrev.04/ 
Retrofitting code that wasn't developed to be used by multiple concurrent 
threads to be thread safe takes time and will require a lot of review 
effort. I don't have time to spend on this now and I suspect this one will 
need a second reviewer to help with the confidence that you've got 
everything.

Things to check are:

- ConnectorImpl::toString iterates over the values in defaultArguments, I 
assume this will require synchronization

- ConnectorImpl.trueString and falseString are initialized lazily without 
synchronization. It might be okay but a comment to explain why. Ditto for 
the lazily initialization of the messages field in getString.

- All but the "value" field in the Connector.Argument implementations 
should be final. It might be that the value fields need to volatile (needs 
more study).

- GenericListeningConnector fields should be final. You can also 
initialize listenMap with new ConcurrentHashMap<>() .

- GenericListeningConnector.accept needs further analysis, at least for 
the case where the debugger hasn't called startListening.

There may be more issues, it just needs time to walk through the original 
implementation.

-Alan



Unless stated otherwise above:
IBM United Kingdom Limited - Registered in England and Wales with number 
741598. 
Registered office: PO Box 41, North Harbour, Portsmouth, Hampshire PO6 3AU

Reply via email to