p.s. If you really want to make this a spec discussion vs an implementation issue, you could bring it up on the osgi-...@mail.osgi.org mailing list.

On 5/2/17 18:55 , Dirk Hogan wrote:
Hi Richard-
I have a embedded jetty OSGi component that exposes the conglomeration of
OSGi services to the outside world. Felix would need to set these service
references in a thread-safe way. You appear to be suggesting that Felix can
be only consumed by the Felix threads themselves, as only that would not
bypass 'the hidden synchronization inside the framework' - whatever that is.

Let me try one more time: a while back, Felix mandated that DYNAMIC
@References be volatile. Presumably that decision was made by someone who
knows the JMM, and thus could provide a response to the question in my
initial post:

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?

I don't mean to be contentious, and there is nothing preventing me from
declaring my @References volatile. I just was hoping that there was
JMM-knowledge active in this forum which could provide an answer to my
original question. I may well have my answer.

Thanks

Dirk


On Tue, May 2, 2017 at 2:29 PM, Richard S. Hall <he...@ungoverned.org>
wrote:

Dirk,

Allow I'm not well versed on the details of JMM. I think this boils down
to typical OSGi component code will be going through the hidden barriers in
the the framework when they try to retrieve and access the service objects.
You appear to be concocting a situation where you have threads from outside
that you have given access to OSGi service components and bypassing the
hidden synchronization inside the framework. If you can create such a
scenario, then it is up to you to safely publish these objects when you
hand them off to this other thread. And the only way this is really
problematic is if your handoff is done in such a way that you bypass all
barriers to begin with.

-> richard



On 5/2/17 16:27 , Dirk Hogan wrote:

Hi Neil-
OK - now we are getting somewhere.

You need to dig a bit deeper to see what establishes a happens-before
relationship. For within a single thread, it is the Program Order: the
underlying virtual machine cannot allow the visibility of memory effects
which contradict the sequence of instructions defined in your .java file,
even though these commands will be re-ordered by the compiler, and
pipelined and executed concurrently by machine cores.

Between threads, it is the Synchronization Order, which is NOT Program
Order. Between threads, the memory effects of your .java file writes/reads
do NOT have to be honored. So if you say 'But Felix writes the reference
before publishing the service', and thus concluding that the reference
will
always be present in the service, you are correct, but ONLY from the
perspective of the thread which wrote the reference and published the
service. For ALL other threads, all bets are off, unless there is a
Synchronization Action (volatile reference read/write, monitor lock/unlock
on the same monitor) which dictates a Synchronization Order of the
visibility of memory effects between DISTINCT threads.

The definition of Synchronization Actions, how they combine to create a
Synchronization Order, and how this, in turn, allows a happens-before
relationship to be established, is a formal set of rules defined in the
JMM. There is no ambiguity here. A read of section 17.4 will illuminate as
much. It is very dense - that is why I turned to the other references I
provided in the links above. They are not a quick/easy read, but are
necessary to coherently reason about memory visibility across threads.

Thanks

Dirk

On Tue, May 2, 2017 at 1:10 PM, Neil Bartlett <njbartl...@gmail.com>
wrote:

I think I get what Dirk is saying, and although I disagree with some of
his analysis there is arguably a gap in the DS specification that makes
this unclear. I hope somebody can point at the vital sentence I have
missed, but here is my analysis:

The JLS defines happens-before thus: "Two actions can be ordered by a
happens-before relationship. If one action happens-before another, then
the
first is visible to and ordered before the second.” (
https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5
<
https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5

).

Define two actions, A1 and A2. A1 is the setting of an @Reference field
in
a component. A2 is reading the value of that field. It is Dirk’s
contention
that no provable happens-before relationship edge exists between A1 and
A2,
and therefore it’s possible for A2 to access the value of the @Reference
field that obtained before A1. Let’s see.

A1 is an action that is taken by SCR on an object that it creates (the
component instance). A2 can only occur in the following circumstances:

1. SCR itself reads the field.
SCR is in full control of its own code and I am assuming a correct SCR
implementation.

2. The activate method of the component uses the value of the field.
Section 112.3.8.1 of OSGi Compendium R6 states "there is a happens-before
relationship between setting the field and activating the component
instance”. Also section 112.3.6.1 states “The bind method is called
and/or
the field is set before the component instance is activated”, which is
less
clear about the happens-before but I think the intent is there, and it
also
clarifies that this applies to bind methods as well as injected fields.
Therefore action A1 happens-before A2 in this case.

Note that the spec does not tell the implementation HOW to achieve this
happens-before edge. As Dirk points out, if it is done with a
synchronized
block then it would have to be on the same monitor. For example, the
implementation can achieve this by synchronizing on the component
instance
itself when binding fields and calling the activate method.

3. The activate method starts a thread which uses the value of the field
(I think this maps to Dirk’s HTTP-serving example).
  From point 2 above, we know that A1 happens-before the activate method
is
invoked. JLS 17.4.5 states that “a call to start() on a thread
happens-before any actions in the started thread”. JLS also states that
happens-before is transitive, i.e. if X happens-before Y and Y
happens-before Z then X happens-before Z.

Therefore A1 happens-before A2 in this case.

4. Service method(s) on the component use the value of the field.
The analysis here diverges for immediate vs delayed components.

For immediate components, Compendium section 112.5.3 states: "If an
immediate component configuration is satisfied and specifies a service,
SCR
must register the component configuration as a service in the service
registry and then activate the component configuration”. This does NOT
state that the registration of the service must happen after the binding
of
the reference fields. So it seems an implementation is free to hand the
service object to a consumer before the static references are bound. This
surprised me.

For delayed components, Compendium section 112.5.4 states: "When the
service is requested … SCR must create and activate a [unique] component
configuration”. It does NOT explicitly state that the static references
must be bound before the service object is handed to the caller of
getService(). Again this surprised me.


In summary, it’s clear to me that the *intention* of the specification is
for static references to be bound before the service becomes accessible,
and that component writers should not have to declare those fields
volatile, but this intention is not adequately spelled out. The best
statement I could find is in section 112.3.6.1: "A component instance
never sees any of the dynamics of the static reference”, which is very
vague.

Again, I may well have missed something or made an error in my analysis.
I
look forward to be being corrected.


Neil


On 2 May 2017, at 19:56, David Jencks <david.a.jen...@gmail.com> wrote:
I don’t understand your example or I don’t understand how your example

relates to an osgi or ds problem.

I think you are proposing that the DS component is an http server and

starts threads etc.  If so, it’s that components responsibility to make
sure its’ internal operations are thread safe, and this has little to do
with osgi or ds.

If you are asking about osgi, for instance if the component exposes

HttpServlet and is registered with the whiteboard http service and
receives
calls from it, then the whiteboard had to call getService to get the DS
component instance. In this case I think that there are plenty of
synchronization barriers in the service registry and in e.g.
SingleComponentManager.getService to assure that the view a request
thread has of the component is the same as the view the activation thread
had.

I could be wrong about whether there are actually enough synchronization

barriers.  Have you looked at the code to see?

thanks
david jencks

On May 2, 2017, at 10:45 AM, Dirk Hogan <dirk.ho...@forgerock.com>
wrote:
Hi Raymond-
Assume Felix does it's thing: sets all @References, activates all
components, publishes all services. It has resolved all dependencies,

and
set references accordingly.
Thus, in the example above, myOSGiComponent has its @Reference to
SomeOtherOSGiService resolved - Felix has set this reference. At the
conclusion of the activate method, myOSGiComponent has exposed some
functionality via http, even successfully dereferenced myOSGiComponent,

and
now requests start to come it, serviced by the http-server's
thread-pool.
Part of servicing this request involves dereferencing (reading) the
@Reference myServiceReference, which, I agree has been set (written) by

a
Felix thread.
The point of the Java Memory Model is that memory state, including
references, read and written across threads, do not have to have
determinate state, unless there is a Synchronization Action which

ensures
that the state written by thread A is visible to any other thread - a
volatile reference provides such a Synchronization Action. So code in
myOSGiComponent activate method can successfully dereference the
SomeOtherOSGiService reference, because the same thread which set the
reference is calling activate. But this does NOT mean that another

thread,
reading the SAME reference, will see a properly initialized reference.
Again, this should be self-evident, and the various rules of the JMM

model
are defined in section 17.4 of the Java Language Specification. If it is
not clear, then an understanding if the JMM is required. This

understanding
can be gained by reading the JLS, reading the links above, the chapter
in *Concurrency
in Practice* on the JMM,  or http://gee.cs.oswego.edu/dl/cpj/jmm.html
provides a good intro.

The bottom line: memory state, including references, shared among

multiple
threads can have indeterminate state when written/read, unless explicit
steps, defined in the JMM, are taken to ensure this visibility and thus
coherent state. This is not an opinion.

Thanks

Dirk



On Tue, May 2, 2017 at 10:23 AM, Raymond Auge <
raymond.a...@liferay.com
wrote:

On Tue, May 2, 2017 at 1:18 PM, Raymond Auge <raymond.a...@liferay.com
wrote:


On Tue, May 2, 2017 at 1:14 PM, Raymond Auge <

raymond.a...@liferay.com>
wrote:
On Tue, May 2, 2017 at 11:46 AM, Dirk Hogan <
dirk.ho...@forgerock.com>
wrote:
But no similar guarantee applies when another thread hits the
component,

I believe the discussion boils down to why you believe the above is
possible?

If SCR has not yet made the component available to other threads

(which,
to my knowledge, it only does by registering it as a service to the
service
registry) how can _another_ thread access the component at all?
I don't even see a way for components within the same DS bundle to
interact with each other other than via the service registry because
@Reference only works through the registry.

Correction, components could interact with each other via the
ComponentContext.. but I guess we'd have to know if that's part of

your
use
case.

Actually, no, it's not even possible via the ComponentContext. It
only
allows access to Services.

- Ray

Please, can you explain in more detail what case might allow for the
above? Because I believe the assumption is that it's not currently
possible. Certainly there could be a bug and I'm certain everyone

would
want to see that fixed.
--
*Raymond Augé* <http://www.liferay.com/web/raymond.auge/profile>
(@rotty3000)
Senior Software Architect *Liferay, Inc.* <http://www.liferay.com>
(@Liferay)
Board Member & EEG Co-Chair, OSGi Alliance <http://osgi.org>
(@OSGiAlliance)


--
*Raymond Augé* <http://www.liferay.com/web/raymond.auge/profile>
(@rotty3000)
Senior Software Architect *Liferay, Inc.* <http://www.liferay.com>
(@Liferay)
Board Member & EEG Co-Chair, OSGi Alliance <http://osgi.org>
(@OSGiAlliance)


--
*Raymond Augé* <http://www.liferay.com/web/raymond.auge/profile>
(@rotty3000)
Senior Software Architect *Liferay, Inc.* <http://www.liferay.com>
(@Liferay)
Board Member & EEG Co-Chair, OSGi Alliance <http://osgi.org>
(@OSGiAlliance)



Reply via email to