Ada. How to set task priorities at run-time? - task

First of all lets get this out of the way. I am a beginner in Ada, and the reason that I want to be able to do this is because I would like to program a Priority Inversion.
I have included,
with Ada.Task_Identification;
I have also made a task type:
task type tasktype1 is
pragma PRIORITY (20);
entry gotosleep;
end tasktype1;
and I have declared a task:
High : tasktype1;
Now I would like to change the priority of the task "High" to some other priority.
I have tried writing:
High.Prority(1);
where I would put it in the main's begin block.
and declared a Task_ID.
A : Task_Id;
then tried to fetch the current task with A := Current_Task;
and then put Priority(3,A); in the mains begin instead.
Here is all of my code for reference:
with Ada.Text_IO, Ada.Integer_Text_IO, System, Ada.Task_Identification;
use Ada.Text_IO, Ada.Integer_Text_IO;
procedure Main is
task type tasktype1 is
pragma PRIORITY (20);
entry gotosleep;
end tasktype1;
pragma PRIORITY (3); -- This is the priority for the main program
High : tasktype1;
A : Task_Id;
task body tasktype1 is
begin
accept gotosleep do
Put("Cow is not sleeping");
end gotosleep;
end tasktype1;
begin
A := Current_Task;
Priority(3, A);
Put_Line("This is an example of use of a task type");
Put_Line("This is an example of use of a task type");
Put_Line("This is an example of use of a task type");
Put_Line("This is an example of use of a task type");
Put_Line("This is an example of use of a task type");
end Main;

See: http://www.adaic.org/resources/add_content/standards/05rm/html/RM-D-5-1.html
TLDR; (if you wish to set/get the priority for the current task)
"with" the package to your Ada source:
with Ada.Dynamic_Priorities;
Call the Set_Priority procedure
Ada.Dynamic_Priorities.Set_Priority(1);
If you wish to find out the current priority, you can call
Ada.Dynamic_Priorities.Get_Priority;

First, concerning task priority, you must check your OS capability.
For example, on Linux or Solaris, you can use priority only as root user. Else, the OS give the same priority for each task, regardless of what you set in the code.
On Windows, I did not check what is the tasking policy available, but by default I would say that all tasks have the same priority.
Once it is done, the solution below should work fine.

Related

Can array of registers can be used in tasks in verilog?

i am trying to implement a task for a Ripple carry adder in Verilog HDL. There is an error showing:"root scope declaration is not allowed in Verilog 95/2K mode" at line no-1
task rca; `<---line 1`
input [15:0]in1,in2;
output reg [15:0]out2;
reg [15:0]c;
integer i;
begin
c=16'b0;
for(i=0;i<16;i=i+1)
begin
out2[i]=in1[i]^in2[i]^c[i];
c[i+1]=(in1[i]&in2[i])|(in2[i]&c[i])|(c[i]&in1[0]);
end
end
endtask
You have to declare your task inside a module. I suggest to create file with .vh extension (Verilog Header), place you task inside this file and include your task by `include directive. For example:
module example_module(
// list of ports
);
`include "tasks.vh"
// Use your task here
endmodule

What is wrong with my gen_statem fsm implementation?

I am implementing a gen_fsm using the gen_statem module and when i am trying to check its state as a handle_event_function i get the following error:
> ** exception error: {function_clause,
> {gen_statem,call,[{ok,<0.139.0>},state,0]}}
> in function gen:do_for_proc/2
> called as gen:do_for_proc({ok,<0.139.0>},#Fun<gen.0.9801092>)
> in call from gen_statem:'-call_clean/4-fun-0-'/5 (gen_statem.erl, line 637) 25> c("C:/Erlang/Genserv/fsm.erl").
Below is my code which is separated into :
-mandatory methods for the fsm to work
-api that the client can use (state change,get the state,start)
- generic handlers for when client demands something related to state
-state implementations
Module
-module(fsm).
-record(state,{
current="None",
intvCount=0,
jobCount=0
}).
-export([init/1,terminate/3,callback_mode/0,code_change/4]).
-export([state/1,start/0,hire/2,fire/2,interview/2]).
-export([sitting_home/3,interviewing/3,working/3]).
-behaviour(gen_statem).
%API
start()->
gen_statem:start_link(?MODULE,[],[]).
state(PID)->
gen_statem:call(PID,state,0).
hire(PID,Company)->
gen_statem:call(PID,{hire,Company},0).
fire(PID,Company)->
gen_statem:call(PID,{fire,Company},0).
interview(PID,Company)->
gen_state:call(PID,{intv,Company},0).
%mandatory
code_change(V,State,Data,Extra)->{ok,State,Data}.
callback_mode() ->
[state_functions,handle_event_function].
init([])->
{ok,sitting_home,#state{current="None",jobCount=0,intvCount=0}}.
terminate(Reasom,State,Data)->
void.
% Generic handlers
handle_event({call,From},state,State)->
{keep_state,State,[{reply,From,State}]};
handle_event(_,_,State)->
{keep_state,State}.
% State implementations
sitting_home({call,From},{intv,Company},State=#state{intvCount=C})->
{next_state,interviewing,State#state{intvCount=C+1},[{reply,From,"Interviewing by:"++Company}]};
sitting_home(EventType,Event,State)->
handle_event(EventType,Event,State).
interviewing({call,From},{rejected,Company},State)->
{next_state,sitting_home,State,[{reply,From,"rejected by:"++Company}]};
interviewing({call,From},{accepted,Company},State=#state{jobCount=J})->
{next_state,
working,
State#state{jobCount=J+1,current=Company},
[{reply,From,"accepted offer from:"++Company}]
};
interviewing(EventType,Event,State)->
handle_event(EventType,Event,State).
working({call,From},{fire,Company},State=#state{current=C})->
{next_state,working,State#state{current="None"},[{reply,From,"Got fired from"++Company}]};
working(EventType,Event,State)->
handle_event(EventType,Event,State).
Usage
FSM_PID=fsm:start().
fsm:state(PID). //crashes when demanding state
fsm:hire(PID,"Some Company").
fsm:start() returns the tuple {ok,Pid}. You cannot use directly the return of the function in your next call. Instead you must do something like:
{ok,P} = fsm:start().
fsm:state(P).
Then you will experience other troubles, the first one is that you specify a timeout of 0, so you will get a timeout error. You will have to change this, and continue debugging :o)
[edit]
You don't need to specify the Pid, it is done in background by the gen_statem code, the gen_statem:call function is executed in the caller context so it still has access to the caller Pid.
In fact it is a little more complex, depending if you specify a timeout or not, the gen_statem:call/3 will spawn a process to call the gen:call/4 function or will directly call it, thus the Pid sent to the state machine will be either the spawned function's one or the caller's one.
The gen:call/4 also add a Reference in the message to the state machine to "sign" the answer and guaranty that an incoming message from any other part of the application will not be interpreted as the answer.
This is a general pattern in erlang (and programming) to hide as much as possible the system mechanism in interface function. Just as you do in the function state/1

Ada - How to implement an asynchronous task that allows the main thread to poll it?

I want to create a task that reads from a file for a few minutes while the main thread does other things. But I'd like the main thread to be able to poll the task to see if it is "Busy" or not (a Boolean value) without blocking the main thread.
I have a naive attempt here, which does work but it leaves the Busy flag completely exposed to be toggled at will by the main thread (this is not safe)...
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
task type Non_Blocking_Reader_Task (Busy : access Boolean) is
entry Read (Destination : in Natural);
end Non_Blocking_Reader_Task;
task body Non_Blocking_Reader_Task is
begin
loop
select
when not Busy.all =>
accept Read (Destination : in Natural) do
Busy.all := True;
end Read;
for i in 1 .. 50 loop
Put ("."); -- pretend to do something useful
delay 0.1; -- while wasting time
end loop;
Busy.all := False;
end select;
end loop;
end Non_Blocking_Reader_Task;
Reader_Busy_Volatile : aliased Boolean;
Reader : Non_Blocking_Reader_Task (Reader_Busy_Volatile'Access);
begin
Put_Line (Reader_Busy_Volatile'Image);
Reader.Read (123);
for i in 1 .. 15 loop
Put_Line (Reader_Busy_Volatile'Image);
delay 0.5;
end loop;
abort Reader;
end Main;
My second idea was to create a protected type and hide the flag and the task inside it, but this is not permitted by the language.
Question
How can I create a protected "task is busy" flag that can is read-only from the main thread and read/write from the task (which does not cause the main thread to block)?
Edit:
The solution!
My revised (working) solution based on the stirling advice of #flyx :)
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
task type Reader_Task is
entry Read (Destination : in Natural);
entry Join;
entry Ready;
end Reader_Task;
task body Reader_Task is
Dest : Natural;
begin
loop
select
accept Read (Destination : in Natural) do
Dest := Destination;
end Read;
-- we only get here after a Read has been received.
for i in 1 .. 5 loop
Put ("."); -- pretend to do something useful
delay 1.0; -- while wasting time
end loop;
or
accept Join;
or
accept Ready;
or
terminate;
end select;
end loop;
end Reader_Task;
Reader : Reader_Task;
begin
-- first call will not block.
Reader.Read (123);
Put_Line ("MAIN: Reading in progress on second thread");
for i in 1 .. 12 loop
select
-- NON-BLOCKING CALL!
Reader.Ready; -- test if task is busy
Put_Line ("MAIN: NON-BLOCKING CALL SUCCEEDED -- TASK IS NOT BUSY");
else
Put_Line ("MAIN: NON-BLOCKING CALL FAILED -- TASK IS BUSY");
end select;
delay 1.0;
end loop;
Put_Line ("Main: Waiting for Reader (BLOCKING CALL)...");
Reader.Join;
Put_Line ("Main: all finished!");
end Main;
I've added two more entries to the task: Join and Ready which are basically the same but for the names. Join reminds me to do a blocking call to it, and Ready indicates that a non-blocking call is suitable for testing task availability. I've done this because there are times when I want to know if the previous run of Read() has finished without firing off a new one. This lets me do this neatly and all without any discrete flags at all! Awesome.
In Ada, the caller decides whether an entry call is blocking or not. You should not try and implement code for checking this inside the task.
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
task type Reader_Task is
entry Read (Destination : in Natural);
end Reader_Task;
task body Reader_Task is
begin
loop
select
accept Read (Destination : in Natural) do
null;
-- store Destination (?)
end Read;
or
-- allow task to be terminated while waiting
terminate;
end select;
-- we only get here after a Read has been received.
for i in 1 .. 50 loop
Put ("."); -- pretend to do something useful
delay 0.1; -- while wasting time
end loop;
end loop;
end Reader_Task;
Reader : Reader_Task;
begin
-- first call will not block.
Reader.Read (123);
for i in 1 .. 15 loop
-- check whether Read can be called immediately and if yes,
-- call it.
select
Reader.Read (456);
else
-- Read is not available, do something else.
null;
end select;
delay 0.5;
end loop;
-- don't call abort; let Reader finish its current task.
-- Reader will be terminated once it waits on the terminate alternative
-- since the parent is finished.
end Main;
The select … else … end select structure is Ada's way of doing a non-blocking call. You don't use a flag for signalling that the task is ready to receive an entry call because potentially, this state could change between the query of the flag and the actual call of the entry. select has been designed to avoid this problem.

How can I use Firebird's Execute Block with Delphi TSQLQuery?

Using dbExpress TSQLQuery, I can't execute a query with execute block command because that command requires ? notation for parameters, and Delphi uses : for parameters, then, if in the body of that block creates variables and uses them as
select data from table where .... into :var;
that ":var" is interpreted as a parameter by TSQLQuery.
Which is the way for executing an execute block statement with Delphi?
If I write:
execute block(param1 char(1)=:param1)
I can load a value for :param1 from Delphi, but when I execute it with Query.Open or Query.ExecSQL an error returns indicating absence of parameter so ? because in Firebird execute block is written:
execute block(param1 char(1)=?param1)
Is there any way to resolve this with TSQLQuery?
first you can disable the TSQLQuery property for
ParamCheck := False;
Then at the beginning of execute block, remove the parameter path..
execute block (param1 char (1) = :param1)
and your query is passed (%s) instead of :param1.
I did so in my problem and solved it !
":var" is interpreted as a parameter by TSQLQuery
You can turn that off by setting the ParamCheck property to False.
the only way that worked for me was not putting ":" for internal vars in the block.
Ex. select data from table into var; and that's work!, then, as this is a block, evaluate the var with an if!
if (var = 1)
do something;
else
do anotherthing;
and resolved business!

Ada - Task termination error - "Statement expected"

I have the following task
task body auto is
begin
Put_Line( licencepalte.all & " set off.");
delay traveltime.all;
Put_Line( licencepalte.all & " arrived.");
loop
select
indicator.passthrough;
terminate; -- error for this line: 'statement expected'
or
delay 0.2;
Put_Line( licencepalte.all & " is waiting.");
end select;
end loop;
end auto;
where we represent an indicator light and some cars (auto ~ automobiles) with tasks and protecteds. My main issue is, that I don't know, how to terminate, in case the indicator accepts the entry of the auto. You can see what I'm currently trying to do, and it pops up an error (see inline). How do I stop the task once the entry gets accepted? Why does this terminate not work? Thank you!
terminate is not an "action" that you perform. That is, you can't use a terminate statement anywhere you choose in the task body to terminate the task. The way to terminate a task is for the execution to reach the end that ends the body; in your case, exit to exit the loop works, as in Jacob's answer.
The purpose of or terminate is tell the program that a task is eligible for termination (I don't know if there's a better technical term for this). Suppose your task looks like:
task body Task_Type_1 is
begin
loop
select
accept Entry_1(...parameters...) do
-- something
end Entry_1;
or
accept Entry_2(...parameters...) do
-- something
end Entry_2;
end select;
end loop;
end Task_Type_1;
If the "something" code of the accept statements never exits the loop, the task will never terminate. This means that other constructs enclosing the task can never terminate. For example:
procedure Proc is
T1 : Task_Type_1;
begin
-- do some stuff
-- now we're at the end, and we have to wait for T1 to complete
end Proc;
The procedure creates a task of type Task_Type_1 and starts it. Then the body of the procedure is executed. When end Proc; is reached, the procedure doesn't terminate immediately, because it has to wait until the task finishes its job. But the way the task is written, the task will never complete. Therefore Proc will never return, and the program will probably deadlock.
or terminate is how to say that the task could terminate:
task body Task_Type_1 is
begin
loop
select
accept Entry_1(...parameters...) do
-- something
end Entry_1;
or
accept Entry_2(...parameters...) do
-- something
end Entry_2;
or
terminate;
end select;
end loop;
end Task_Type_1;
In this small example, where we have a procedure that just creates this one task, or terminate means: if this task reaches a point where it's blocked in the select because there aren't any entry calls waiting, and if Proc has reached the end of its code, then we terminate the task. The task body exits, any finalization that needs to be done is done, and then Proc can complete.
or terminate can be used only in a "selective accept". If you say select Some_Other_Task.Entry_2(...); so that it blocks until the other task's entry is available, you can't use or terminate in that kind of select.
In a more complex case, a procedure could create two or more tasks. When that procedure reaches its end statement, it won't return until (roughly speaking) all the tasks it creates are completed or all of the tasks that haven't completed are blocked on select statements that have or terminate clauses. If the latter happens, then all of those tasks complete and then the procedure can return.
The rule about "terminate alternatives" is in RM 9.3(6). It speaks in terms of depending on a master; in the example I showed above, Proc is the master.
If I understand your question correctly, an exit would do nicely instead of terminate.

Resources