Thanks for the discussion guys. I failed to subscribe before posting -
hopefully this ends up in the right place.

Referencing S1 from a volatile field will guarantee that that the OSGi
context which writes/reads the reference will see the written reference,
even if distinct threads write and read the reference.

However, this does nothing if the @Reference field in my Component is not
volatile, as the the Synchronization Action defined by a volatile field
write/read only applies to that volatile field. So even if the correct S1
reference is written to the @Reference by the OSGi runtime, if the
Component @Reference is non-volatile, there is no guarantee that this S1
state will be visible when this @Reference is read by another thread.
What's worse, it could be that this initial reference is correct, but
additional references in S1 will not be visible from the @Reference. In
fact, any non-volatile, non-final references in S1 are not guaranteed to be
visible, even if the Service @Reference is non-null.

And as far as synchronized blocks are concerned, they only provide a
guarantee for the inter-thread memory visibility of references written/read
within the synchronized block of the SAME monitor (first bullet point in
17.4.4 of
http://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4. Or
the section under Visibility here: http://gee.cs.oswego.edu/dl/cpj/jmm.html).
So initializing S1 in a synchronized block will do nothing for these
references if the @Reference is not read when synchronized on the same
monitor.

Not to be pedantic, but
https://shipilev.net/blog/2016/close-encounters-of-jmm-kind/
has some good examples of the mind-blowing implications of the JMM.

The bottom line: I think STATIC @References need to be volatile.

Thanks

Dirk



Hi David

On Fri, Apr 28, 2017 at 5:19 PM, David Jencks <david.a.jen...@gmail.com> wrote:
> Step 5 happens before step 1.

You are right. SCR registers a ServiceFactory with the framework
before step 1 (at least for a delayed component). And on top of that,
I got the terminology pretty wrong.

Let me try again (the following assumes a delayed component):

1. the component becomes satisfied
2. DS (or rather SCR) registers a ServiceFactory with the framework's
service registry
3. the service is requested from the service registry by thread T1
3.1. DS creates a new instances of the implementation object S1 in thread T1
3.2. DS injects S1 with the (static) @Reference service in thread T1
3.3. DS calls activate() in thread T1
3.4. at this time no other thread has a reference to service S1
3.5. DS makes S1 accessible and returns it from the
ServiceFactory#getService() method
4. at this time other threads can get a fully initialized reference to
service S1

So regarding Java's memory model, I still assume that full activation
of the implementation object S1 before it leaves the scope of
ServiceFactory#getService() is the key. FWIW, the Felix implementation
keeps the reference to S1 in a volatile field that can only be
accessed once a volatile boolean is set to true.

Does this sound better?

Regards
Julian

>
> I’m not sure that java by itself has sufficient synchronization to assure
> that a requesting thread gets the fully correct memory set up by thread T1.
> However I Think that with the synchronization in Felix DS requesting threads
> will get correct information.
>
> thanks
> david jencks
>
>> On Apr 28, 2017, at 1:13 AM, Julian Sedding <jsedd...@gmail.com> wrote:
>>
>> My theory is as follows:
>>
>> 1. DS creates a new instances of the service S1 in thread T1
>> 2. DS injects the (static) @Reference service in thread T1
>> 3. DS calls activate() in thread T1
>> 4. at this time no other thread has a reference to service S1
>> 5. DS publishes the service in the OSGi service registry
>> 6. at this time other thread can get a fully initialized reference to
>> service S1
>>
>> I believe that because up to 4. the reference to S1 is "private" to
>> thread T1. In 5. S1 is "published" and thus first allowed to cross a
>> thread boundary (I assume Java internally creates some sort of copy of
>> S1's memory for a new thread T2). However, at that point S1 is fully
>> initialized and immutable. Should the static @Reference on S1 change,
>> it is deactivated and a new instance S1' is created, activated and
>> registered.
>>
>> In contrast, with a dynamic @Reference, the field's value may change
>> after it is published. Thus it needs to be volatile.
>>
>> As I said, this is a theory ;) I have no references to back me up.
>>
>> Regards
>> Julian
>>
>>
>> On Thu, Apr 27, 2017 at 7:06 PM, David Jencks <david.a.jen...@gmail.com>
>> wrote:
>>> My theory about why this is ok is as follows, perhaps you can see something
>>> wrong with it.
>>>
>>> Felix DS has some synchronization after activate is called, therefore the
>>> state of the static reference is definitely written to memory.  This
>>> reference field won’t change after that, since it’s (SCR) static.
>>> Any getService call on the service reference also has sufficient
>>> synchronization that it happens after the above write.  Therefore any other
>>> thread which obtained the referenced service will get an object with the
>>> correct field value.  Therefore any access to this possibly cached object
>>> by any thread will have the correct value.
>>>
>>> thanks
>>>
>>> david jencks
>>>
>>>> On Apr 27, 2017, at 9:33 AM, Dirk Hogan <dirk.ho...@forgerock.com> wrote:
>>>>
>>>> I have been puzzled about the visibility of references written/read across
>>>> threads in Felix.
>>>>
>>>> Scenario:
>>>>
>>>> public class myOSGiComponent {
>>>>
>>>> @Reference
>>>>
>>>> SomeOtherOSGiService myServiceReference;
>>>>
>>>> public void activate(ComponentContext cc) {
>>>>
>>>> // myServiceReference will be set - use it to initialize other
>>>> dependencies, etc
>>>>
>>>> }
>>>>
>>>> public void clientRequestViaEmbeddedJetty() {
>>>>
>>>> myServiceReference.foo();
>>>>
>>>> }
>>>>
>>>> The bottom line is that a STATIC reference does not have to be volatile. I
>>>> can see that the write to myServiceReference is guaranteed to be visible in
>>>> the activate method, provided that same Felix thread which set
>>>> myServiceReference invokes activate, and thus the visibility is guaranteed
>>>> by program order (17.4.3 of the Java Language Spec).
>>>>
>>>> However, in the absence of the synchronization action provided by e.g. a
>>>> volatile @Reference declaration, I do not see how Felix can provide a Java
>>>> Memory Model compliant guarantee that myServiceReference will be visible in
>>>> clientRequestViaEmbeddedJetty, as the thread which set the reference, and
>>>> the thread which invokes clientRequestViaEmbeddedJetty, will be distinct.
>>>> In the absence of a volatile @Reference declaration, there is no
>>>> synchronization action (17.4.2 of JLS) which would guarantee that the
>>>> reference write is visible to the reference read, as they are being
>>>> performed by distinct threads.
>>>>
>>>> Perhaps an explanation as to why a DYNAMIC @Reference does need to be
>>>> volatile would be helpful - e.g. why does component
>>>> de-activation/re-activation provide memory visibility guarantees for STATIC
>>>> references?
>>>>
>>>>
>>>> Thanks
>>>>
>>>>
>>>> Dirk
>>>

Reply via email to