comp.lang.ada
 help / color / mirror / Atom feed
* Advice,  tasking and hardware
@ 2016-05-25 21:24 patrick
  2016-05-26  1:09 ` Jeffrey R. Carter
                   ` (2 more replies)
  0 siblings, 3 replies; 33+ messages in thread
From: patrick @ 2016-05-25 21:24 UTC (permalink / raw)


Hi Everyone

I don't want to troll the list, I need some honest advice and I need to be honest about my goals, I hope I don't offend anyone.

I spent almost every night in 2012 studying Ada. I bought/printed 53 lbs of Ada books.

I struggled to find a GUI binding I liked and I struggled to work with C. I wanted to use Ada to avoid using C and I didn't understand C well.

For the past few years I have been using GnuCOBOL. I absolutely love it. It is much easier to interface to C with and it compiles to intermediate C so it's easier to see what is happening rather then going from Ada to Assembly. While the interfaces.COBOL package is quite outdated and does not have knowledge of modern COBOL it does work well and I can mix the two languages.

I am thinking about writing a backend in Ada again. I could do it in COBOL but tasking and exceptions sound like a wise idea. I feel I am going to have an easier time with C this time around.

I don't have any experience with tasking though and while I have many examples of tasking in my books, none of them seem to call low level functions such as drivers or driver-like functions. I am planning on using the Linux-GPIB library.

Sorry for the long introduction, to the point...

Do you have any examples of tasking calling low level functions?

Spark doesn't use tasking, are there many dangers in using tasking with hardware?

Would it be wise to wrap C driver calls in a protected object or are most drivers in Linux thread safe and suitable for being called from different threads?

Could anyone give me some general guidelines? any pitfalls to avoid before I set out to attempt this?

Thanks for reading-Patrick



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-25 21:24 Advice, tasking and hardware patrick
@ 2016-05-26  1:09 ` Jeffrey R. Carter
  2016-05-26  8:13   ` Simon Wright
  2016-05-26  7:26 ` Dmitry A. Kazakov
  2016-05-28  0:25 ` rieachus
  2 siblings, 1 reply; 33+ messages in thread
From: Jeffrey R. Carter @ 2016-05-26  1:09 UTC (permalink / raw)


On 05/25/2016 02:24 PM, patrick@spellingbeewinnars.org wrote:
>
> I struggled to find a GUI binding I liked and I struggled to work with C. I
> wanted to use Ada to avoid using C and I didn't understand C well.
>
> For the past few years I have been using GnuCOBOL. I absolutely love it. It
> is much easier to interface to C with and it compiles to intermediate C so
> it's easier to see what is happening rather then going from Ada to Assembly.
> While the interfaces.COBOL package is quite outdated and does not have
> knowledge of modern COBOL it does work well and I can mix the two languages.

I'm not sure what you're getting at here. A compiler's intermediate code is 
usually of no interest to a developer. I've done more interfacing to C from Ada 
than I'd like, and it's usually straightforward.

> I don't have any experience with tasking though and while I have many
> examples of tasking in my books, none of them seem to call low level
> functions such as drivers or driver-like functions. I am planning on using
> the Linux-GPIB library.

Every call to a subprogram in Ada, be it high-level or low-level, is made by a 
task. The elaboration and the the main-program subprogram are executed by the 
environment task. Any subprogram calls made, directly or indirectly, by the main 
program are made by the environment task. I see no reason why you should expect 
calls from user-defined tasks to be any different.

> Spark doesn't use tasking, are there many dangers in using tasking with
> hardware?

SPARK 2014 includes Ravenscar tasking. 
(http://docs.adacore.com/spark2014-docs/html/lrm/tasks-and-synchronization.html)

I don't know how you'd use tasking without hardware. Concurrent development is a 
superset of sequential development, and some who are competent at the latter 
have difficulty with the former, even after extensive experience. Deadlock and 
race conditions are common dangers if you don't understand concurrency (and 
sometimes if you do).

> Would it be wise to wrap C driver calls in a protected object or are most
> drivers in Linux thread safe and suitable for being called from different
> threads?

That will depend on the library you're binding to, and you should refer to its 
documentation. If in doubt, wrapping the calls in a PO will ensure they are made 
sequentially.

-- 
Jeff Carter
"He didn't get that nose from playing ping-pong."
Never Give a Sucker an Even Break
110


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-25 21:24 Advice, tasking and hardware patrick
  2016-05-26  1:09 ` Jeffrey R. Carter
@ 2016-05-26  7:26 ` Dmitry A. Kazakov
  2016-05-26 16:41   ` patrick
  2016-05-26 19:35   ` Jeffrey R. Carter
  2016-05-28  0:25 ` rieachus
  2 siblings, 2 replies; 33+ messages in thread
From: Dmitry A. Kazakov @ 2016-05-26  7:26 UTC (permalink / raw)


On 25/05/2016 23:24, patrick@spellingbeewinnars.org wrote:

> Do you have any examples of tasking calling low level functions?

Just call it as any other subprogram.

> Spark doesn't use tasking, are there many dangers in using tasking with hardware?

Dangers to the hardware? (:-))

Pre-/postcondition based proofs (SPARK's business) are pretty much 
orthogonal to tasking issues. Schedulability and other tasking stuff has 
a non-functional aspect whereas proofs are about functional issues. If 
you are concerned about static analysis regarding tasks, see Ravenscar 
profile.

> Would it be wise to wrap C driver calls in a protected object or are
> most drivers in Linux thread safe and suitable for being called from
> different threads?

Driver calls are thread safe. It does not mean that they are safe from 
the higher level semantics point of view. E.g. it is safe to delete a 
file in one process and open it in another, safe at the filesystem 
level, but unsafe at the application level.

Anyway, you never call driver operations from a protected action because 
it is a "potentially blocking" call. Even if not blocking in the sense 
of being asynchronous to the CPU/memory bus cycles, accessing hardware 
might be quite slow, e.g. reading/writing a hardware port, dual-ported 
memory access etc. A protected action is considered logically instant.

If you want interlocking for doing blocking calls use a mutex etc. A 
mutex implementation based on protected objects is two actions: Seize 
and Release.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-26  1:09 ` Jeffrey R. Carter
@ 2016-05-26  8:13   ` Simon Wright
  0 siblings, 0 replies; 33+ messages in thread
From: Simon Wright @ 2016-05-26  8:13 UTC (permalink / raw)


"Jeffrey R. Carter" <spam.jrcarter.not@spam.not.acm.org> writes:

>> Spark doesn't use tasking, are there many dangers in using tasking
>> with hardware?
>
> SPARK 2014 includes Ravenscar
> tasking. (http://docs.adacore.com/spark2014-docs/html/lrm/tasks-and-synchronization.html)

But SPARK GPL 2015 doesn't support tasking. We live in hope that SPARK
GPL 2016 will.

I'm not sure of the best way to delegate tasking to the non-SPARK part
of a program while maintaining SPARK for as much as possible. I suppose
you'd have to be very restrained in your use of tasking (e.g. perhaps
only use Ravenscar tasking, have the task call a SPARK subprogram to do
the work).

I had a program with a large PO/task job dispatcher with multiple
entries and requeues in the PO, which was hugely improved when I had to
reimplement under Ravenscar.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-26  7:26 ` Dmitry A. Kazakov
@ 2016-05-26 16:41   ` patrick
  2016-05-26 17:56     ` Dmitry A. Kazakov
  2016-05-26 20:35     ` Jeffrey R. Carter
  2016-05-26 19:35   ` Jeffrey R. Carter
  1 sibling, 2 replies; 33+ messages in thread
From: patrick @ 2016-05-26 16:41 UTC (permalink / raw)


Hi Guys

Thanks for the feedback this is very helpful :)

I work with scientific instruments. I have been trying to write an application to control this instrumentation on and off for many years. It's back on.

I doubt that any of the software I see in my industry is written in Ada, there is no real exception handling. Joel is a an exception, they work with high end mass spectrometers and were featured in an Adacore commercial.

If there is a hardware failure of any kind software in this business just locks up silently or there is a non-descriptive error like "instrument error", even when there are multiple instruments networked into a system.

Does this approach sound logical for a first attempt with tasking:

I could write a mostly single threaded application that used tasking for error detection/handling only.

I could queue tasks. One would be called just before calling into a driver. The task would delay for a given amount of time and if the call to the driver blocked unexpectedly the task would reach a point were it will notify the user with a detailed error message. If the driver call did not block another task would be called to signal that the driver call completed on time and the first task would be notified at rendezvous that it was on time and the tasks would queue again and wait for the next driver call.

This may not be a full use of Ada but it would be better then what's currently being used on the market in my industry.

Thanks again-Patrick


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-26 16:41   ` patrick
@ 2016-05-26 17:56     ` Dmitry A. Kazakov
  2016-05-26 20:35     ` Jeffrey R. Carter
  1 sibling, 0 replies; 33+ messages in thread
From: Dmitry A. Kazakov @ 2016-05-26 17:56 UTC (permalink / raw)


On 2016-05-26 18:41, patrick@spellingbeewinnars.org wrote:

> I work with scientific instruments. I have been trying to write an
> application to control this instrumentation on and off for many years.
> It's back on..
>
> I doubt that any of the software I see in my industry is written in
> Ada, there is no real exception handling.

It is the "state of the art" in all automation industry. There is 
practically no diagnostics at all. The software is written by technical 
engineers with no understanding of software and protocols design.

> If there is a hardware failure of any kind software in this business
> just locks up silently or there is a non-descriptive error like
> "instrument error", even when there are multiple instruments networked
> into a system.

It is a software failure most of the time. The hardware is usually just 
fine.

> Does this approach sound logical for a first attempt with tasking:
>
> I could write a mostly single threaded application that used tasking
> for error detection/handling only.

For handling timeouts, you mean.

> I could queue tasks. One would be called just before calling into a
> driver. The task would delay for a given amount of time and if the call
> to the driver blocked unexpectedly the task would reach a point were it
> will notify the user with a detailed error message. If the driver call
> did not block another task would be called to signal that the driver
> call completed on time and the first task would be notified at
> rendezvous that it was on time and the tasks would queue again and wait
> for the next driver call.

You should beware using vendor libraries, many of them are not 
thread-safe. Some require that all calls be from the same task. E.g. if 
you open the device and get a handle to it, then all subsequent 
operations must occur on the context of the same thread. [ Under Linux 
and Windows Ada task corresponds to a thread ]

A typical Ada design is writing an interface object encapsulating an I/O 
task that does all exchange with the device. That is when you have a 
half-duplex communication with the device. [ Software designed by 
technical engineers cannot go full duplex, it is an alien concept to 
them... ]

The calls involving communication to the device will do an entry call to 
the I/O task, e.g.

procedure Write_Something
           (  Device  : in out Device_Type;
              Data    : Data_Type;
              Timeout : Duration
           )  is
    Deadline : Time := Clock + Timeout;
begin
    select
       Device.IO_Task.Initiate_Write (Data); -- Begin I/O
    or delay until Deadline;
       raise Timeout_Error with "Device is busy";
    end select;
    select
       Device.IO_Task.Wait_For_Completion; -- Wait for I/O to end
    or delay until Deadline;
       raise Timeout_Error with "Device I/O is stalled";
    end select;
end Write_Something;

type IO_State is (Idle, Write_Completed);
task IO_Task (Device : not null access Device_Type'Class) is
    entry Initiate_Write (Data : Data_Type);
    entry Wait_For_Completion;
    entry Shut_Down;
end IO_Task;

task body IO_Task is
    Data_To_Write : Data_Type;
    State : IO_State := Idle;
begin
    -- Open device etc
    loop
       select
          accept Initiate_Write (Data : Data_Type) do
             Data_To_Write := Data; -- Store data
          end;
          Call_Driver (Data); -- This may block forever
          State := Completed;
       or accept Wait_For_Completion do
          if State = Write_Completed then
             State := Idle;
          else
             raise Use_Error with "No I/O pending";
          end if;
       or accept Shut_Down;
          exit;
       end select;
    end loop;
    -- Close device, cleanup
end IO_Task;

Of course with this there is no way to do anything useful after a 
timeout. Unless the library supports closing the device from outside. 
E.g. socket library allows closing the socket from another thread to 
terminate blocking socket I/O.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-26  7:26 ` Dmitry A. Kazakov
  2016-05-26 16:41   ` patrick
@ 2016-05-26 19:35   ` Jeffrey R. Carter
  2016-05-26 20:51     ` patrick
  2016-05-27  7:50     ` Dmitry A. Kazakov
  1 sibling, 2 replies; 33+ messages in thread
From: Jeffrey R. Carter @ 2016-05-26 19:35 UTC (permalink / raw)


On 05/26/2016 12:26 AM, Dmitry A. Kazakov wrote:
> 
> If you want interlocking for doing blocking calls use a mutex etc. A mutex
> implementation based on protected objects is two actions: Seize and Release.

To the OP: This is terrible advice. One should only use a low-level mechanism
such as a semaphore when one can't achieve what one needs with the high-level
mechanisms provided by the language: tasks and protected objects. Since there's
no way for the compiler to know that the subprogram is potentially blocking,
there's no reason not to put the call in a PO and make use of the high-level
mutual exclusion it provides. Even if the system has problems with the call
being in a protected operation, it's better to put a request for the call on a
protected queue and have a task that gets the requests from the queue and makes
the calls than to use a semaphore.

-- 
Jeff Carter
"This trial is a travesty. It's a travesty of a mockery of a
sham of a mockery of a travesty of two mockeries of a sham. ...
Do you realize there's not a single homosexual on that jury?"
Bananas
27

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-26 16:41   ` patrick
  2016-05-26 17:56     ` Dmitry A. Kazakov
@ 2016-05-26 20:35     ` Jeffrey R. Carter
  1 sibling, 0 replies; 33+ messages in thread
From: Jeffrey R. Carter @ 2016-05-26 20:35 UTC (permalink / raw)


On 05/26/2016 09:41 AM, patrick@spellingbeewinnars.org wrote:
> 
> I could write a mostly single threaded application that used tasking for
> error detection/handling only.
> 
> I could queue tasks. One would be called just before calling into a driver.
> The task would delay for a given amount of time and if the call to the driver
> blocked unexpectedly the task would reach a point were it will notify the
> user with a detailed error message. If the driver call did not block another
> task would be called to signal that the driver call completed on time and the
> first task would be notified at rendezvous that it was on time and the tasks
> would queue again and wait for the next driver call.

It sounds like you're interested in a "watchdog", which does something if an
action doesn't complete in time. Possible ways to implement this include the
selective abort (ATC), a timing event, or using a task.

ATC is simple:

select
   delay until Deadline;

   -- Whatever reporting or corrective action is needed
then abort
   Perform_Action;
   -- Whatever success reporting is needed
end select;

If the delay expires, an attempt is made to abort the "then abort" part.
Obviously you wouldn't use it if you don't want to abort the call. Note also
that there are things that cannot be aborted, so this may not work if
Perform_Action contains any of them. You should review ARM 9.8 to see if they
apply to you.

http://www.ada-auth.org/standards/rm12_w_tc1/html/RM-9-8.html

A timing event (ARM D.15) has an associated handler, which is a protected
procedure. Depending on what your compiler will let you get away with in a
protected operation, and how concerned you are about portability, you may be
able to put your reporting/recovery in the handler, and this is almost as simple
as ATC, though it's a bit harder to find out what the recovery options are. If
you want to do any potentially blocking operations, to be portable, your handler
needs to simply open the barrier on an entry of the same PO, and a task that
waits on that entry does the actual recovery. If you're going to do that, it's
simpler and clearer to just use a task.

You'd use a timing event this way

Event.Set_Handler (At_Time => Deadline, Handler => PO.Handler'access);
Perform_Action;
Event.Cancel_Handler (Cancelled => Canceled);

Deadline needs to have enough slack in it to prevent a race condition between
the handler being invoked and Cancel_Handler being called.

A task would look like

task Watchdog is
   entry Start (Deadline : in Time);
   entry Stop;
end Watchdog;

and is used similarly to a timing event

Watchdog.Start (Deadline => Deadline);
Perform_Action;
Watchdog.Stop;

and has a similar comment about race conditions.

The body of Watchdog is like

Forever : loop
   select
      accept Start (Deadline : in Time) do
         Expiry := Deadline;
      end Start;
   or
      terminate;
   end select;

   select
      accept Stop;
   or
      delay until Expiry;

      -- Recovery
   end select;
end loop Forever;

Note that this could be generic on the recovery action.

-- 
Jeff Carter
"This trial is a travesty. It's a travesty of a mockery of a
sham of a mockery of a travesty of two mockeries of a sham. ...
Do you realize there's not a single homosexual on that jury?"
Bananas
27

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-26 19:35   ` Jeffrey R. Carter
@ 2016-05-26 20:51     ` patrick
  2016-05-27  7:50     ` Dmitry A. Kazakov
  1 sibling, 0 replies; 33+ messages in thread
From: patrick @ 2016-05-26 20:51 UTC (permalink / raw)


Hi Jeffery

I value your advice but I also want to say that Dmitry has been a huge help to me and I have learned to trust his advice. I can't count the posts he answered for me in 2012, I won't forget his kindness.

-Patrick

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-26 19:35   ` Jeffrey R. Carter
  2016-05-26 20:51     ` patrick
@ 2016-05-27  7:50     ` Dmitry A. Kazakov
  2016-05-27 18:00       ` Simon Wright
                         ` (2 more replies)
  1 sibling, 3 replies; 33+ messages in thread
From: Dmitry A. Kazakov @ 2016-05-27  7:50 UTC (permalink / raw)


On 26/05/2016 21:35, Jeffrey R. Carter wrote:
> On 05/26/2016 12:26 AM, Dmitry A. Kazakov wrote:
>>
>> If you want interlocking for doing blocking calls use a mutex etc. A mutex
>> implementation based on protected objects is two actions: Seize and Release.
>
> To the OP: This is terrible advice. One should only use a low-level mechanism
> such as a semaphore when one can't achieve what one needs with the high-level
> mechanisms provided by the language: tasks and protected objects.

In practice it is not just a semaphore. The implementation protected 
object frequently carries higher level functions, e.g. protecting a 
queue of requests.

BTW an explicit queue is used only in the case of asynchronous 
processing of requests.

The rule of thumb is that if all requests are done synchronously to the 
caller, no task is used, only a protected interlocking object is. The 
entry of the protected object serves as a queue. If some requests are 
asynchronous, a task and a protected object are necessary.

A task alone is a rare case.

> Since there's
> no way for the compiler to know that the subprogram is potentially blocking,
> there's no reason not to put the call in a PO and make use of the high-level
> mutual exclusion it provides. Even if the system has problems with the call
> being in a protected operation, it's better to put a request for the call on a
> protected queue and have a task that gets the requests from the queue and makes
> the calls than to use a semaphore.

Tasks and protected objects have advantages and disadvantages. Regarding 
tasks the disadvantages are:

1. You need a task.

2. Ada tasks are difficult to compose, especially to have encapsulated 
tasks. Task components do not work in practical cases, so a pointer to 
the task will be required.

3. Ada tasks have problems with termination. The termination alternative 
design makes is unusable in most cases. There must be Shut_Down entry 
instead and a caller of it as well.

4. Task objects are tricky to deallocate. You must wait for task 
termination before calling Unchecked_Deallocation on it. Waiting within 
a Finalize is no fun.

5. Tasks entries have parameter passing problems. If you don't handle 
everything in the rendezvous in order to release the caller as soon as 
possible, you need to copy parameters and store them locally. The design 
of the select statement prevents doing this in a structured way. E.g.

    select
       accept String_Call (Text : String) do
          Local_Text := Text; -- Accept scope
       end;
       declare -- Handler's scope
          Local_Text : String -- This does not work!
       begin
          -- Process Local_Text
       end;
    or accept ...

6. Task entries cannot return unconstrained objects.

7 + 5-6. Task design requires sometimes a very complex state machine 
implementation to remember the order of accepted entries. It cannot be 
decomposed in a structured way because tasks are not composable. 
Protected objects have this too but they are somewhat simpler because 
some handling of the states could be done at the caller's side.

So in the end there could be a lot more low-level stuff regarding task 
maintenance, result passing, elaboration and finalization.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-27  7:50     ` Dmitry A. Kazakov
@ 2016-05-27 18:00       ` Simon Wright
  2016-05-27 19:06       ` Jeffrey R. Carter
  2016-05-27 19:13       ` Shark8
  2 siblings, 0 replies; 33+ messages in thread
From: Simon Wright @ 2016-05-27 18:00 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

> The rule of thumb is that if all requests are done synchronously to
> the caller, no task is used, only a protected interlocking object
> is. The entry of the protected object serves as a queue.

I think Ravenscar was mentioned? if using an RTS which only supports
Ravenscar, you can't have entry queues. I'm not sure whether you can mix
Ravenscar and unrestricted profiles within the same partition using the
full RTS?

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-27  7:50     ` Dmitry A. Kazakov
  2016-05-27 18:00       ` Simon Wright
@ 2016-05-27 19:06       ` Jeffrey R. Carter
  2016-05-27 22:05         ` Randy Brukardt
  2016-05-27 19:13       ` Shark8
  2 siblings, 1 reply; 33+ messages in thread
From: Jeffrey R. Carter @ 2016-05-27 19:06 UTC (permalink / raw)


On 05/27/2016 12:50 AM, Dmitry A. Kazakov wrote:

[a lot of irrelevant stuff]

No response to this post is needed, since it had nothing to do with the specific
point I made and to which he was apparently responding. However, there is a
false statement that should be corrected.

> 3. Ada tasks have problems with termination. The termination alternative design
> makes is unusable in most cases. There must be Shut_Down entry instead and a
> caller of it as well.

I have personally written hundreds of tasks that cannot use a terminate
alternative and do not have an entry to cause them to terminate, yet which
terminate normally when they should. Anyone who can't see multiple ways to
achieve this using only tasks and protected objects should not be considered
competent to develop concurrent software.

-- 
Jeff Carter
"I'm a kike, a yid, a heebie, a hook nose! I'm Kosher,
Mum! I'm a Red Sea pedestrian, and proud of it!"
Monty Python's Life of Brian
77


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-27  7:50     ` Dmitry A. Kazakov
  2016-05-27 18:00       ` Simon Wright
  2016-05-27 19:06       ` Jeffrey R. Carter
@ 2016-05-27 19:13       ` Shark8
  2016-05-27 20:27         ` Dmitry A. Kazakov
  2 siblings, 1 reply; 33+ messages in thread
From: Shark8 @ 2016-05-27 19:13 UTC (permalink / raw)


On Friday, May 27, 2016 at 1:50:50 AM UTC-6, Dmitry A. Kazakov wrote:
> 5. Tasks entries have parameter passing problems. If you don't handle 
> everything in the rendezvous in order to release the caller as soon as 
> possible, you need to copy parameters and store them locally. The design 
> of the select statement prevents doing this in a structured way. E.g.
> 
>     select
>        accept String_Call (Text : String) do
>           Local_Text := Text; -- Accept scope
>        end;
>        declare -- Handler's scope
>           Local_Text : String -- This does not work!
>        begin
>           -- Process Local_Text
>        end;
>     or accept ...

Pretty much a non-problem in Ada 2012:

    package Example is
	
	Task Text_IO is
	    Entry Get( Data : String );
	    Entry Put;
	    Entry Done;
	End Text_IO;
	
    end Example;
    
    package body Example is
	
	Task Body Text_IO is
	    Package String_Holder is new Ada.Containers.Indefinite_Holders(
	      Element_Type => String );

	    Internal_Data : String_Holder.Holder:= String_Holder.To_Holder("");
	    Finished      : Boolean := False;
	begin
	    loop
		select
		    accept Done do
			Finished:= True;
		    end Done;
		or
		    accept Get (Data : in String) do
			Internal_Data:= String_Holder.To_Holder( Data );
		    end Get;
		or
		    accept Put do
			Ada.Text_IO.Put_Line( "DATA: "& Internal_Data.Element );
		    end Put;
		end select;
		
		Exit when Finished;
	    end loop;
		
	End Text_IO;
	
    end Example;

and used via:
    Example.Text_IO.Put;
    Example.Text_IO.Get( "Test Data" );
    Example.Text_IO.Put;
    Example.Text_IO.Get( "Something Else" );
    Example.Text_IO.Put;

    Example.Text_IO.Done;

> 6. Task entries cannot return unconstrained objects.

This can be worked around:
   We can add to the previous task the following:
	    Entry Data( Item : out Natural );
	    Entry Data( Item : out String );
   Where the one returns the constraints needed for the other... it would be used something like this:
    declare
	Length : Natural renames Example.Text_IO.Data;
	Test   : constant String(1..Length):= Example.Text_IO.Data;
    begin
	Put_Line ( "----- " & Test & " -----" );
    end;


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-27 19:13       ` Shark8
@ 2016-05-27 20:27         ` Dmitry A. Kazakov
  2016-05-27 22:27           ` Randy Brukardt
  2016-05-28 14:38           ` Shark8
  0 siblings, 2 replies; 33+ messages in thread
From: Dmitry A. Kazakov @ 2016-05-27 20:27 UTC (permalink / raw)


On 2016-05-27 21:13, Shark8 wrote:
> On Friday, May 27, 2016 at 1:50:50 AM UTC-6, Dmitry A. Kazakov wrote:
>> 5. Tasks entries have parameter passing problems. If you don't handle
>> everything in the rendezvous in order to release the caller as soon as
>> possible, you need to copy parameters and store them locally. The design
>> of the select statement prevents doing this in a structured way. E.g.
>>
>>     select
>>        accept String_Call (Text : String) do
>>           Local_Text := Text; -- Accept scope
>>        end;
>>        declare -- Handler's scope
>>           Local_Text : String -- This does not work!
>>        begin
>>           -- Process Local_Text
>>        end;
>>     or accept ...
>
> Pretty much a non-problem in Ada 2012:
>
>     package Example is
> 	
> 	Task Text_IO is
> 	    Entry Get( Data : String );
> 	    Entry Put;
> 	    Entry Done;
> 	End Text_IO;
> 	
>     end Example;
>
>     package body Example is
> 	
> 	Task Body Text_IO is
> 	    Package String_Holder is new Ada.Containers.Indefinite_Holders(
> 	      Element_Type => String );

That is no solution. You still have to move entry-specific local data to 
the task-wide scope, which was the main point of being unstructured.

And you certainly don't want pool-allocated stuff in drivers. Finally, 
this is no different from Unbounded_String.

>> 6. Task entries cannot return unconstrained objects.
>
> This can be worked around:
>    We can add to the previous task the following:
> 	    Entry Data( Item : out Natural );
> 	    Entry Data( Item : out String );

This is a very low-level and very fragile design. Consider ensuring that 
nothing comes between querying the length and the body that could change 
the string. You start doing that with entry barriers risking running 
into a deadlock. Then consider a possibility that the caller of a 
get-length request dies prematurely, or that another task steals the 
string body and so on.

Note that the "discussion" started around the claim that design based on 
semaphore is more low-level than one based on monitor (the task serves 
as a monitor).

(There was a reason why protected objects were introduced in Ada 95)

P.S. The Ada-way of returning string is this:

    entry Get_Text (Text : in out String; Last : out Integer);

I am using a bit more general:

    entry Get_Text (Text : in out String; Pointer : in out Integer);

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-27 19:06       ` Jeffrey R. Carter
@ 2016-05-27 22:05         ` Randy Brukardt
  2016-05-27 23:09           ` Jeffrey R. Carter
  0 siblings, 1 reply; 33+ messages in thread
From: Randy Brukardt @ 2016-05-27 22:05 UTC (permalink / raw)


"Jeffrey R. Carter" <spam.jrcarter.not@spam.not.acm.org> wrote in message 
news:nia5lo$oik$1@dont-email.me...
> On 05/27/2016 12:50 AM, Dmitry A. Kazakov wrote:
>
> [a lot of irrelevant stuff]
>
> No response to this post is needed, since it had nothing to do with the 
> specific
> point I made and to which he was apparently responding. However, there is 
> a
> false statement that should be corrected.
>
>> 3. Ada tasks have problems with termination. The termination alternative 
>> design
>> makes is unusable in most cases. There must be Shut_Down entry instead 
>> and a
>> caller of it as well.
>
> I have personally written hundreds of tasks that cannot use a terminate
> alternative and do not have an entry to cause them to terminate, yet which
> terminate normally when they should. Anyone who can't see multiple ways to
> achieve this using only tasks and protected objects should not be 
> considered
> competent to develop concurrent software.

Huh. Most people *aren't* competent to develop concurrent software -- it's 
way too hard and (unlike sequential code) the compiler and language is no 
help. (Race conditions and deadlocks are trivial in Ada code; very little 
practical code doesn't have them.). But most of us have to develop such 
software anyway, whether or not we're competent.

So I don't find that much of an argument for any point vis-a-vis 
concurrency.

[Especially as I've never figured out how to properly shut down the tasks in 
any of my service programs. Maybe I could have figured out something, but it 
would have greatly complicated an already complicated system. Instead, I 
kill the process manually in the rare case that I need to restart a service 
(and I also have a watchdog program that kills and restarts non-responsive 
services, and triggers a full system reboot if that doesn't work - that 
probably would be needed in any case, just to keep services up as much as 
possible {in case of DoS bugs}). A club rather than a screwdriver, but a lot 
easier.]

                                             Randy.



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-27 20:27         ` Dmitry A. Kazakov
@ 2016-05-27 22:27           ` Randy Brukardt
  2016-05-28  6:49             ` Dmitry A. Kazakov
  2016-05-28 14:38           ` Shark8
  1 sibling, 1 reply; 33+ messages in thread
From: Randy Brukardt @ 2016-05-27 22:27 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:niaaji$1nar$1@gioia.aioe.org...
> On 2016-05-27 21:13, Shark8 wrote:
>> On Friday, May 27, 2016 at 1:50:50 AM UTC-6, Dmitry A. Kazakov wrote:
>>> 5. Tasks entries have parameter passing problems. If you don't handle
>>> everything in the rendezvous in order to release the caller as soon as
>>> possible, you need to copy parameters and store them locally. The design
>>> of the select statement prevents doing this in a structured way. E.g.
>>>
>>>     select
>>>        accept String_Call (Text : String) do
>>>           Local_Text := Text; -- Accept scope
>>>        end;
>>>        declare -- Handler's scope
>>>           Local_Text : String -- This does not work!
>>>        begin
>>>           -- Process Local_Text
>>>        end;
>>>     or accept ...
>>
>> Pretty much a non-problem in Ada 2012:
>>
>>     package Example is
>>
>> Task Text_IO is
>>     Entry Get( Data : String );
>>     Entry Put;
>>     Entry Done;
>> End Text_IO;
>>
>>     end Example;
>>
>>     package body Example is
>>
>> Task Body Text_IO is
>>     Package String_Holder is new Ada.Containers.Indefinite_Holders(
>>       Element_Type => String );
>
> That is no solution. You still have to move entry-specific local data to 
> the task-wide scope, which was the main point of being unstructured.
>
> And you certainly don't want pool-allocated stuff in drivers.

> Finally, this is no different from Unbounded_String.

Sure, if the only unconstrained type you ever use is a String. The 
Indefinite_Holders solution works for any unconstrained type, not just 
String.

And no one (I hope!) is putting tasks in drivers in the first place; one 
wants as little as possible in OS drivers, because they necessarily are 
outside of the control of the OS (written without the standards used for the 
OS, etc.) The caller of the driver needs to manage concurrency. So how one 
writes tasks isn't particularly relevant to writing drivers. (Whether or not 
the OS should avoid pool allocation is a different question altogether...)

Aside: I get the feeling that the term "drivers" has been totally corrupted 
in recent systems, including all kinds of higher-level junk that belongs to 
the OS. So we might be talking about different things.

                       Randy.


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-27 22:05         ` Randy Brukardt
@ 2016-05-27 23:09           ` Jeffrey R. Carter
  0 siblings, 0 replies; 33+ messages in thread
From: Jeffrey R. Carter @ 2016-05-27 23:09 UTC (permalink / raw)


On 05/27/2016 03:05 PM, Randy Brukardt wrote:
> 
> Huh. Most people *aren't* competent to develop concurrent software -- it's 
> way too hard and (unlike sequential code) the compiler and language is no 
> help. (Race conditions and deadlocks are trivial in Ada code; very little 
> practical code doesn't have them.). But most of us have to develop such 
> software anyway, whether or not we're competent.

Most people aren't competent to develop any software. That doesn't make it
acceptable that some incompetent is creating yet another buffer-overflow
vulnerability right now. I don't suppose there's any way to stop such people,
but we shouldn't encourage them.

> [Especially as I've never figured out how to properly shut down the tasks in 
> any of my service programs. Maybe I could have figured out something, but it 
> would have greatly complicated an already complicated system. Instead, I 
> kill the process manually in the rare case that I need to restart a service 
> (and I also have a watchdog program that kills and restarts non-responsive 
> services, and triggers a full system reboot if that doesn't work - that 
> probably would be needed in any case, just to keep services up as much as 
> possible {in case of DoS bugs}). A club rather than a screwdriver, but a lot 
> easier.]

I suspect it's a characteristic, if not a requirement, for these programs that
they be able to die suddenly without harm. Would you have taken the same
approach if not shutting down cleanly would cause problems? (I designed the
shutdown mechanism for a program with hundreds of tasks that ran as a service.
The program intercepted the signal sent by the service stop command, and
everything terminated cleanly as required.)

-- 
Jeff Carter
"I'm a kike, a yid, a heebie, a hook nose! I'm Kosher,
Mum! I'm a Red Sea pedestrian, and proud of it!"
Monty Python's Life of Brian
77


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice,  tasking and hardware
  2016-05-25 21:24 Advice, tasking and hardware patrick
  2016-05-26  1:09 ` Jeffrey R. Carter
  2016-05-26  7:26 ` Dmitry A. Kazakov
@ 2016-05-28  0:25 ` rieachus
  2016-05-28  1:57   ` patrick
  2016-05-28  4:13   ` Jeffrey R. Carter
  2 siblings, 2 replies; 33+ messages in thread
From: rieachus @ 2016-05-28  0:25 UTC (permalink / raw)


I think there is a lot of well argued stuff here which is several months ahead of where the OP is.

If you are writing a controller for a wall of instruments talking IEEE 488 or some such, and the goal is to write programs for automated testing, the first huge win with Ada is:

   In Ada you model the environment, not the problem set.

It is not unusual to have changes in the requirements for automated testing (or just about any other field) at the last minute.  If you modeled the environment/solution space, a small (in text terms) change in the requirements with require only a small change in the code.

Next, there are choices you have to make in doing your modelling.  Having a package corresponding to each instrument, and putting a task inside iff you need to deal with state in the instrument.  Otherwise use a protected object to insure sequential communications.

Some instruments have state, lots of state, others are nice and use a stateless protocol.  To use POs, to control other hardware you definitely want to do a classic semaphore.  Any thread/task talking to that device does a Seize, and a Release when done.  For devices with state, you need a task that tracks the state of the device.  Would it were so simple as that makes it sound.  The interface the package presents to the rest of the world is clean, but your task may end up pages long to deal with error states and recovery.

Finally how you deal with task termination will depend to a great deal on the safety requirements.  There is a design pattern when you need each active device to have a call during shutdown and multiple shutdowns are the way to go.  Basically you have a shutdown package in the with list of packages with hidden tasks.  You create a new task which does what is necessary and it waits on a task entry provided by the shutdown package:

package Shutdown is
  task Suspend is
    entry Stop;
    entry Wait;
  end Suspend;
end Shutdown;
...
package body Shutdown is
begin
 task body Suspend is
 begin
   accept Stop;
   loop
     select
       accept Wait;
     or
       accept Stop; -- in case of multiple calls to Stop.
     or
       terminate;
     end select;
   end loop;
 end Shutdown;

  Now any package can call Shutdown.Suspend.Wait from a task that does the necessary shutdown actions.  (This is about the only situation where you want to call abort in Ada.  You have a task which deals with normal operations, and a emergency task which turns of the gas, high voltage, fuel, or whatever.)

   task Killer is
   end Killer  -- no entries.

   task body Killer is 
   begin
     Shutdown.Suspend.Wait;
     select
       Local_Task.Shutdown;
     or delay XXX;  --- delay time will depend on physical system properties.
     end select;
     delay YYY;   --- delay time will depend on physical system properties.
     abort Local_Task;
     -- shut down everything controlled by Local_Task here.
   end Killer; 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice,  tasking and hardware
  2016-05-28  0:25 ` rieachus
@ 2016-05-28  1:57   ` patrick
  2016-05-28  4:13   ` Jeffrey R. Carter
  1 sibling, 0 replies; 33+ messages in thread
From: patrick @ 2016-05-28  1:57 UTC (permalink / raw)


Thanks so much for this, it's very helpful. I am a little surprised you even know what IEEE 488 is, it's not that common anymore. There are still hundreds of scientific instruments out there using it though not to mention test and measurement equipment.

Have a great weekend-Patrick

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-28  0:25 ` rieachus
  2016-05-28  1:57   ` patrick
@ 2016-05-28  4:13   ` Jeffrey R. Carter
  2016-06-01 14:37     ` rieachus
  1 sibling, 1 reply; 33+ messages in thread
From: Jeffrey R. Carter @ 2016-05-28  4:13 UTC (permalink / raw)


On 05/27/2016 05:25 PM, rieachus@comcast.net wrote:
> 
> package Shutdown is
>   task Suspend is
>     entry Stop;
>     entry Wait;
>   end Suspend;
> end Shutdown;
> ...
> package body Shutdown is
> begin
>  task body Suspend is
>  begin
>    accept Stop;
>    loop
>      select
>        accept Wait;
>      or
>        accept Stop; -- in case of multiple calls to Stop.
>      or
>        terminate;
>      end select;
>    end loop;
>  end Shutdown;

Is there any reason for this to be a task? I've always used a protected object:

package Shutdown is
   protected Control is
      procedure Time_To_Die;
      -- Tell the system to shut down

      function Time_To_Die return Boolean;
      -- Returns True if the system is shutting down

      entry Wait;
      -- Blocks until the system is shutting down
   private -- Control
      Shutting_Down : Boolean := False;
   end Control;
end Shutdown;

Procedure Time_To_Die sets Shutting_Down to True, function Time_To_Die returns
Shutting_Down, and Wait is null and has the barrier "when Shutting_Down".
Procedure Time_To_Die and Wait work the same as Stop and Wait. The function is
useful for sporadic tasks that block on an entry waiting for something to do.

-- 
Jeff Carter
"I'm a kike, a yid, a heebie, a hook nose! I'm Kosher,
Mum! I'm a Red Sea pedestrian, and proud of it!"
Monty Python's Life of Brian
77


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-27 22:27           ` Randy Brukardt
@ 2016-05-28  6:49             ` Dmitry A. Kazakov
  0 siblings, 0 replies; 33+ messages in thread
From: Dmitry A. Kazakov @ 2016-05-28  6:49 UTC (permalink / raw)


On 2016-05-28 00:27, Randy Brukardt wrote:

> And no one (I hope!) is putting tasks in drivers in the first place; one
> wants as little as possible in OS drivers, because they necessarily are
> outside of the control of the OS (written without the standards used for the
> OS, etc.)

Right. On the contexts (there are several) of an OS driver proper, one 
simply could not start/switch to a thread. Theoretically one could have 
Ada-scheduled tasks in a driver in a way one does it on bare-boards, but 
that would be useless.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-27 20:27         ` Dmitry A. Kazakov
  2016-05-27 22:27           ` Randy Brukardt
@ 2016-05-28 14:38           ` Shark8
  2016-05-28 15:45             ` Dmitry A. Kazakov
  1 sibling, 1 reply; 33+ messages in thread
From: Shark8 @ 2016-05-28 14:38 UTC (permalink / raw)


On Friday, May 27, 2016 at 2:27:37 PM UTC-6, Dmitry A. Kazakov wrote:
> On 2016-05-27 21:13, Shark8 wrote:
> > On Friday, May 27, 2016 at 1:50:50 AM UTC-6, Dmitry A. Kazakov wrote:
> >> 6. Task entries cannot return unconstrained objects.
> >
> > This can be worked around:
> >    We can add to the previous task the following:
> > 	    Entry Data( Item : out Natural );
> > 	    Entry Data( Item : out String );
> 
> This is a very low-level and very fragile design. Consider ensuring that 
> nothing comes between querying the length and the body that could change 
> the string.

That's actually easy to do with Ada's tasking:
		select
		    accept Done do
			Finished:= True;
		    end Done;
		or
		    accept Get (Data : in String) do
			Internal_Data:= String_Holder.To_Holder( Data );
		    end Get;
		or
		    accept Put do
			Ada.Text_IO.Put_Line( "DATA: "& Internal_Data.Element );
		    end Put;
		or
		    accept Data (Item : out Natural) do
			Item:= Internal_Data.Element'Length;
		    end Data;
		    accept Data (Item : out String) do
			Item:= Internal_Data.Element;
		    end Data;
		    
		end select;

> You start doing that with entry barriers risking running 
> into a deadlock.

As you can see, no barrier needed.
This is one of the nice things about Ada's tasking: you can directly encode a protocol. -- And with package specifications, you can put the task in the private part and declare the public interface in the public portion as [inline]subprograms which, in the body do the proper entry-calls.

package example is
  Function Get_String return String with Inline;
  -- ...
  
private
  Task Text_IO is
  --...
end example;

package body example is
  Function Get_String return String is
    Length : Natural;
  begin
    Text_IO.Data( Length );
    Return Result : String(1..Length) do
      Text_IO.Data( Result );
    End Return;
  end Get_String;
  --...
end example;

> Then consider a possibility that the caller of a 
> get-length request dies prematurely, or that another task steals the 
> string body and so on.

Again, precluded by the construction of the select statement shown above.
Once the task accepts a get-length it *MUST* next accept a get-data, so if multiple threads call the get-data then only one gets processed and that one is the only one that can then be accepted for a get-data because all the rest are waiting on get-length to be serviced.

> Note that the "discussion" started around the claim that design based on 
> semaphore is more low-level than one based on monitor (the task serves 
> as a monitor).
> (There was a reason why protected objects were introduced in Ada 95)

And tasking shows itself to be a higher-level construct; sure, protected objects have their place, but they *AREN'T* capable of directly mapping to a protocol w/o forcing the manual creation of barriers.
 
> P.S. The Ada-way of returning string is this:
> 
>     entry Get_Text (Text : in out String; Last : out Integer);

I would argue that the Ada way would be creating a function that returns the string of the proper length in the public part of the spec and keeping the implementation hidden in the body.


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-28 14:38           ` Shark8
@ 2016-05-28 15:45             ` Dmitry A. Kazakov
  0 siblings, 0 replies; 33+ messages in thread
From: Dmitry A. Kazakov @ 2016-05-28 15:45 UTC (permalink / raw)


On 2016-05-28 16:38, Shark8 wrote:
> On Friday, May 27, 2016 at 2:27:37 PM UTC-6, Dmitry A. Kazakov wrote:
>> On 2016-05-27 21:13, Shark8 wrote:
>>> On Friday, May 27, 2016 at 1:50:50 AM UTC-6, Dmitry A. Kazakov wrote:
>>>> 6. Task entries cannot return unconstrained objects.
>>>
>>> This can be worked around:
>>>    We can add to the previous task the following:
>>> 	    Entry Data( Item : out Natural );
>>> 	    Entry Data( Item : out String );
>>
>> This is a very low-level and very fragile design. Consider ensuring that
>> nothing comes between querying the length and the body that could change
>> the string.
>
> That's actually easy to do with Ada's tasking:
> 		select
> 		    accept Done do
> 			Finished:= True;
> 		    end Done;
> 		or
> 		    accept Get (Data : in String) do
> 			Internal_Data:= String_Holder.To_Holder( Data );
> 		    end Get;
> 		or
> 		    accept Put do
> 			Ada.Text_IO.Put_Line( "DATA: "& Internal_Data.Element );
> 		    end Put;
> 		or
> 		    accept Data (Item : out Natural) do
> 			Item:= Internal_Data.Element'Length;
> 		    end Data;
> 		    accept Data (Item : out String) do
> 			Item:= Internal_Data.Element;
> 		    end Data;

You have a deadlock here when the order of calls is violated, e.g. when 
the caller does not call second Data entry.

>> Then consider a possibility that the caller of a
>> get-length request dies prematurely, or that another task steals the
>> string body and so on.
 >
> Again, precluded by the construction of the select statement shown above.

How do you preclude the caller from not calling the second Data entry?

> Once the task accepts a get-length it *MUST* next accept a get-data,
> so if multiple threads call the get-data then only one gets processed
> and that one is the only one that can then be accepted for a get-data
> because all the rest are waiting on get-length to be serviced.

That happen only if other tasks call Data entries in the exact same 
order. Which is why this is fragile.

The proper design of an Ada task is that *all* declared entries were 
callable in any task state. So if a certain order need to be enforced it 
is better done with barriers than with replicating accept statements and 
nesting selects.

> And tasking shows itself to be a higher-level construct; sure,

Not really. First of all, are you talking about the level of a language 
construct or about the level of a concurrent programming pattern? That is:

1. task type vs protected object type
2. semaphore vs monitor

It is frequently said that Ada concurrent programming primitives are 
higher level. The meaning of this is that they allow implementation of 
other primitives (event, mutex etc) and are integrated into the language 
control flow and type system.

Claiming that tasks are higher level than protected objects or reverse 
is meaningless.

> protected objects have their place, but they *AREN'T* capable of
> directly mapping to a protocol w/o forcing the manual creation of barriers.

As you see it is a quite bad idea to map protocol this way. When dealing 
with protocols, error handing is more important than protocol 
implementation itself. The latter is pretty much trivial. The former is 
what makes software reliable or not.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-05-28  4:13   ` Jeffrey R. Carter
@ 2016-06-01 14:37     ` rieachus
  2016-06-01 19:09       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 33+ messages in thread
From: rieachus @ 2016-06-01 14:37 UTC (permalink / raw)


On Saturday, May 28, 2016 at 12:13:15 AM UTC-4, Jeffrey R. Carter wrote:
>
> Is there any reason for this to be a task? I've always used a protected object:

Shrug.  If it ain't broke don't fix it?  Seriously I started doing this avoiding of terminate options back when they were expensive in some implementations, and before protected objects came along.  Never rethought it since the complex calls were outside the hard real time parts.

Hmmm.  The other difference is you can't call abort in a protected object. My way I can abort any hung tasks when shutting down.


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-06-01 14:37     ` rieachus
@ 2016-06-01 19:09       ` Dmitry A. Kazakov
  2016-06-06  3:33         ` rieachus
  0 siblings, 1 reply; 33+ messages in thread
From: Dmitry A. Kazakov @ 2016-06-01 19:09 UTC (permalink / raw)


On 2016-06-01 16:37, rieachus@comcast.net wrote:

> Hmmm.  The other difference is you can't call abort in a protected object.

Protected object never blocks, thus there is nothing to abort.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-06-01 19:09       ` Dmitry A. Kazakov
@ 2016-06-06  3:33         ` rieachus
  2016-06-06  7:18           ` Dmitry A. Kazakov
  0 siblings, 1 reply; 33+ messages in thread
From: rieachus @ 2016-06-06  3:33 UTC (permalink / raw)


On Wednesday, June 1, 2016 at 3:09:33 PM UTC-4, Dmitry A. Kazakov wrote:
 
> Protected object never blocks, thus there is nothing to abort.

If you look at my code, I am interested in aborting any other task that did not shut down properly before restarting:

         abort Local_Task;

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-06-06  3:33         ` rieachus
@ 2016-06-06  7:18           ` Dmitry A. Kazakov
  2016-06-07 16:53             ` rieachus
  0 siblings, 1 reply; 33+ messages in thread
From: Dmitry A. Kazakov @ 2016-06-06  7:18 UTC (permalink / raw)


On 06/06/2016 05:33, rieachus@comcast.net wrote:
> On Wednesday, June 1, 2016 at 3:09:33 PM UTC-4, Dmitry A. Kazakov wrote:
>
>> Protected object never blocks, thus there is nothing to abort.
>
> If you look at my code, I am interested in aborting any other task that did not shut down properly before restarting:

As questionable aborting task is, if do, that is unrelated to any 
protected objects. They block nothing unless erroneous, e.g. when you 
run an infinite loop within a protected action. If you do you would not 
be able to abort the task stuck in the action, it is abort-deferred.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-06-06  7:18           ` Dmitry A. Kazakov
@ 2016-06-07 16:53             ` rieachus
  2016-06-07 20:21               ` Dmitry A. Kazakov
  2016-06-08  0:19               ` Dennis Lee Bieber
  0 siblings, 2 replies; 33+ messages in thread
From: rieachus @ 2016-06-07 16:53 UTC (permalink / raw)


On Monday, June 6, 2016 at 3:19:20 AM UTC-4, Dmitry A. Kazakov wrote:
 
> As questionable aborting task is, if do, that is unrelated to any 
> protected objects. They block nothing unless erroneous, e.g. when you 
> run an infinite loop within a protected action. If you do you would not 
> be able to abort the task stuck in the action, it is abort-deferred.
 
Sigh!  This is the one instance where aborting a task is not just appropriate, but sometimes necessary.  I have no control over, for example, bit flipping by cosmic rays.  If the deadman timer runs out, there is a serious problem and the airplane (or launch vehicle) is falling out of the sky.  For tasks which close as expected, my code does not abort them.  For tasks that keep running, abort may clear the issue.  If it doesn't?  You have a very expensive pile of wreckage to analyze.  If a task got stuck in a loop but not in an abort deferred area, the abort works, and if the times are set right, you may recover the system.


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-06-07 16:53             ` rieachus
@ 2016-06-07 20:21               ` Dmitry A. Kazakov
  2016-06-08  4:06                 ` rieachus
  2016-06-08  0:19               ` Dennis Lee Bieber
  1 sibling, 1 reply; 33+ messages in thread
From: Dmitry A. Kazakov @ 2016-06-07 20:21 UTC (permalink / raw)


On 2016-06-07 18:53, rieachus@comcast.net wrote:
> On Monday, June 6, 2016 at 3:19:20 AM UTC-4, Dmitry A. Kazakov wrote:
>
>> As questionable aborting task is, if do, that is unrelated to any
>> protected objects. They block nothing unless erroneous, e.g. when you
>> run an infinite loop within a protected action. If you do you would not
>> be able to abort the task stuck in the action, it is abort-deferred.
>
> Sigh! This is the one instance where aborting a task is not just
> appropriate, but sometimes necessary. I have no control over, for
> example, bit flipping by cosmic rays.

Why do you think aborting task would heal that? Why not zeroing a random 
section of memory, sending an SMS, or assigning 666 to the process counter?

> If the deadman timer runs out,
> there is a serious problem and the airplane (or launch vehicle) is
> falling out of the sky.

Yes, but that is not to address by some random actions. You have to 
bring the system to the nearest known safe state. Restarting a task 
might be one, unless the cosmic ray hit the task body's code, external 
objects the task uses, other tasks and hardware it communicates to etc.

Regarding protected objects, an equivalent of aborting task is deleting 
the protected object and creating another instance of. If you believe in 
voodoo magic protected objects are as good as tasks.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-06-07 16:53             ` rieachus
  2016-06-07 20:21               ` Dmitry A. Kazakov
@ 2016-06-08  0:19               ` Dennis Lee Bieber
  1 sibling, 0 replies; 33+ messages in thread
From: Dennis Lee Bieber @ 2016-06-08  0:19 UTC (permalink / raw)


On Tue, 7 Jun 2016 09:53:37 -0700 (PDT), rieachus@comcast.net declaimed the
following:

>On Monday, June 6, 2016 at 3:19:20 AM UTC-4, Dmitry A. Kazakov wrote:
> 
>> As questionable aborting task is, if do, that is unrelated to any 
>> protected objects. They block nothing unless erroneous, e.g. when you 
>> run an infinite loop within a protected action. If you do you would not 
>> be able to abort the task stuck in the action, it is abort-deferred.
> 
>Sigh!  This is the one instance where aborting a task is not just appropriate, but sometimes necessary.  I have no control over, for example, bit flipping by cosmic rays.  If the deadman timer runs out, there is a serious problem and the airplane (or launch vehicle) is falling out of the sky.  For tasks which close as expected, my code does not abort them.  For tasks that keep running, abort may clear the issue.  If it doesn't?  You have a very expensive pile of wreckage to analyze.  If a task got stuck in a loop but not in an abort deferred area, the abort works, and if the times are set right, you may recover the system.

	Based on the systems I've seen at my current employer... If, for
example, a deadman timer does go off... The entire system is restarted --
recreating ALL tasks -- but attempting to save the data state (a cold start
does destructive RAM tests, a warm start skips those).

	No attempt is made to abort pieces of the system or restart them. All
tasks are created during the initialization phase, before the system is
"active".
-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
    wlfraed@ix.netcom.com    HTTP://wlfraed.home.netcom.com/

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-06-07 20:21               ` Dmitry A. Kazakov
@ 2016-06-08  4:06                 ` rieachus
  2016-06-08  7:29                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 33+ messages in thread
From: rieachus @ 2016-06-08  4:06 UTC (permalink / raw)


On Tuesday, June 7, 2016 at 4:21:15 PM UTC-4, Dmitry A. Kazakov wrote:
> On 2016-06-07 18:53, rieachus@comcast.net wrote:
> > On Monday, June 6, 2016 at 3:19:20 AM UTC-4, Dmitry A. Kazakov wrote:
> >
> >> As questionable aborting task is, if do, that is unrelated to any
> >> protected objects. They block nothing unless erroneous, e.g. when you
> >> run an infinite loop within a protected action. If you do you would not
> >> be able to abort the task stuck in the action, it is abort-deferred.
> >
> > Sigh! This is the one instance where aborting a task is not just
> > appropriate, but sometimes necessary. I have no control over, for
> > example, bit flipping by cosmic rays.
> 
> Why do you think aborting task would heal that? Why not zeroing a random 
> section of memory, sending an SMS, or assigning 666 to the process counter?
> 
> > If the deadman timer runs out,
> > there is a serious problem and the airplane (or launch vehicle) is
> > falling out of the sky.
> 
> Yes, but that is not to address by some random actions. You have to 
> bring the system to the nearest known safe state. Restarting a task 
> might be one, unless the cosmic ray hit the task body's code, external 
> objects the task uses, other tasks and hardware it communicates to etc.

Code is in Flash, with caches that get flushed on a restart. the software consists of a number of tasks all dispatched by a 50 Hz (or some such) clock.  In other words, the tasking (source) code is a few dozen lines, and the select statement is about the only tasking operation used in the operating code, absent extreme events.

It is fairly common for flipped bits to result in a task which is in an indefinite loop, and no lower priority tasks get to run.  The code example I gave tries stopping and restarting every task, and any that don't stop get aborted and then restarted.  May not be perfect, but about the best you can do with cosmic rays around. (The operating tasks where possible detect a restart and don't depend on any data they own in DRAM memory.)

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-06-08  4:06                 ` rieachus
@ 2016-06-08  7:29                   ` Dmitry A. Kazakov
  2016-06-08 12:56                     ` rieachus
  0 siblings, 1 reply; 33+ messages in thread
From: Dmitry A. Kazakov @ 2016-06-08  7:29 UTC (permalink / raw)


On 08/06/2016 06:06, rieachus@comcast.net wrote:
> On Tuesday, June 7, 2016 at 4:21:15 PM UTC-4, Dmitry A. Kazakov wrote:
>> On 2016-06-07 18:53, rieachus@comcast.net wrote:
>>> On Monday, June 6, 2016 at 3:19:20 AM UTC-4, Dmitry A. Kazakov wrote:
>>>
>>>> As questionable aborting task is, if do, that is unrelated to any
>>>> protected objects. They block nothing unless erroneous, e.g. when you
>>>> run an infinite loop within a protected action. If you do you would not
>>>> be able to abort the task stuck in the action, it is abort-deferred.
>>>
>>> Sigh! This is the one instance where aborting a task is not just
>>> appropriate, but sometimes necessary. I have no control over, for
>>> example, bit flipping by cosmic rays.
>>
>> Why do you think aborting task would heal that? Why not zeroing a random
>> section of memory, sending an SMS, or assigning 666 to the process counter?
>>
>>> If the deadman timer runs out,
>>> there is a serious problem and the airplane (or launch vehicle) is
>>> falling out of the sky.
>>
>> Yes, but that is not to address by some random actions. You have to
>> bring the system to the nearest known safe state. Restarting a task
>> might be one, unless the cosmic ray hit the task body's code, external
>> objects the task uses, other tasks and hardware it communicates to etc.
>
> Code is in Flash, with caches that get flushed on a restart.

But the system's state is not in there, e.g. the memory pools, external 
objects, states of other tasks, states of external devices. In order to 
be able to repair the system by restarting one task, there must be some 
very strong conditions to satisfy, which are not except for very rare 
and very special cases.

So if a watchdog fires, the nearest safe state is restart of whole 
partition.

> It is fairly common for flipped bits to result in a task which is in
> an indefinite loop,

That is the visible effect, the point is if restarting a task heals a 
symptom or the illness.

P.S. It would be nice if Ada had, as well, a non-cooperative model of 
private, protected and task. That is, private parts inacessible without 
memory mapping only to occur through publicly visible calls. Such tasks 
and objects could be resurrected without partition restart. They would 
also be great for distributed systems done high-level instead of 
low-level Annex E. Unfortunately there is no demand...

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Advice, tasking and hardware
  2016-06-08  7:29                   ` Dmitry A. Kazakov
@ 2016-06-08 12:56                     ` rieachus
  0 siblings, 0 replies; 33+ messages in thread
From: rieachus @ 2016-06-08 12:56 UTC (permalink / raw)


On Wednesday, June 8, 2016 at 3:30:07 AM UTC-4, Dmitry A. Kazakov wrote:
  
> That is the visible effect, the point is if restarting a task heals a 
> symptom or the illness.
> 
> P.S. It would be nice if Ada had, as well, a non-cooperative model of 
> private, protected and task. That is, private parts inacessible without 
> memory mapping only to occur through publicly visible calls. Such tasks 
> and objects could be resurrected without partition restart. They would 
> also be great for distributed systems done high-level instead of 
> low-level Annex E. Unfortunately there is no demand...

Um.  Hard real-time systems are hard, and it is harder still to recover from (transient) hardware errors.  However, there are tools, and SPARK helps a lot.  In the systems I worked on, each priority level corresponded to a thread, and was fired off every 20 ms.  There was a time requirement on restarting any task from scratch that basically resulted in a (small) collection of state variables, and the large swaths of state data like radar tracks would be discarded by hardware transient recovery. 

Oh, all physical memory allocations had to be done before the system was started.  You could, and often did have a per task memory pool, and restart just changed the allocated amount to zero.  Of course, any package which contained state had to be task specific.  The tasks that updated the HUD was relatively low priority, and some cockpit displays lower still. So telling the pilot to try cycling the power to the computer system wasn't a solution.  Hmm. I remember some older systems A6A DIANE? Where the watchdog timer was connected to a cockpit light.  That system though, did nav, radar and weapons, but was not involved in flight control.


^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2016-06-08 12:56 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-25 21:24 Advice, tasking and hardware patrick
2016-05-26  1:09 ` Jeffrey R. Carter
2016-05-26  8:13   ` Simon Wright
2016-05-26  7:26 ` Dmitry A. Kazakov
2016-05-26 16:41   ` patrick
2016-05-26 17:56     ` Dmitry A. Kazakov
2016-05-26 20:35     ` Jeffrey R. Carter
2016-05-26 19:35   ` Jeffrey R. Carter
2016-05-26 20:51     ` patrick
2016-05-27  7:50     ` Dmitry A. Kazakov
2016-05-27 18:00       ` Simon Wright
2016-05-27 19:06       ` Jeffrey R. Carter
2016-05-27 22:05         ` Randy Brukardt
2016-05-27 23:09           ` Jeffrey R. Carter
2016-05-27 19:13       ` Shark8
2016-05-27 20:27         ` Dmitry A. Kazakov
2016-05-27 22:27           ` Randy Brukardt
2016-05-28  6:49             ` Dmitry A. Kazakov
2016-05-28 14:38           ` Shark8
2016-05-28 15:45             ` Dmitry A. Kazakov
2016-05-28  0:25 ` rieachus
2016-05-28  1:57   ` patrick
2016-05-28  4:13   ` Jeffrey R. Carter
2016-06-01 14:37     ` rieachus
2016-06-01 19:09       ` Dmitry A. Kazakov
2016-06-06  3:33         ` rieachus
2016-06-06  7:18           ` Dmitry A. Kazakov
2016-06-07 16:53             ` rieachus
2016-06-07 20:21               ` Dmitry A. Kazakov
2016-06-08  4:06                 ` rieachus
2016-06-08  7:29                   ` Dmitry A. Kazakov
2016-06-08 12:56                     ` rieachus
2016-06-08  0:19               ` Dennis Lee Bieber

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox