Version 1.9 of ais/ai-00159.txt

Unformatted version of ais/ai-00159.txt version 1.9
Other versions for file ais/ai-00159.txt

!standard 09.10 (00)          00-05-30 AI95-00159/07
!standard E.04 (20)
!class binding interpretation 96-09-04
!status Corrigendum 2000 99-07-20
!status WG9 approved 98-06-12
!status ARG Approved 11-0-1 98-04-01
!status work item 96-09-08
!status received 96-09-04
!priority Medium
!difficulty Medium
!qualifier Clarification
!subject Shared variables in Shared_Passive?
!summary
For the purposes of the shared variables rules in 9.10, with respect to shared variables in shared passive partitions, a synchronous remote procedure call is considered to be part of the execution of the calling task.
For an asynchronous RPC, the call signals the start of the remote body, but the body then proceeds in parallel, and thus does not signal the next action of the calling task.
!question
There is no task rendezvous between two partitions, and protected entries are disallowed in Shared_Passive packages, so how can two actions of reading/updating variables declared in a Shared_Passive package performed on two different partitions be sequential as defined by 9.10(11)?
!recommendation
(See summary.)
!wording
(See summary.)
!discussion
9.10 says:
(2) Separate tasks normally proceed independently and concurrently with one another. However, task interactions can be used to synchronize the actions of two or more tasks to allow, for example, meaningful communication by the direct updating and reading of variables shared between the tasks. The actions of two different tasks are synchronized in this sense when an action of one task signals an action of the other task; an action A1 is defined to signal an action A2 under the following circumstances:
(3) If A1 and A2 are part of the execution of the same task, and the
language rules require A1 to be performed before A2;
...
(7) If A1 is the action of issuing an entry call, and A2 is part of
the corresponding execution of the appropriate entry_body or accept_statement.
(8) If A1 is part of the execution of an accept_statement or
entry_body, and A2 is the action of returning from the corresponding entry call;
(9) If A1 is part of the execution of a protected procedure body or
entry_body for a given protected object, and A2 is part of a later execution of an entry_body for the same protected object;
(10)If A1 signals some action that in turn signals A2.
Erroneous Execution
(11) Given an action of assigning to an object, and an action of reading or updating a part of the same object (or of a neighboring object if the two are not independently addressable), then the execution of the actions is erroneous unless the actions are sequential. Two actions are sequential if one of the following is true:
(12) One action signals the other;
(13) Both actions occur as part of the execution of the same task;
(14) Both actions occur as part of protected actions on the same
protected object, and at most one of the actions is part of a call on a protected function of the protected object.
A remote procedure call is a procedure call, so 9.10(3) implies that RPC's are signaling, so long as we view the call as taking place within the execution of a single task.
The only problem is that asynchronous RPC's are weird; the caller proceeds without awaiting return of the call. Thus, we need a special-case rule for that case.
As an example, suppose a task in one partition writes upon a shared variable in a shared passive partition. It may then do an RPC to notify other partitions that it has done writing. The other partitions may then safely read from that shared variable.
As a special case, consider a partition that initializes such a shared variable during that partition's elaboration. E.4(14) says:
If a remote subprogram call is received by a called partition before the partition has completed its elaboration, the call is kept pending until the called partition completes its elaboration (unless the call is cancelled by the calling partition prior to that).
So other partitions may assume that the shared variable has been initialized, so long as they first do an RPC (that does not raise Communication_Error) to the initializing partition.
!corrigendum E.04(20)
Insert after the paragraph:
The implementation of remote subprogram calls shall conform to the PCS interface as defined by the specification of the language-defined package System.RPC (see E.5). The calling stub shall use the Do_RPC procedure unless the remote procedure call is asynchronous in which case Do_APC shall be used. On the receiving side, the corresponding receiving stub shall be invoked by the RPC-receiver.
the new paragraph:
With respect to shared variables in shared passive library units, the execution of the corresponding subprogram body of a synchronous remote procedure call is considered to be part of the execution of the calling task. The execution of the corresponding subprogram body of an asynchronous remote procedure call proceeds in parallel with the calling task and does not signal the next action of the calling task (see 9.10).
!ACATS test
It is unknown (by the editor) if a C-Test can be created to check this rule.
!appendix

!section 9.10(00)
!subject Shared Variables in Shared_Passive?
!reference RM95-9.10, RM95-E.2.1
!from Laurent Guerby 96-08-23
!keywords synchronization
!reference 96-5647.a Laurent Guerby  96-8-23>>
!discussion

   There is no task rendez-vous between two partitions, and protected
entries are disallowed in Shared_Passive packages, so how can two
actions of reading/updating variables declared in a Shared_Passive
package performed on two different partitions can be sequencial as
defined by RM95-9.10(11)?

   May be all PCS actions should be considered as signaling.

--
Laurent Guerby <guerby@gnat.com>, Team Ada.
   "Use the Source, Luke. The Source will be with you, always (GPL)."

****************************************************************

!section 9.10(00)
!subject Shared Variables in Shared_Passive?
!reference RM95-9.10, RM95-E.2.1
!keywords synchronization
!reference as: 96-5647.a Laurent Guerby  96-8-23
!from Anthony Gargaro 96-8-24
!reference 96-5649.a Anthony Gargaro  96-8-24>>
!discussion

>   There is no task rendez-vous between two partitions, and protected
>entries are disallowed in Shared_Passive packages, so how can two
>actions of reading/updating variables declared in a Shared_Passive
>package performed on two different partitions can be sequencial as
>defined by RM95-9.10(11)?

It would seem that two actions on a variable declared in a shared
passive package must be sequential if the variable is included in an
entry-less protected object.

****************************************************************

!section 9.10(00)
!subject Shared Variables in Shared_Passive?
!reference RM95-9.10, RM95-E.2.1
!reference 96-5647.a Laurent Guerby  96-8-23
!reference 96-5649.a Anthony Gargaro  96-8-24
!keywords synchronization
!from Robert Dewar 96-8-25
!reference 96-5650.a Robert Dewar 96-8-25>>
!discussion

Laurent said

 >   There is no task rendez-vous between two partitions, and protected
 >entries are disallowed in Shared_Passive packages, so how can two
 >actions of reading/updating variables declared in a Shared_Passive
 >package performed on two different partitions can be sequencial as
 >defined by RM95-9.10(11)?

Anthony replied

 It would seem that two actions on a variable declared in a shared
 passive package must be sequential if the variable is included in an
 entry-less protected object.

Robert notes

 Sure of course if the object is in an entry-less protected object, then
 it is not a shared variable in the sense of the rules which Laurent is
 asking about. So far, Anthony seems to be agreeing with Laurent that
 shared variables in the sense of the rules in RM95-9.10(11) are not
 permitted in shared passive packages. Is this the intention? It seems
 a big limitation to me.

****************************************************************

!section 9.10(00)
!subject Shared Variables in Shared_Passive?
!reference RM95-9.10, RM95-E.2.1
!reference 96-5647.a Laurent Guerby  96-8-23
!reference 96-5649.a Anthony Gargaro  96-8-24
!keywords synchronization
!reference 96-5650.a Robert Dewar 96-8-25
!from Bob Duff
!reference 96-5656.a Robert A Duff 96-8-27>>
!discussion

> Laurent said
>
>  >   There is no task rendez-vous between two partitions, and protected
>  >entries are disallowed in Shared_Passive packages, so how can two
>  >actions of reading/updating variables declared in a Shared_Passive
>  >package performed on two different partitions can be sequencial as
>  >defined by RM95-9.10(11)?
>
> Anthony replied
>
>  It would seem that two actions on a variable declared in a shared
>  passive package must be sequential if the variable is included in an
>  entry-less protected object.
>
> Robert notes
>
>  Sure of course if the object is in an entry-less protected object, then
>  it is not a shared variable in the sense of the rules which Laurent is
>  asking about. So far, Anthony seems to be agreeing with Laurent that
>  shared variables in the sense of the rules in RM95-9.10(11) are not
>  permitted in shared passive packages. Is this the intention? It seems
>  a big limitation to me.

And Bob says:

I'm not sure what we're arguing about.  9.10(11) does not use the term
"shared variable".  As Anthony pointed out, the wording implies that
you need to wrap lots of things in entry-less protected objects.
Alternatively, you can use pragma Atomic.  Why is this a problem?  If
you were programming such a system in assembly, you would use
spin-locks and cache-flushes to make sure things work right.  And
protected procedures seem to map pretty well onto that way of doing
things.

Are Laurent and Robert saying (essentially) that every variable in a
shared-passive package should have an implicit pragma Atomic on it?
Including giant arrays (where an explicit pragma Atomic would be
illegal)?  Hmm.  It seems to me that Ada is a low-enough-level language
that one would expect to do something explicit in the cases we're
talking about.

- Bob

****************************************************************

!section 9.10(00)
!subject Shared Variables in Shared_Passive?
!reference RM95-9.10, RM95-E.2.1
!reference 96-5647.a Laurent Guerby  96-8-23
!reference 96-5649.a Anthony Gargaro  96-8-24
!reference 96-5656.a Robert A Duff 96-8-27
!keywords synchronization
!reference 96-5650.a Robert Dewar 96-8-25
!from Robert Dewar
!reference 96-5658.a Robert Dewar 96-8-28>>
!discussion

Bob says:

I'm not sure what we're arguing about.  9.10(11) does not use the term
"shared variable".  As Anthony pointed out, the wording implies that
you need to wrap lots of things in entry-less protected objects.
Alternatively, you can use pragma Atomic.  Why is this a problem?  If
you were programming such a system in assembly, you would use
spin-locks and cache-flushes to make sure things work right.  And
protected procedures seem to map pretty well onto that way of doing
things.

Are Laurent and Robert saying (essentially) that every variable in a
shared-passive package should have an implicit pragma Atomic on it?
Including giant arrays (where an explicit pragma Atomic would be
illegal)?  Hmm.  It seems to me that Ada is a low-enough-level language
that one would expect to do something explicit in the cases we're
talking about.

Robert replies

"9.10(11) does not use the term 'shared variable'"

Um, in my RM, 9.10(11) appears in section 9.10, whose title
is, guess what "Shared Variables", so of course 9.10(11) is
talking about shared variables!

Perhaps I can make myself clearer, here goes with an example:

Suppose in an ordinary Ada program, you have a global variable called junk
that is read by many tasks throughout the program, but the only time it
is assigned is during program startup. Providing that the program startup
is properly synchronized in the sense of 9.10.11 with all tasks that read
junk, then all is fine.

Now, put junk in a shared passive partition, note that the idea is that junk
is big, and is NOT atomic, and is NOT even volatile.

What you want to do is to have one partition setup the values in junk, and
then send messages to other partitions saying, OK: now you can read this
data.

Well according to my understanding of the RM, this program is erroneous
and there is no way to stop it being erroneous.

No spin locks or atomic access or anything like that is required, and
requiring junk to be put into a protected object is unnecessary overhead,
even if your compiler manages to handle special cases of protected objects
efficiently (which is in itself VERY trick to do right).

THAT's the problem that we are talking about!

****************************************************************

!section 9.10(00)
!subject Shared Variables in Shared_Passive?
!reference RM95-9.10, RM95-E.2.1
!reference 96-5647.a Laurent Guerby  96-8-23
!reference 96-5649.a Anthony Gargaro  96-8-24
!reference 96-5656.a Robert A Duff 96-8-27
!keywords synchronization
!reference 96-5650.a Robert Dewar 96-8-25
!reference 96-5658.a Robert Dewar 96-8-28
!from Bob Duff
!reference 96-5662.a Robert A Duff 96-8-29>>
!discussion

> THAT's the problem that we are talking about!

OK, I think I understand the problem.  Do you have a suggested solution?

Actually, I'm not so sure it's really a problem.  Is it not the
responsibility of System.RPC.Do_RPC (which is written by the user) to do
whatever is necessary to flush the cache or whatever?  That is, it might
do an entry call in order to block the RPC (as required by the RM), and
that will have the desired effect.  In other words, a remote procedure
call doesn't really have any semantics -- it's just a macro that expands
into a certain set of calls to 'Read/'Write and user-defined stuff in
the PCS, and if the user-defined stuff does the wrong thing, it will be
wrong.

If this really *is* a problem, then it seems to me that the solution is to
treat an RPC like an entry call, as far as the definition of "signal" in
9.10 is concerned.  Is there not a potentiall efficiency hit for this,
though?  That is, the implementation might flush the cache twice -- once
because it's doing an RPC, and then again because the user's Do_RPC does
an entry call to implement the necessary blocking.  But the
implementation can't eliminate the first cache flush, because it can
never be sure what's inside Do_RPC.

I thought you and Laurent were suggesting that every variable in a
shared passive package act like an atomic variable, or something like
that, which seems like overkill to me.  Whatever overhead is necessary
should be attached to the operation of "tell the other partition that
I've written the shared variable" -- the overhead should not be attached
to the act of reading or writing the shared variable.

- Bob

****************************************************************

!section 9.10(00)
!subject Shared Variables in Shared_Passive?
!reference RM95-9.10, RM95-E.2.1
!reference 96-5647.a Laurent Guerby  96-8-23
!reference 96-5649.a Anthony Gargaro  96-8-24
!reference 96-5656.a Robert A Duff 96-8-27
!keywords synchronization
!reference 96-5650.a Robert Dewar 96-8-25
!reference 96-5658.a Robert Dewar 96-8-28
!reference 96-5662.a Robert A Duff 96-8-29
!from Robert Dewar
!reference 96-5666.a Robert Dewar 96-8-30>>
!discussion

Bob said:

  Actually, I'm not so sure it's really a problem.  Is it not the
  responsibility of System.RPC.Do_RPC (which is written by the user) to do
  whatever is necessary to flush the cache or whatever?  That is, it might
  do an entry call in order to block the RPC (as required by the RM), and
  that will have the desired effect.  In other words, a remote procedure
  call doesn't really have any semantics -- it's just a macro that expands
  into a certain set of calls to 'Read/'Write and user-defined stuff in
  the PCS, and if the user-defined stuff does the wrong thing, it will be
  wrong.

Sure you are describing how an implementation would in practice be able
to get this to work without problems, but that's not the subject of this
discussion. The subject of this discussion is whether a program that uses
shared variables in a shared passive partition is erroneous or not, and
it appears that with the current definition of the language, such a program
will in general be erroneous, since you cannot count on the Do_RPC (which is
NOT written by the user in real life!) having the right semantics.

Note incidentally that your suggestion that all such variables be wrapped in
protected types is completely bogus, since it would mean that share passive
partitions provide no additional functionality not available by other means!
The whole idea of shared passive partitions is to provide shared data which
does NOT have a procedural interface!

  If this really *is* a problem, then it seems to me that the solution is to
  treat an RPC like an entry call, as far as the definition of "signal" in
  9.10 is concerned.  Is there not a potentiall efficiency hit for this,
  though?  That is, the implementation might flush the cache twice -- once
  because it's doing an RPC, and then again because the user's Do_RPC does
  an entry call to implement the necessary blocking.  But the
  implementation can't eliminate the first cache flush, because it can
  never be sure what's inside Do_RPC.

I indeed think that this is the only solution (to say that the RPC operation
is a syncrhonizing operation). I think the cache flushing worry is one you
don't need to worry about. You are thinking about tightly coupled machines
with non-coherent caches, which are not in any case a typical configuration.
The more normal cases are either using shared memory in a normal unix
environment on a single processor, where the Unix shared memory facility
is used, and you do not have to worry about caches even in a multiprocessor,
or alternatively a true distributed system (say using an ethernet), where
the issue of cache flushing is handled at an entirely different level).

Bob, you have always had the image that the main issue with share variable
synchronization is cache flushing, but it isn't most of the time, and it
certainly is not in this case. The issue is holding copies in registers,
and typically you will be making these shared variables volatile in any
case, so even that will not arise.

  I thought you and Laurent were suggesting that every variable in a
  shared passive package act like an atomic variable, or something like
  that, which seems like overkill to me.  Whatever overhead is necessary
  should be attached to the operation of "tell the other partition that
  I've written the shared variable" -- the overhead should not be attached
  to the act of reading or writing the shared variable.

There is really not an overhead issue here. It is almost impossible to imagine
an implementation in which things will not work correctly, and indeed if the
ARG does nothing in this area, people will still use passive partitions,
their programs will all be erroneous, but they will work anyway!

****************************************************************

!section 9.10(00)
!subject Shared Variables in Shared_Passive?
!reference RM95-9.10, RM95-E.2.1
!reference 96-5647.a Laurent Guerby  96-8-23
!reference 96-5649.a Anthony Gargaro  96-8-24
!reference 96-5656.a Robert A Duff 96-8-27
!keywords synchronization
!reference 96-5650.a Robert Dewar 96-8-25
!reference 96-5658.a Robert Dewar 96-8-28
!reference 96-5662.a Robert A Duff 96-8-29
!reference 96-5666.a Robert Dewar 96-8-30
!from Anthony Gargaro 96-9-01
!reference 96-5673.a Anthony Gargaro  96-9-1>>
!discussion

Robert notes:

>The subject of this discussion is whether a program that uses
>shared variables in a shared passive partition is erroneous or not, and
>it appears that with the current definition of the language, such a program
>will in general be erroneous, since you cannot count on the Do_RPC (which is
>NOT written by the user in real life!) having the right semantics.

This is correct; a partitioned program cannot rely on remote calls to
synchronize access to a variable declared in a shared passive package.
Annex E requires that shared passive packages be supported in
the absence of remote calls (E.2.3(20)).

>Note incidentally that your suggestion that all such variables be wrapped in
>protected types is completely bogus, since it would mean that share passive
>partitions provide no additional functionality not available by other means!
>The whole idea of shared passive partitions is to provide shared data which
>does NOT have a procedural interface!

A shared passive package allows a variable to be accessed from
different partitions with same assurance as that provided for a
nonpartitioned program. This is the additional functionality provided
by Annex E. There is no requirement in Annex E to provide additional
assurance. Consequently, it is my understanding that if access to a
shared variable is erroneous for a nonpartitioned program, it will be
erroneous if the variable is declared in a shared passive package for
a partitioned program. It should be recalled that an important goal of
Annex E is that a partitioned program must execute with the same
semantics as its nonpartitioned counterpart.

****************************************************************

!section 9.10(00)
!subject Shared Variables in Shared_Passive?
!reference RM95-9.10, RM95-E.2.1
!reference 96-5647.a Laurent Guerby  96-8-23
!reference 96-5649.a Anthony Gargaro  96-8-24
!reference 96-5656.a Robert A Duff 96-8-27
!keywords synchronization
!reference 96-5650.a Robert Dewar 96-8-25
!reference 96-5658.a Robert Dewar 96-8-28
!reference 96-5662.a Robert A Duff 96-8-29
!reference 96-5666.a Robert Dewar 96-8-30
!reference 96-5673.a Anthony Gargaro  96-9-1
!from Robert Dewar 96-09-02
!reference 96-5674.a Robert Dewar 96-9-2>>
!discussion

Anthony says

  A shared passive package allows a variable to be accessed from
  different partitions with same assurance as that provided for a
  nonpartitioned program. This is the additional functionality provided
  by Annex E. There is no requirement in Annex E to provide additional
  assurance. Consequently, it is my understanding that if access to a
  shared variable is erroneous for a nonpartitioned program, it will be
  erroneous if the variable is declared in a shared passive package for
  a partitioned program. It should be recalled that an important goal of
  Annex E is that a partitioned program must execute with the same
  semantics as its nonpartitioned counterpart.

Robert replies

  Well I suppose that we could rejoice as implementors to discover that we
  do not need to implement shared memory (the implementation of shared
  passive partitions is trivial if you take the attitude that shared
  variables in the 9.10 sense are erroneous -- if the only shared variables
  allowed are those inside protected types, then shared passive partitions
  provide no additional capability over RCI partitions).

  However, I suspect, from many conversations that people expect shared
  passive partitions to provide shared memory, and indeed in fact in GNAT,
  we are committed to providing this facility.

  The two choices are:

    The language takes the position that all programs using such shared
    memory are erroneous, but GNAT documents that this works, and programs
    use it and in fact work fine.

    The ARG fixes this obvious gap. This has no effect on GNAT users, except
    that their programs are now non-erroneous, but leaves the language in a
    more coherent state.

  Anthony, I am really puzzled, are you saying that you do NOT think of shared
  passive partitions as providing shared memory capability.

  YOu say "if access to a shared variable is erroneous for a nonpartitioned
  program, it will be erroneous for a paritioned progrm". Well yes, but in
  the nonpartitioned case, you can synchronize with an entry call. From a
  users point of view, an RPC is a similar synchronization.

  If you aim to get the same expressive power for shared passive partitions
  as for non-partioned programs, then you must do something, because in the
  non-partitioned case, you can syncrhnoize to make the access to the shared
  data valid, but there is simply no way to do this in the partitioned case.

  Let me again note my simple example.

  You wish to have a shared passive partition with a bunch of data in it.
  This data is for almost all the execution of the program read only, but
  in the start up phase of the program, this data is computed on the basis
  of supplied data.

  This seems a reasonable paradigm!

  There is no way to do this in a non-erroneous manner in Ada 95!

  Are you really happy with this conclusion?

****************************************************************

!section 9.10(00)
!subject Shared Variables in Shared_Passive?
!reference RM95-9.10, RM95-E.2.1
!reference 96-5647.a Laurent Guerby  96-8-23
!reference 96-5649.a Anthony Gargaro  96-8-24
!reference 96-5656.a Robert A Duff 96-8-27
!reference 96-5650.a Robert Dewar 96-8-25
!reference 96-5658.a Robert Dewar 96-8-28
!reference 96-5662.a Robert A Duff 96-8-29
!reference 96-5666.a Robert Dewar 96-8-30
!reference 96-5673.a Anthony Gargaro  96-9-1
!from Ted Baker 96-9-02
!keywords synchronization
!reference 96-5676.a Ted Baker  96-9-2>>
!discussion

When these features first were proposed, I had thought it would be
OK on map the concept of partition onto the concept of UNIX
process (say in a SMP machine) and the concept of a shared passive
partition onto a UNIX shared-memory object.

The unfortunate part of this is that the primitives most
appropriate for synchronizing data acccess between threads/tasks
(mutexes) are not the most appropriate for synchronization between
processes (semaphores), and some systems may not even support
primitives that work for interchangeably for both
(i.e. thread-level semaphores or process-shared mutexes).

Thus, if protected objects are required to be allowed in shared
passive partitions, an implementation will at least have to
special-case the implementation, and at worst may be prevented
from supporting this model.

--Ted Baker

****************************************************************

!section 9.10(00)
!subject Shared Variables in Shared_Passive?
!reference RM95-9.10, RM95-E.2.1
!reference 96-5647.a Laurent Guerby  96-8-23
!reference 96-5649.a Anthony Gargaro  96-8-24
!reference 96-5656.a Robert A Duff 96-8-27
!keywords synchronization
!reference 96-5650.a Robert Dewar 96-8-25
!reference 96-5658.a Robert Dewar 96-8-28
!reference 96-5662.a Robert A Duff 96-8-29
!reference 96-5666.a Robert Dewar 96-8-30
!reference 96-5673.a Anthony Gargaro  96-9-1
!reference as: 96-5674.a Robert Dewar 96-9-2
!from Anthony Gargaro 96-9-03
!reference 96-5679.a Anthony Gargaro  96-9-3>>
!discussion

>Robert replies

>  Well I suppose that we could rejoice as implementors to discover that we
>  do not need to implement shared memory (the implementation of shared
>  passive partitions is trivial if you take the attitude that shared
>  variables in the 9.10 sense are erroneous

Intentionally, the annex avoids specifying a shared passive package capability
that incurs a significant additional implementation cost. For example, the
Rationale (E.1) mentions that "By naming a shared passive library unit (which
resides in a passive partition) in a context clause, the referencing unit
gains access to data and code that may be shared with other partitions.
Different active partitions (executing on separate nodes) may thus shared
protected data or call subprograms in such shared passive units. An active
partition can obtain mutually exclusive access to data in a shared passive
package if the data is encapsulated in a protected object or is specified as
atomic."

>  -- if the only shared variables
>  allowed are those inside protected types, then shared passive partitions
>  provide no additional capability over RCI partitions).

I do not understand this last point. Remote call interface package
specifications cannot include variable declarations.

>  Anthony, I am really puzzled, are you saying that you do NOT think of shared
>  passive partitions as providing shared memory capability.

E.2.1 requires that data in a passive partition be shared among active
partitions. Since a passive partition may be mapped to a storage node
then a passive partition does provide for a shared memory capability.
Our disagreement is in the interpretation of what a shared memory
capability implies. Apparently you have in mind a capability that
provides some form of implicit synchronization of partitions (which is
of course not precluded by the annex).

>  YOu say "if access to a shared variable is erroneous for a nonpartitioned
>  program, it will be erroneous for a paritioned progrm". Well yes, but in
>  the nonpartitioned case, you can synchronize with an entry call. From a
>  users point of view, an RPC is a similar synchronization.

In the partitioned case synchronization can be achieved if the
variable is a protected object.

>  If you aim to get the same expressive power for shared passive partitions
>  as for non-partioned programs, then you must do something, because in the
>  non-partitioned case, you can syncrhnoize to make the access to the shared
>  data valid, but there is simply no way to do this in the partitioned case.

This is correct. However, once again the annex does not require the
same expressive power.

>  Let me again note my simple example.

>  You wish to have a shared passive partition with a bunch of data in it.
>  This data is for almost all the execution of the program read only, but
>  in the start up phase of the program, this data is computed on the basis
>  of supplied data.

It seems that including the data in a protected object is a
straightforward method of accomplishing this example by maintaining
some kind of "ready" status. The partition that performs the
initialization must set the ready status. Thus other partitions must
explicitly query this status before attempting to use the data.

****************************************************************

!section 9.10(00)
!subject Shared Variables in Shared_Passive?
!reference RM95-9.10, RM95-E.2.1
!reference 96-5647.a Laurent Guerby  96-8-23
!reference 96-5649.a Anthony Gargaro  96-8-24
!reference 96-5656.a Robert A Duff 96-8-27
!keywords synchronization
!reference 96-5650.a Robert Dewar 96-8-25
!reference 96-5658.a Robert Dewar 96-8-28
!reference 96-5662.a Robert A Duff 96-8-29
!reference 96-5666.a Robert Dewar 96-8-30
!reference 96-5673.a Anthony Gargaro  96-9-1
!reference as: 96-5674.a Robert Dewar 96-9-2
!reference as: 96-5679.a Anthony Gargaro
!from Robert Dewar
!reference 96-5682.a Robert Dewar 96-9-4>>
!discussion

I am completely puzzled by Anthony's reaction here. If the only shared
data that is available is protected objects, then that means the only
interface to such data is via a procedural interface. But in this case,
shared passive partitions provide ZERO functionality, since of course
the normal RPC mechanism can perfectly well provide an absolutely
identical interface.

Shared data means to me data that can be shared directly. The functionality
of shared passive partitions is important, since it corresponds to a feature
that has been found useful (shared memory) in programming distributed
applications.

After all the language allows non-protected variables to appear in shared
passive partitions? Why? Was this simply a careless mistake? Given Anthony's
viewpoint, it is always erroneous to place a non-protected variable in
a shared passive partition, so clearly they should not be allowed if that
is really your viewpoint.

To me this is a major hole in the language, and one of two things should be
done. Either completely remove passive partitions from the language, on the
grounds that they are misleading and provide no functionality, or fix them
so that they do provide shared data.

This is not only an issue of expressive power, but also of efficiency. The
requirement that any access to shared data be via protected objects means
that you have all the overhead (typically significant when operating over
an operating system, as will usually be the case with distributed
applications) of protected objects, making this feature useless for efficient
interchange of data.

As I said before, the issue is largely academic, since it is obvious that
convenient access to shared memory is an important requirement, and certainly
in GNAT we will implement it regardless, so what we are discussing is whether
this should be a required part of Annex E functionality or not.

I note that we have found the facilities of Annex E to be very widely
applicable, and in particular, they seem well suited for the implementation
of MetaH, but this observation is entirely predicated on the availability
of shared memory.

****************************************************************

!section 9.10(00)
!subject Shared Variables in Shared_Passive?
!reference RM95-9.10, RM95-E.2.1
!reference 96-5647.a Laurent Guerby  96-8-23
!reference 96-5649.a Anthony Gargaro  96-8-24
!reference 96-5656.a Robert A Duff 96-8-27
!keywords synchronization
!reference 96-5650.a Robert Dewar 96-8-25
!reference 96-5658.a Robert Dewar 96-8-28
!reference 96-5662.a Robert A Duff 96-8-29
!reference 96-5666.a Robert Dewar 96-8-30
!reference 96-5673.a Anthony Gargaro  96-9-1
!reference as: 96-5674.a Robert Dewar 96-9-2
!reference as: 96-5679.a Anthony Gargaro
!reference 96-5682.a Robert Dewar 96-9-4
!from Tucker Taft 96-09-05
!reference 96-5686.a Tucker Taft 96-9-5>>
!discussion

Rather than treating an RPC as any special kind of synchronization,
I would rather treat an RPC like a normal subprogram call.
In particular, this means that the normal "sequentiality" between
a caller and a callee within a single task would apply between
the caller and the remote callee.

In 9.10 terms, this means that the actions occurring as part of executing
the remote subprogram body are "sequential" with the actions occurring in the
calling task.  It is as though they are both part of the same task.

-Tuck

****************************************************************

!section 9.10(00)
!subject Shared Variables in Shared_Passive?
!reference RM95-9.10, RM95-E.2.1
!reference 96-5647.a Laurent Guerby  96-8-23
!reference 96-5649.a Anthony Gargaro  96-8-24
!reference 96-5656.a Robert A Duff 96-8-27
!keywords synchronization
!reference 96-5650.a Robert Dewar 96-8-25
!reference 96-5658.a Robert Dewar 96-8-28
!reference 96-5662.a Robert A Duff 96-8-29
!reference 96-5666.a Robert Dewar 96-8-30
!reference 96-5673.a Anthony Gargaro  96-9-1
!reference as: 96-5674.a Robert Dewar 96-9-2
!reference as: 96-5679.a Anthony Gargaro
!reference 96-5682.a Robert Dewar 96-9-4
!reference 96-5686.a Tucker Taft 96-9-5>>
!from Robert Dewar
!reference 96-5687.a Robert Dewar 96-9-6>>
!discussion

Tuck said:

  Rather than treating an RPC as any special kind of synchronization,
  I would rather treat an RPC like a normal subprogram call.
  In particular, this means that the normal "sequentiality" between
  a caller and a callee within a single task would apply between
  the caller and the remote callee.

  In 9.10 terms, this means that the actions occurring as part of executing
  the remote subprogram body are "sequential" with the actions occurring in the
  calling task.  It is as though they are both part of the same task.
Robert replies

  OK, but how does this relate to the discussion at hand.

  The issue again is the following.

  Shared passive partitions allow the use of ordinary variables. But it
  appears that with the current RM definition. Any program that declares
  such a variable can only reference it from one partition, making a
  mockery of the idea of shared data.

  Either such shared data should be banned in shared passive partitions,
  in which case they are not much use, or the language should provide
  some way of making them work as expected.

****************************************************************

!section 9.10(00)
!subject Shared Variables in Shared_Passive?
!reference RM95-9.10, RM95-E.2.1
!reference 96-5647.a Laurent Guerby  96-8-23
!reference 96-5649.a Anthony Gargaro  96-8-24
!reference 96-5656.a Robert A Duff 96-8-27
!keywords synchronization
!reference 96-5650.a Robert Dewar 96-8-25
!reference 96-5658.a Robert Dewar 96-8-28
!reference 96-5662.a Robert A Duff 96-8-29
!reference 96-5666.a Robert Dewar 96-8-30
!reference 96-5673.a Anthony Gargaro  96-9-1
!reference as: 96-5674.a Robert Dewar 96-9-2
!reference as: 96-5679.a Anthony Gargaro
!reference 96-5682.a Robert Dewar 96-9-4
!reference 96-5686.a Tucker Taft 96-9-5
!reference 96-5687.a Robert Dewar 96-9-6
!from Tucker Taft 96-09-06
!reference 96-5688.a Tucker Taft 96-9-6>>
!discussion

> Tuck said:
>
>   Rather than treating an RPC as any special kind of synchronization,
>   I would rather treat an RPC like a normal subprogram call.
>   In particular, this means that the normal "sequentiality" between
>   a caller and a callee within a single task would apply between
>   the caller and the remote callee.
>
>   In 9.10 terms, this means that the actions occurring as part of executing
>   the remote subprogram body are "sequential" with the actions occurring in
>   the calling task.  It is as though they are both part of the same task.

> Robert replies
>
>   OK, but how does this relate to the discussion at hand.
>
>   The issue again is the following.
>
>   Shared passive partitions allow the use of ordinary variables. But it
>   appears that with the current RM definition. Any program that declares
>   such a variable can only reference it from one partition, making a
>   mockery of the idea of shared data.
>
>   Either such shared data should be banned in shared passive partitions,
>   in which case they are not much use, or the language should provide
>   some way of making them work as expected.

I guess my quick note didn't give enough information.

All you need to do to make unprotected data legitimately shareable is
for sequentiality to be established between the two tasks that
are manipulating the data.  If we presume sequentiality between
an RPC caller and the RPC callee, then this can be done by having the two
tasks both make an RPC to the same partition, and the two remote subprogram
bodies signal each other in one of the usual ways.

Hence, a task could write a bunch of stuff into an unprotected variable
in a shared-passive package, make an RPC to inform the world that they
are done, and then one or more other tasks (which have also made appropriate
RPCs, presumably) could read from the unprotected variable.  This could
still be much more efficient than passing the data itself via an RPC.

Of course if the variable is marked volatile, then you don't need
an RPC to establish sequentiality, and simple "ordering" can be
established using a spinlock implemented using a shared entryless
protected object or an atomic variable.

Robert also mentioned synchronization relative to partition
elaboration time.  Based on the semantics of a remote subprogram call
given in E.4(14), it should be clear that any (non-asynchronous) RPC that
returns without Communication_Error is an indication that the remote
partition has been elaborated.  If we add anything to the RM to cover
synchronization in the presence of distribution, it probably makes sense
to mention this as well.

-Tuck

****************************************************************

!section 9.10(00)
!subject Shared Variables in Shared_Passive?
!reference RM95-9.10, RM95-E.2.1
!reference 96-5647.a Laurent Guerby  96-8-23
!reference 96-5649.a Anthony Gargaro  96-8-24
!reference 96-5656.a Robert A Duff 96-8-27
!keywords synchronization
!reference 96-5650.a Robert Dewar 96-8-25
!reference 96-5658.a Robert Dewar 96-8-28
!reference 96-5662.a Robert A Duff 96-8-29
!reference 96-5666.a Robert Dewar 96-8-30
!reference 96-5673.a Anthony Gargaro  96-9-1
!reference as: 96-5674.a Robert Dewar 96-9-2
!reference as: 96-5679.a Anthony Gargaro
!reference as: 96-5682.a Robert Dewar 96-9-4
!from Anthony Gargaro 96-9-7
!reference 96-5691.a Anthony Gargaro  96-9-7>>
!discussion

>Robert notes:

>I am completely puzzled by Anthony's reaction here. If the only shared
>data that is available is protected objects, then that means the only
>interface to such data is via a procedural interface. But in this case,
>shared passive partitions provide ZERO functionality, since of course
>the normal RPC mechanism can perfectly well provide an absolutely
>identical interface.

The advantage of using a protected object in a shared passive partition over
using the remote call capability is that it avoids the overhead of a remote
call which at a minimum requires marshaling/unmarshaling. Furthermore, as is
mentioned in subsequent comments, using remote calls to support shared
variables still requires that the calls be synchronized.

>After all the language allows non-protected variables to appear in shared
>passive partitions? Why? Was this simply a careless mistake? Given Anthony's
>viewpoint, it is always erroneous to place a non-protected variable in
>a shared passive partition, so clearly they should not be allowed if that
>is really your viewpoint.

It should be recalled that one important aspect in specifying Annex E
was to balance functionality with implementation cost. The issue of
non-protected variables was discussed at the IRTAW-6 (Ravenscar 92,
were you not present) and the sentiment was that requiring support
beyond that provided by protected objects and pragma Atomic might be
unacceptable to implementors. (Note that at the time Annex E required
that Annex C be supported.)

>Shared data means to me data that can be shared directly.

In the case of the example that you presented in an earlier comment,
i.e., a single one-time writer partition and multiple reader
partitions, this can be achieved. Consider the case that the writer
allocates and writes to the variable using a protected object. Readers
may then obtain the access value to the variable using the same
protected object so that subsequent reads are made using this access
value.

>To me this is a major hole in the language, and one of two things should be
>done. Either completely remove passive partitions from the language, on the
>grounds that they are misleading and provide no functionality, or fix them
>so that they do provide shared data.

The first position seems too extreme. A possible compromise is to provide
a documentation requirement where an implementation must state whether
or not access to a non-protected variable is erroneous.

>This is not only an issue of expressive power, but also of efficiency. The
>requirement that any access to shared data be via protected objects means
>that you have all the overhead (typically significant when operating over
>an operating system, as will usually be the case with distributed
>applications) of protected objects, making this feature useless for efficient
>interchange of data.

I do not understand why you seem to presume that using a protected object
declared in a shared passive package is any less efficient than using a
protected object declared elsewhere. Why would there be a difference in
efficiency? It seems that only when an implementation supports some form of
distributed shared virtual memory does this become an efficiency issue.

>As I said before, the issue is largely academic, since it is obvious that
>convenient access to shared memory is an important requirement, and certainly
>in GNAT we will implement it regardless, so what we are discussing is whether
>this should be a required part of Annex E functionality or not.

It would be helpful if you would suggest the proposed change that does
not preclude the GNAT implementation. If this is an instance of where
the implementors believe that the Annex is too conservative, it would
be a very appropriate topic for discussion at the next IRTAW.

****************************************************************

!section 9.10(00)
!subject Shared Variables in Shared_Passive?
!reference RM95-9.10, RM95-E.2.1
!reference 96-5647.a Laurent Guerby  96-8-23
!reference 96-5649.a Anthony Gargaro  96-8-24
!reference 96-5656.a Robert A Duff 96-8-27
!keywords synchronization
!reference 96-5650.a Robert Dewar 96-8-25
!reference 96-5658.a Robert Dewar 96-8-28
!reference 96-5662.a Robert A Duff 96-8-29
!reference 96-5666.a Robert Dewar 96-8-30
!reference 96-5673.a Anthony Gargaro  96-9-1
!reference 96-5674.a Robert Dewar 96-9-2
!reference 96-5679.a Anthony Gargaro
!reference 96-5682.a Robert Dewar 96-9-4
!reference 96-5691.a Anthony Gargaro  96-9-7
!reference 96-5693.a Robert Dewar 96-9-8>>

!from Robert Dewar
!discussion

Anothony said (non-indented text)

It should be recalled that one important aspect in specifying Annex E
was to balance functionality with implementation cost. The issue of
non-protected variables was discussed at the IRTAW-6 (Ravenscar 92,
were you not present) and the sentiment was that requiring support
beyond that provided by protected objects and pragma Atomic might be
unacceptable to implementors. (Note that at the time Annex E required
that Annex C be supported.)

Rober replies (indented text)

  Fine, but then one of two things should happen:

    (a) non-protected objects should be required to have a pragma Atomic

         or

    (b) something should be done in the language to make it clear that it
        is at least optionally possible to allow non-protected non-Atomic
        shared objects in a non-erroneous manner

  It makes no sense to have a situation in the language where
  you allow something
  syntactically and semantically, which looks like a big useful feature, but
  which in practice is completely useless since any use is bound to be
  erroneous.

  I don't mind this feature being optional, after all the whole annex is
  optional, so you don't have to implement anything in it, but I would like
  the option of doing it properly.

  Note that the implementation is extremely straightforward on a single
  machine that supports normal Unix shared memory semantics. That's why
  I think the language should be adjusted to allow it.

I do not understand why you seem to presume that using a protected object
declared in a shared passive package is any less efficient than using a
protected object declared elsewhere. Why would there be a difference in
efficiency? It seems that only when an implementation supports some form of
distributed shared virtual memory does this become an efficiency issue.

  You are imagining! I never said that using a protected object declared in
  a shared package was less efficient than using a protected object declared
  elsewhere. All I said is that when building over an operating system, using
  a protected object declared in a shared package can be very inefficient
  JUST LIKE using a protected object anywhere. The whole design of protected
  objects makes sense only if you have a light locking mechanism, which you
  often do not on a multi-processor with an operating system.

It would be helpful if you would suggest the proposed change that does
not preclude the GNAT implementation. If this is an instance of where
the implementors believe that the Annex is too conservative, it would
be a very appropriate topic for discussion at the next IRTAW.

  Nothing precludes the GNAT implementation. As I have said before, the issue
  can be left moot as far as GNAT is concerned. The situation we have in
  GNAT is that we have implemented a useful facility which is consistent with
  the syntactic and semantic requirements of the RM. It is true that all
  programs using this facility are erroneous, but their effect is well
  defined and the fact that the programs are erroneous is not
  going to keep programmers awake at night, only language lawyers!

It would be helpful if you would suggest the proposed change that does
not preclude the GNAT implementation. If this is an instance of where
the implementors believe that the Annex is too conservative, it would
be a very appropriate topic for discussion at the next IRTAW.

  That sounds like a very good idea. By all means lets do this, and in fact
  I would be happy to volunteer to lead the discussion. You (or whoever) can
  consider my contributions to the list a position paper on the subject!

****************************************************************

Questions? Ask the ACAA Technical Agent