comp.lang.ada
 help / color / mirror / Atom feed
* Tasking problem (delay)
@ 2007-08-15 17:04 Gerd
  2007-08-15 17:34 ` Georg Bauhaus
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Gerd @ 2007-08-15 17:04 UTC (permalink / raw)


Hi all,

I have a problem with some code. Maybe I misunderstood the LRM. Can
someone explain and maybe show a solution?

First I have to say, I work with GNAT on Windows, but what I try is to
simulate the behavior of an embedded processor (which is currently
programmed in C).

I have three tasks (much reduced from real  world task), one for
startup, one for receiving data and one for processing it:

WD_Delay: Duaration := 1000.0; -- so do not trigger on start

task startup is
end startup;

task receiver is
end receiver;

task worker is
  entry Data(...);
end worker;

task body startup is
begin
  ...
 WD_Delay := 1.0;
 ...
end startup;

task body receiver is
begin
   loop
     ... -- receive data
    worker.Data (...);
  end loop;
end receiver;

task body worker is
begin
  loop
    select
       accept Data (...)
   or
     delay WD_Timeout;
     trigger_WD;
    end select;
  end loop;
end worker;


So what I expected was, that after the init-task set the new delay,
the worker would trigger the watchdog in short intervalls. But it
seems, that the delay still waits for the initial delay time.
Whats wrong?

Thanks,
Gerd




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

* Re: Tasking problem (delay)
  2007-08-15 17:04 Tasking problem (delay) Gerd
@ 2007-08-15 17:34 ` Georg Bauhaus
  2007-08-15 18:32 ` Jeffrey R. Carter
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: Georg Bauhaus @ 2007-08-15 17:34 UTC (permalink / raw)


On Wed, 2007-08-15 at 10:04 -0700, Gerd wrote:

> task body worker is
> begin
>   loop
>     select
>        accept Data (...)
>    or
>      delay WD_Timeout;
             WD_Delay; ? 
>      trigger_WD;
>     end select;
>   end loop;
> end worker;





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

* Re: Tasking problem (delay)
  2007-08-15 17:04 Tasking problem (delay) Gerd
  2007-08-15 17:34 ` Georg Bauhaus
@ 2007-08-15 18:32 ` Jeffrey R. Carter
  2007-08-19  9:50   ` Gerd
  2007-08-16  5:16 ` anon
  2007-08-16  5:17 ` AW: " Grein, Christoph (Fa. ESG)
  3 siblings, 1 reply; 7+ messages in thread
From: Jeffrey R. Carter @ 2007-08-15 18:32 UTC (permalink / raw)


Gerd wrote:
> 
> WD_Delay: Duaration := 1000.0; -- so do not trigger on start

Assuming this is "Duration" ...

> task body startup is
> begin
>   ...
>  WD_Delay := 1.0;
>  ...
> end startup;
> 
> task body worker is
> begin
>   loop
>     select
>        accept Data (...)
>    or
>      delay WD_Timeout;

... and this is "WD_Delay"

>      trigger_WD;
>     end select;
>   end loop;
> end worker;

The expression in the delay statement (in this case "WD_Delay") is 
evaluated once upon reaching the select statement. So this will wait for 
a call to Data, or for the value of WD_Delay at the time the select 
statement was reached, whichever comes 1st.

Using unprotected shared variables is not a good idea anyway. I'd 
suggest something more like:

task Worker is
    entry Startup_Complete;
    entry Data (...);
end Worker;

task body Worker is
    WD_Delay : constant := 1.0;
begin -- Worker
    select
       accept Startup_Complete;
    or
       terminate;
    end select;

    Forever : loop
       select
          accept Data ...
       or
          delay WD_Delay;

          Trigger_WD;
       end select;
    end loop Forever;
end Worker;

If Worker needs to be able to accept data before startup is complete, 
this would become

task body Worker is
    WD_Delay : Duration := 1_000.0;
begin -- Worker
    Forever : loop
       select
          accept Data ...
       or
          accept Startup_Complete;

          WD_Delay := 1.0;
       or
          delay WD_Delay;

          Trigger_WD;
       end select;
    end loop Forever;
end Worker;

-- 
Jeff Carter
"Clear? Why, a 4-yr-old child could understand this
report. Run out and find me a 4-yr-old child. I can't
make head or tail out of it."
Duck Soup
94



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

* Re: Tasking problem (delay)
  2007-08-15 17:04 Tasking problem (delay) Gerd
  2007-08-15 17:34 ` Georg Bauhaus
  2007-08-15 18:32 ` Jeffrey R. Carter
@ 2007-08-16  5:16 ` anon
  2007-08-16  5:17 ` AW: " Grein, Christoph (Fa. ESG)
  3 siblings, 0 replies; 7+ messages in thread
From: anon @ 2007-08-16  5:16 UTC (permalink / raw)


-- You can copy and paste to a file: 'test5.adb'
--
-- GNAT executable program follows after a few comments: 
--

--
-- For another example try the 
--
--            'Dining Philosophers - Ada 95 edition'
--
--            which starts with the file 'diners.adb'
--            and includes a set of 5 extra packages.            
--
--            The files should be in the example directory 
--            that is include with GNAT. If not look on the 
--            net.
-- 
--

--
-- As for Style. the LRM allows for style but it not require 
-- by LRM. With that said you may have unprotected global 
-- variables it is your choice! Plus it allow you to create 
-- your own programming style.
-- 
--
-- Also useage of an accept statement to shutdown is shown to be
-- abnormal or premature RM 9.7.1 (24). While the terminate 
-- statement is normal.  But to shutdown a task which has 
-- terminate statement within a loop, external task must use 
-- the ABORT statement. Which is defined as valid RM 9.3 (18). 
--


with Ada.Text_IO ;
use  Ada.Text_IO ;

procedure Test5 is


  -- ------------------------------- --
  -- Declaration of Global Variables --
  -- ------------------------------- --

  Timeout_Constant : Duration ;  -- Used as a constant once task 
                                 -- are active


  -- -------------------- --
  -- Declaration of Tasks --
  -- -------------------- --

  -- 
  -- I remove startup task because since it is a set of code that 
  -- is normally execute once, which normally it does not need 
  -- it own task.  It is better to insert the code either in a 
  -- master procedure or a master task which in your case, that 
  -- would be the 'Worker' task
  --

    task receiver is
      entry Start ;
      entry Shut_Down ;   -- abnormal shutdown entry point
    end receiver ;

    task worker is
      --
      -- Inserting T for testing purposes only
      --
      entry Data ( T : in Boolean ) ;
    end worker;


  -- ---------------- --
  -- Bodies for Tasks --
  -- ---------------- --


task body receiver is

    Z : Boolean := False ; -- only use for testing purposes in call

  begin

    -- Insert Receiver Initialization Code
    --
    -- Gives time for system to activate other tasks
    -- and to execute initialization or startup code
    --

    Put_Line ( "Receiver: Initialization code" ) ;
    delay 1.0 ; -- inserted for testing only 

    -- Main Receiver Task Code

    loop
      select 
        accept Start do
            --     ... -- receive data

                        -- value insures watch dog will be executed
        for index in 0..3 loop
            Put_Line ( "Receiver: Data transfer to worker" ) ;
            worker.Data ( Z ) ;

            Put_Line ( "Receiver: Delay 1.0" ) ;
            delay 1.0 ; -- inserted for testing only, 
          end loop ;
        end start ;
      or
        --
        -- From RM 9.7.1 (24) not acceptable termination routine
        --
        accept shut_down ;   
          Put_Line ( "Receiver: Abnormal ShutDown" ) ;
          exit ; 
      or
        --
        -- Normal task shutdown routine
        -- terminate is use by abort statement to stop code
        --
        terminate ;
      end select ;
    end loop ;
    --
    -- Code define here will never be execute if external abort 
    -- statement is use But if the Accept shut_down statement with a 
    -- exit statement is execute then this code will be executed
    --
    Put_Line ( "Receiver: Extra Abnormal ShutDown Code" ) ;
  end receiver ;



  task body worker is
      --
      -- Watch Dog Timeout variables
      --
      Timeout_Counter : Duration := 10.0 ; 

      Time_Slice      : Duration := 0.1 ; -- smallest delay used in 
                                          -- this example


      Q : Boolean ; -- used for testing 


    begin
      loop
        select
          accept Data ( T : in Boolean ) do

              --
              -- Receive and process data
              --
              Put_Line ( "WORKER: Processing Data"  ) ;
              Q := T ;
              --
              -- reset timeout counter
              --
              Put_Line ( "WORKER: Reset Watch Dog counter"  ) ;
              Timeout_Counter  := Timeout_Constant ;
            end Data ;
            
        or
        --  --  --  -- --  --  --
        --  Watch Dog Routine  --
        --  --  --  -- --  --  --

            --
            -- wait for timed delay
            --
            delay Time_Slice ;
            Put_Line ( "WORKER: Has Time Slice"  ) ;
            Timeout_Counter := Timeout_Counter - 0.1 ;
            --
            -- Check for time_out
            --
            if ( Timeout_Counter < 0.1 ) then 
              exit ;
            end if ;
        end select ;
      end loop ; 
      --
      -- Without the abort statement the receive task will 
      -- hang the process.
      --
      Put_Line ( "WORKER: shutdown Receiver Task"  ) ;
--
--      receiver.shut_down ;  -- abnormal shutdown
--
      abort receiver ; -- Normal Task Shutdown 

      Put_Line ( "WORKER: shutdown self: (Worker task)"  ) ;
    end worker ;


begin
  --
  -- Insert startup code HERE! 
  --
  Put_Line ( "TEST5: Startup code"  ) ;
  Timeout_Constant := 2.0 ;
  --
  -- Start receiver task 
  --
  Put_Line ( "TEST5: Activate Receiver Task "  ) ;
  Receiver.Start ;


  Put_Line ( "TEST5: Waiting for Watch Dog Timeout"  ) ;
  --
  -- Wait for the death of the receiver task 
  --
  while Receiver'callable loop
    delay 1.5 ;
  end loop ;


  Put_Line ( "TEST5: Delay before shutdown"  ) ;
  Delay 1.0 ; -- Give system some time before killing this task
  Put_Line ( "TEST5: ShutDown"  ) ;

end test5 ;











In <1187197490.377548.41000@b79g2000hse.googlegroups.com>,  Gerd <GerdM.O@t-online.de> writes:
>Hi all,
>
>I have a problem with some code. Maybe I misunderstood the LRM. Can
>someone explain and maybe show a solution?
>
>First I have to say, I work with GNAT on Windows, but what I try is to
>simulate the behavior of an embedded processor (which is currently
>programmed in C).
>
>I have three tasks (much reduced from real  world task), one for
>startup, one for receiving data and one for processing it:
>
>WD_Delay: Duaration := 1000.0; -- so do not trigger on start
>
>task startup is
>end startup;
>
>task receiver is
>end receiver;
>
>task worker is
>  entry Data(...);
>end worker;
>
>task body startup is
>begin
>  ...
> WD_Delay := 1.0;
> ...
>end startup;
>
>task body receiver is
>begin
>   loop
>     ... -- receive data
>    worker.Data (...);
>  end loop;
>end receiver;
>
>task body worker is
>begin
>  loop
>    select
>       accept Data (...)
>   or
>     delay WD_Timeout;
>     trigger_WD;
>    end select;
>  end loop;
>end worker;
>
>
>So what I expected was, that after the init-task set the new delay,
>the worker would trigger the watchdog in short intervalls. But it
>seems, that the delay still waits for the initial delay time.
>Whats wrong?
>
>Thanks,
>Gerd
>




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

* AW: Tasking problem (delay)
  2007-08-15 17:04 Tasking problem (delay) Gerd
                   ` (2 preceding siblings ...)
  2007-08-16  5:16 ` anon
@ 2007-08-16  5:17 ` Grein, Christoph (Fa. ESG)
  3 siblings, 0 replies; 7+ messages in thread
From: Grein, Christoph (Fa. ESG) @ 2007-08-16  5:17 UTC (permalink / raw)
  To: comp.lang.ada

WD_Delay: Duaration := 1000.0; -- so do not trigger on start

Since this is not a "shared variable", a task may keep a copy in its
local stack. Ada 83 had a pragma Shared to prevent this. Current Ada has
the pragmas Atomic and Volatile.

Yet I recomment Jeffrey's solution to using volatile globals.


Eurocopter Deutschland GmbH
Sitz der Gesellschaft/Registered Office: Donauwoerth
Registergericht/Registration Court: Amtsgericht Augsburg HRB 16508
Vorsitzender des Aufsichtsrates/Chairman of the Supervisory Board: Dr. Lutz Bertling
Geschaeftsfuehrung/Board of Management:
Dr. Wolfgang Schoder, Vorsitzender/CEO; Friedrich-Wilhelm Hormel; Ralf Barnscheidt

CONFIDENTIALITY NOTICE 

This communication and the information it contains is intended for the addressee(s) named above and for no other persons or organizations. It is confidential and may be legally privileged and protected by law. The unauthorized use, copying or disclosure of this communication or any part of it is prohibited and may be unlawful. 
If you have received this communication in error, kindly notify us by return e-mail and discard and/or delete the communication. Thank you very much. 
It is possible for e-mails to be intercepted or affected by viruses. Whilst we maintain virus checks on our e-mails, we accept no liability for viruses or other material which might be introduced with this message. 




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

* Re: Tasking problem (delay)
  2007-08-15 18:32 ` Jeffrey R. Carter
@ 2007-08-19  9:50   ` Gerd
  2007-08-19 18:26     ` Jeffrey R. Carter
  0 siblings, 1 reply; 7+ messages in thread
From: Gerd @ 2007-08-19  9:50 UTC (permalink / raw)


On 15 Aug., 20:32, "Jeffrey R. Carter"
<spam.jrcarter....@acm.nospam.org> wrote:
>
> The expression in the delay statement (in this case "WD_Delay") is
> evaluated once upon reaching the select statement. So this will wait for
> a call to Data, or for the value of WD_Delay at the time the select
> statement was reached, whichever comes 1st.
>
> Using unprotected shared variables is not a good idea anyway. I'd
> suggest something more like:

Thanks, you've pointed me into the right direction. I changed my code
such, that the delaytime is no longer a global variable (which in fact
was not good coding).

task worker is
  entry Data(...);
  entry set_delay_time(dt : Duration); -- inserted
end worker;


task body startup is
begin
  ...
-- WD_Delay := 1.0;
  worker.set_delay_time (1.0);
 ...
end startup;


task body worker is
  WD_Timeout : Duration := 1000.0;
begin
  loop
    select
       accept Data (...);
   or
      accept set_selay_time (dt : Duration)
      do
        WD_Timeout := dt;
      end;
   or
     delay WD_Timeout;
     trigger_WD;
    end select;
  end loop;
end worker;


Would this be a good solution for my problem or are there any other
traps?


Gerd




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

* Re: Tasking problem (delay)
  2007-08-19  9:50   ` Gerd
@ 2007-08-19 18:26     ` Jeffrey R. Carter
  0 siblings, 0 replies; 7+ messages in thread
From: Jeffrey R. Carter @ 2007-08-19 18:26 UTC (permalink / raw)


Gerd wrote:
> 
> Would this be a good solution for my problem or are there any other
> traps?

I don't see any traps. This design for Worker implies that you need to 
change the WD timeout value repeatedly, to arbitrary values, but what 
you've presented indicates that it only needs to be changed once to a 
fixed value. If that's the case, it would probably be better for the 
design to reflect it, encapsulating all information about the timeout 
value in the Worker task.

However, this design may have the Worker doing too much. In addition to 
the work its supposed to do, it's also doing the work of the watchdog. 
It might be better to separate them:

protected WD_Station is
    procedure Startup_Completed;

    procedure Check_In;
    -- Called periodically by monitored task.

    entry Wait_For_Startup;

    entry Wait;
    -- Called by WD task to wait for the monitored task to check in.
private -- WD_Station
    ...
end WD_Station;

The startup task calls WD_Station.Startup_Complete at the appropriate 
time. The worker task would look like

begin -- Worker
    Forever : loop
       select
          accept Data ...;
          WD_Station.Check_In;
       or
          terminate;
       end select;
    end loop Forever;
end Worker;

There would also be a task WD_Timer:

task body WD_Timer is
begin -- WD_Timer
    WD_Station.Wait_For_Startup;

    Forever : loop
       select
          WD_Station.Wait;
       or
          delay 1.0;
          -- Watchdog processing here.
       end select;
    end loop Forever;
end WD_Timer;

You would need a way for WD_Station to inform WD_Timer that it should 
end, if that is a possibility.

-- 
Jeff Carter
"You empty-headed animal-food-trough wiper."
Monty Python & the Holy Grail
04



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

end of thread, other threads:[~2007-08-19 18:26 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-08-15 17:04 Tasking problem (delay) Gerd
2007-08-15 17:34 ` Georg Bauhaus
2007-08-15 18:32 ` Jeffrey R. Carter
2007-08-19  9:50   ` Gerd
2007-08-19 18:26     ` Jeffrey R. Carter
2007-08-16  5:16 ` anon
2007-08-16  5:17 ` AW: " Grein, Christoph (Fa. ESG)

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