I don't see any trace of this in FSF GCC; has it gone for good?
> Le 10/09/2011 17:19, Simon Wright a écrit :
> > It used to be that you could configure GNAT to use a tasking RTS that
> > didn't use threads; tasks were scheduled entirely within the RTS. I
> > think these may be called 'green threads'[1]. Of course, this meant that
> > blocking on I/O would block the whole program, but for some purposes it
> > might be ideal.
> >
> No, it used the FSU threads
FSU threads were used to implement Ada tasking in Tenon's MachTen and
CodeBuilder products for Mac OS 9.
<http://www.tenon.com/products/machten/>
--
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>
"FSU threads library", "pthreads library" (Solaris only),
"Zero-Cost Exceptions" ("ZCX"), and "setjmp/longjmp"
("SJLJ"), are optional if compiled, by using the "--RTS="
command line option.
Note: "FSU threads library" provide a completely accurate implementation
of Annex D. Since "Glade" was replaced, not sure if GNAT, still provide
a true implementation of Annex D.
Presumably, by "siji" you meant "sjlj" which stands for "setjump/
longjump exception handling". GCC presently comes with two run-time
systems:
- zero-cost exception handling aka ZCX aka "native", which is the
default
on most architectures. The phrase "zero-cost" really means "zero
distributed cost" which means you do not pay a performance penalty
unless
and until you raise an exception. Raising an exception is however
costly.
- sjlj aka setjump/longjump, which is the alternative, in which every
frame
that might possibly raise an exception calls setjmp(3), thus
incurring
distributed cost, and raising an exception calls longjmp(3), which
is
cheap compared to the raising of an exception with ZCX. sjlj is the
only
supported run-time system on a few, non-mainstream architectures.
Both run-time systems now use native threads and both support Annex D
(real-time systems) insofar as the underlying kernel does. The old
FSU threads were intended to provide better support for Annex D but
that was rendered unnecessary by the advances in Linux, Solaris and
other kernels.
It is true that, a few years ago, Glade used to require the sjlj run-
time system to implement exception handling across partitions in in
distributed programs (Annex E). I know because I packaged it for
Debian. However, PolyORB has not required sjlj since it introduced
support for Annex E in version 2.2.
--
Ludovic Brenta.
The stakeholders enable the educated core business by leveraging the
plannings.
> On 13.09.11 10:30, Simon Wright wrote:
>
>> My prompt for asking this was a colleague who was used to Erlang and was
>> complaining that GNAT's use of OS threads meant he would have to change
>> his design mindset to not use thousands of tasks (Erlang processes).
>
> Just an idea: using mostly functions together with protected
> channel objects should allow to use Ada in a way one
> might be used to when passing Erlang data around.
Unfortunately this does not work this way for many reasons (I have
evaluated this design for our middleware and quickly dropped the idea).
Protected objects are not tagged, you need inheritance to provide typed
channels. You meed multiple dispatch to handle channel-type + value-type
hierarchies. You need entries returning indefinite values. You need MI to
have handles to the channels/devices implementing the interface of a
protected object.
> You write to some entry/procedure of a PO (pass data down
> the channel) and read from some entry/function of the PO
> (read from a channel). Add barriers as needed.
Of course this can only be the transport layer. In our design at the
application layer the channels are multiplexed into typed named channels,
so that you can exchange data as if you had one channel per each variable
and in full duplex mode of course.
--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
However implemented, this call can only initiate I/O.
> Can "agents" then simply share a physical task by being selected
> for acting, perhaps triggered by messages sent (rendezvous if ready),
> or by some simple scheduler task selecting them in a round robin fashion,
> or in a way that resembles reacting to HTTP requests in AWS?
Yes, they do. In my design, there is a queue to the I/O task (of a
"device"), to which the operation is queued. Note how this resembles the
behavior of a entry task, being unable to become one.
> Yes, when some agent needs to both deliver a message and be
> sure the message is sent, then it may wait in the channel's queue
> forever until delivery is signaled. If the system allows messages
> to be dropped, then barriers can reflect this permission.
> How would tasks be more helpful?
Yes there is much stuff coming with. You want to be able to wait for a
completion. You want to be able to cancel the operation pending. You want
all temporary objects freed. You want references between objects and their
marshaled parts etc.
To much disappointment, though this appears very similar to how Ada tasks
works, it is impossible to promote as a task or reuse task mechanics
(queues for example).
> Thus, reducing the Channel PO to a very basic thing,
> and, unfortunately, exhibiting all the pointers inherent
> in most functional programming languages,
>
> package Sys is
>
> type Any is abstract tagged limited null record;
> -- ... parent/interface of every message type
Nope, you want to send/receive types, e.g. Integer, not messages. For
"messages" there is already Stream_Array, uninteresting.
> type Box is tagged private;
> -- holds a value of type `Any'Class`; see `Ref` and `Deref`
>
> -- functions for wrapping and unwrapping:
> function Ref (Item : Any'Class) return Box;
> function Deref (This : Box) return access constant Any'Class;
You don't need that, it has values semantics, because things are marshaled.
I have reference-counted handles to the devices and variables
("registers"), but that is mostly because of the language. From the
application point of view, the scopes of devices and variables are static.
Counters are used because there is no way to express their dependencies in
a static manner.
> protected type Channel (Capacity : Natural) is
>
> entry Send (Object : in Box);
> -- ! operation
That is a "device" interface (the transport layer [*]). Actually Send is a
primitive operation of a register, rather than the device (the application
layer). When you do Send, you queue to the device an I/O request with a
reference to the register. You also return back the request object to the
caller, in order to be able to wait for it or cancel it. You may have
several requests pending on a variable, if the underlying protocol support
this.
This is how it looks like in my design:
Device : EtherCAT_Device_Handle := Create (Name, Adapter);
Output : Middleware.Output.Integers_16.Register_Handle := ...
...
Output.Send (123); -- Asynchronous send
Output.Wait; -- Wait for completion
Output.Write (456); -- Synchronous send and wait
And do not forget the opposite direction:
Input.Request; -- Asynchronous request
X := Input.Wait; -- Wait for completion
Y := Input.Read; -- Synchronous request and wait
----
* It cannot be a protected object either, because you want reusable
implementations of the devices. E.g. I have abstract half-duplex device
driver with abstract primitive operations. Protected objects are not
composable upon inheritance. The object you had in mind is still there, but
in the form of a specialized lock object hidden deep inside.