File : s-bbthre.ads
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS --
4 -- --
5 -- S Y S T E M . B B . T H R E A D S --
6 -- --
7 -- S p e c --
8 -- --
9 -- Copyright (C) 1999-2002 Universidad Politecnica de Madrid --
10 -- Copyright (C) 2003-2005 The European Space Agency --
11 -- Copyright (C) 2003-2016, AdaCore --
12 -- --
13 -- GNARL is free software; you can redistribute it and/or modify it under --
14 -- terms of the GNU General Public License as published by the Free Soft- --
15 -- ware Foundation; either version 3, or (at your option) any later ver- --
16 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE. --
19 -- --
20 -- --
21 -- --
22 -- --
23 -- --
24 -- You should have received a copy of the GNU General Public License and --
25 -- a copy of the GCC Runtime Library Exception along with this program; --
26 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
27 -- <http://www.gnu.org/licenses/>. --
28 -- --
29 -- GNARL was developed by the GNARL team at Florida State University. --
30 -- Extensive contributions were provided by Ada Core Technologies, Inc. --
31 -- --
32 -- The port of GNARL to bare board targets was initially developed by the --
33 -- Real-Time Systems Group at the Technical University of Madrid. --
34 -- --
35 ------------------------------------------------------------------------------
36
37 -- Package that implements basic tasking functionalities
38
39 pragma Restrictions (No_Elaboration_Code);
40
41 with System;
42 with System.Storage_Elements;
43 with System.BB.CPU_Primitives;
44 with System.BB.Time;
45 with System.BB.Interrupts;
46 with System.Multiprocessors;
47 with System.BB.CPU_Primitives.Multiprocessors;
48
49 package System.BB.Threads is
50 pragma Preelaborate;
51
52 use type System.Multiprocessors.CPU;
53
54 --------------------------
55 -- Basic thread support --
56 --------------------------
57
58 Initialized : Boolean := False;
59 -- Boolean that indicates whether the tasking executive has finished its
60 -- initialization.
61
62 type Thread_Descriptor;
63 -- This type contains the information about a thread
64
65 type Thread_Id is access all Thread_Descriptor;
66 -- Type used as thread identifier
67
68 Null_Thread_Id : constant Thread_Id := null;
69 -- Identifier used to define an invalid value for a thread identifier
70
71 type Thread_States is (Runnable, Suspended, Delayed);
72 -- These are the three possible states for a thread under the Ravenscar
73 -- profile restrictions: Runnable (not blocked, and it may also be
74 -- executing), Suspended (waiting on an entry call), and Delayed (waiting
75 -- on a delay until statement).
76
77 type Thread_Descriptor is record
78 Context : aliased System.BB.CPU_Primitives.Context_Buffer;
79 -- Location where the hardware registers (stack pointer, program
80 -- counter, ...) are stored. This field supports context switches among
81 -- threads.
82
83 -- It is important that the Context field is placed at the beginning of
84 -- the record, because this assumption is using for implementing context
85 -- switching. Take into account the alignment (8 bytes, 64 bits) to
86 -- compute the required size.
87
88 ATCB : System.Address;
89 -- Address of the Ada Task Control Block corresponding to the Ada task
90 -- that executes on this thread.
91
92 Base_CPU : System.Multiprocessors.CPU_Range;
93 -- CPU affinity of the thread
94
95 Base_Priority : Integer;
96 -- Base priority of the thread
97
98 Active_Priority : Integer;
99 pragma Volatile (Active_Priority);
100 -- Active priority that differs from the base priority due to dynamic
101 -- priority changes required by the Ceiling Priority Protocol.
102 -- This field is marked as Volatile for a fast implementation
103 -- of Get_Priority.
104
105 Top_Of_Stack : System.Address;
106 -- Address of the top of the stack that is used by the thread
107
108 Bottom_Of_Stack : System.Address;
109 -- Address of the bottom of the stack that is used by the thread
110
111 Next : Thread_Id;
112 -- Points to the ready thread that is in the next position for
113 -- execution.
114
115 Alarm_Time : System.BB.Time.Time;
116 -- Time (absolute) when the alarm for this thread expires
117
118 Next_Alarm : Thread_Id;
119 -- Next thread in the alarm queue. The queue is ordered by expiration
120 -- times. The first place is occupied by the thread which must be
121 -- first awaken.
122
123 State : Thread_States;
124 -- Encodes some basic information about the state of a thread
125
126 In_Interrupt : Boolean;
127 pragma Volatile (In_Interrupt);
128 -- True iff this task has been interrupted, and an interrupt handler
129 -- is being executed.
130
131 Wakeup_Signaled : Boolean;
132 -- Variable which reflects whether another thread has performed a
133 -- Wakeup operation on the thread. It may happen when a task is about
134 -- to suspend itself, but it is preempted just before by the task that
135 -- is going to awake it.
136
137 Global_List : Thread_Id;
138 -- Next thread in the global list. The queue is ordered by creation
139 -- time. The first place is occupied by the environment thread, and
140 -- it links all threads in the system.
141
142 Execution_Time : System.BB.Time.Composite_Execution_Time;
143 -- CPU time spent for this thread
144 end record;
145
146 function Get_Affinity
147 (Thread : Thread_Id) return System.Multiprocessors.CPU_Range with
148 -- Return CPU affinity of the given thread (maybe Not_A_Specific_CPU)
149
150 Pre => Thread /= Null_Thread_Id,
151
152 Inline => True;
153
154 function Get_CPU
155 (Thread : Thread_Id) return System.Multiprocessors.CPU with
156 -- Return the CPU in charge of the given thread (always a valid CPU)
157
158 Pre => Thread /= Null_Thread_Id,
159
160 Inline => True;
161
162 procedure Initialize
163 (Environment_Thread : Thread_Id;
164 Main_Priority : System.Any_Priority) with
165 -- Procedure to initialize the board and the data structures related to the
166 -- low level tasking system. This procedure must be called before any other
167 -- tasking operation. The operations to perform are:
168 -- - Hardware initialization
169 -- * Any board-specific initialization
170 -- * Interrupts
171 -- * Timer
172 -- - Initialize stacks for main procedures to be executed on slave CPUs
173 -- - Initialize the thread descriptor for the environment task
174 -- * Set base CPU for the environment task to the one on which this
175 -- initialization code executes
176 -- * Set the base and active priority of the environment task
177 -- * Store the boundaries of the stack for the environment task
178 -- * Initialize the register context
179 -- - Initialize the global queues
180 -- * Set the environment task as first (and only at this moment) in
181 -- the ready queue
182 -- * Set the environment task as first (and only at this moment) in
183 -- the global list of tasks
184 -- * Set the environment task as the currently executing task
185 -- - Initialize the floating point unit
186 -- - Signal the flag corresponding to the initialization
187
188 Pre =>
189
190 -- This procedure must be called by the master CPU
191
192 CPU_Primitives.Multiprocessors.Current_CPU = Multiprocessors.CPU'First
193
194 -- Initialization can only happen once
195
196 and then not Initialized;
197
198 procedure Initialize_Slave
199 (Idle_Thread : Thread_Id;
200 Idle_Priority : Integer;
201 Stack_Address : System.Address;
202 Stack_Size : System.Storage_Elements.Storage_Offset) with
203 -- Procedure to initialize the idle thread on a slave CPU.
204 -- This thread is used to handle interrupt if the CPU doesn't have any
205 -- other task. The initialization for the main CPU must have been
206 -- performed. The operations to perform are:
207 -- - Initialize the thread descriptor
208 -- * Set base CPU to the one on which this code executes
209 -- * Set the base and active priority
210 -- * Store the boundaries of the stack
211 -- * Initialize the register context
212 -- - Initialize the global queues
213 -- * Set the task as the currently executing task in this processor.
214
215 Pre =>
216
217 -- It must happen after the initialization of the master CPU
218
219 Initialized;
220
221 procedure Thread_Create
222 (Id : Thread_Id;
223 Code : System.Address;
224 Arg : System.Address;
225 Priority : Integer;
226 Base_CPU : System.Multiprocessors.CPU_Range;
227 Stack_Address : System.Address;
228 Stack_Size : System.Storage_Elements.Storage_Offset) with
229 -- Create a new thread
230 --
231 -- The new thread executes the code at address Code and using Args as
232 -- argument. Priority is the base priority of the new thread. The new
233 -- thread is provided with a stack of size Stack_Size that has been
234 -- preallocated at Stack_Address.
235 --
236 -- A procedure to destroy threads is not available because that is not
237 -- allowed by the Ravenscar profile.
238
239 Pre => Initialized;
240
241 function Thread_Self return Thread_Id with
242 -- Return the thread identifier of the calling thread
243
244 Post => Thread_Self'Result /= Null_Thread_Id,
245
246 Inline => True;
247
248 ----------------
249 -- Scheduling --
250 ----------------
251
252 procedure Set_Priority (Priority : Integer);
253 pragma Inline (Set_Priority);
254 -- Set the active priority of the executing thread to the given value
255
256 function Get_Priority (Id : Thread_Id) return Integer with
257 -- Get the current active priority of any thread
258
259 Pre => Id /= Null_Thread_Id,
260
261 Inline => True;
262
263 procedure Sleep;
264 -- The calling thread is unconditionally suspended. In the case when there
265 -- is a request to wakeup the caller just before the state changed to
266 -- Suspended then the situation is signaled with the flag Wakeup_Signaled,
267 -- and the call to Sleep consumes this token and the state remains
268 -- Runnable.
269
270 procedure Wakeup (Id : Thread_Id) with
271 -- Thread Id becomes ready (the thread must be previously suspended). In
272 -- the case when there is a request to wakeup the caller just before the
273 -- state changed to Suspended then the situation is signaled with the
274 -- flag Wakeup_Signaled (the state remains unchanged in this case).
275
276 Pre =>
277 Id /= Null_Thread_Id
278
279 -- We can only wakeup a task that is already suspended or about to be
280 -- suspended (and hence still runnable).
281
282 and then Id.all.State in Suspended | Runnable
283
284 -- Any wakeup previously signaled must have been consumed
285
286 and then not Id.all.Wakeup_Signaled;
287
288 ----------
289 -- ATCB --
290 ----------
291
292 procedure Set_ATCB (Id : Thread_Id; ATCB : System.Address);
293 pragma Inline (Set_ATCB);
294 -- This procedure sets the ATCB passed as argument for the thread ID
295
296 function Get_ATCB return System.Address;
297 pragma Inline (Get_ATCB);
298 -- Returns the ATCB of the currently executing thread
299
300 end System.BB.Threads;