Ada में real-time systems programming — priority, period और execution time control

· अद्यतन तिथि: · · Ada, RealTime, Ravenscar, CeilingLocking, Tasking, Scheduling, PriorityInversion, ProgrammingLanguage, real-time, high-integrity

1. परिचय — Ada और real-time का गहरा रिश्ता

पिछले लेख “Ada में सुरक्षित concurrency” में हमने Ada के task और protected object से safe concurrent programming की basics देखी थीं। इस बार उसी लाइन पर आगे बढ़ते हैं — एक और tightly constrained domain में: real-time systems।

Real-time system में “correctness” का मतलब सिर्फ़ logically सही result नहीं है। वह result deadline के अंदर मिलना भी correctness का हिस्सा है। एक millisecond देर से आया सही जवाब, गलत जवाब जितना ही खतरनाक होता है।

Ada इस requirement के लिए language specification के Annex D (Real-Time Systems) के रूप में एक पूरा real-time feature set देती है। यह “बाद में library से जोड़ दिया गया” नहीं है — language runtime में ही बनी real-time guarantee है।

Ada के real-time features (Annex D):
- Task priority और preemption (FIFO_Within_Priorities)
- Ceiling_Locking protocol (priority inversion रोकना)
- delay until से absolute time पर periodic execution
- Ravenscar profile (safety-critical subset)
- Timing events (बिना polling के time-driven wakeup)
- Execution time monitoring (Ada.Execution_Time)
- Multi-periodic scheduling

इस लेख में हम इन्हें 8 practical code examples से step-by-step देखेंगे। हर snippet conceptually अकेला चल सकता है, लेकिन 04/05 में कई compilation units हैं — उन्हें gnatchop से split करके फिर gnatmake करें।

Audience और prerequisites: पिछले लेख वाले task, rendezvous, और protected object की basics पता होनी चाहिए। Embedded devices या high-integrity control software में दिलचस्पी रखने वाले developers के लिए है; Ada syntax की शुरुआत यहाँ नहीं है।

Verification environment: लेख के 8 examples GNAT 13.3.0 (Ubuntu 24.04, x86-64) पर build होते confirm किए गए हैं। अध्याय 3 और 5 में छपे run outputs भी उसी environment से हैं। Priority और preemption असल में कैसे behave करते हैं, यह OS और GNAT runtime पर depend करता है (अध्याय 12), इसलिए output की बारीकियाँ environment के हिसाब से बदल सकती हैं।

लेख में आए code fragments chapter-wise files में बाँटकर GitHub पर reference collection के रूप में उपलब्ध हैं।

ada-real-time-systems - komurasoft-blog-samples (GitHub)

इस लेख का knowledge map

Ada की language specification का Annex D task priority पर आधारित FIFO_Within_Priorities, protected object को automatically ceiling priority देने वाला Ceiling_Locking protocol, cumulative drift रोकने वाला delay until से periodic execution, static analysis के लिए आसान Ravenscar profile, बिना polling वाले timing events, और per-task execution time measurement तक language runtime में ही embed करता है। Ceiling_Locking उस priority inversion को रोकता है जो 1997 के Mars Pathfinder पर असल में हुई और जिसने spacecraft को बार-बार reset कराया: protected object enter करने वाले task को automatically ceiling priority पर उठा देता है। Ravenscar profile relative delay और select statement वगैरह मना करके Ada के task को static timing analysis के लिए आसान subset तक सीमित करता है, और GNAT में gnat.adc file में pragma लिखकर enable होता है। लेकिन priority का असल mapping OS और GNAT runtime पर depend करता है।

Ada real-time systems programming का knowledge mapAda Annex D task और protected object के ऊपर priority-based dispatch, Ceiling_Locking, delay until, Ravenscar profile, timing events और execution time measurement कैसे embed करता है, तथा Ceiling_Locking Mars Pathfinder जैसी priority inversion कैसे रोकता है — दिखाने वाला diagramuse करता हैuse करता हैuse करता हैuse करता हैuse करता हैuse करता हैrequire करता हैrequire करता हैrequire करता हैprevent करता हैcause हो सकताrequire करता हैrequire करता हैrequire करता हैसे configurecause हो सकताprevent करता हैrecommended नहींuse करता हैuse करता हैrequire करता हैAnnex D (Ada का real-time systems standard)Ceiling_Locking protocolFIFO_Within_Prioritiesdelay until (absolute time पर delay)Ravenscar profiletiming events (Ada.Real_Time.Timing_Events)Ada.Execution_Time (execution time measurement)Ada task (concurrency)protected objectGNATpriority inversionMars Pathfinder का priority inversion incidentrelative delay (delay statement)periodic execution का cumulative drift

Diagram में solid line हमेशा लागू रहने वाला relation दिखाती है और dashed line conditional relation दिखाती है (शर्तें detail page पर हर relation के explanation में दी गई हैं)। Relations की पूरी list (कुल 21, evidence और certainty सहित) तथा मुख्य concepts की definitions knowledge map की detail page पर संकलित हैं (जापानी में)। Data: JSON-LD / Turtle

2. Real-time system क्या है

पहले terminology साफ़ कर लें।

Concept Explanation
Hard real-time Deadline miss का मतलब system का catastrophic failure है (flight control, airbag, pacemaker)
Soft real-time Deadline miss undesirable है, लेकिन कभी-कभार miss चल सकता है (video streaming, games)
Deadline Absolute time जिस तक task पूरा होना चाहिए
Period वह interval जिस पर task बार-बार release होता है
WCET (Worst-Case Execution Time) Task का worst-case execution time
Jitter Periodic execution की timing variation
Schedulability “क्या यह task set सभी deadlines पूरा करते हुए चल सकता है” — यह गुण। इसे theoretically confirm करना schedulability analysis है (response-time analysis वगैरह)
Ravenscar profile Ada के tasking को statically analyzable subset तक सीमित करने वाला convention। नाम UK के गाँव Ravenscar से है, जहाँ drafting meeting हुई थी (अध्याय 6)

Real-time design में हर task के लिए WCET <= deadline एक ज़रूरी necessary condition है। अकेले इससे पूरे system की deadline guarantee नहीं मिलती। Blocking time, priority assignment, jitter, interrupts, और runtime/OS behaviour समेत response-time analysis अलग से चाहिए। Practice में margin रखने के लिए WCET < deadline लक्ष्य रखते हैं। Ada के real-time features उसी analysis को आसान बनाने वाला predictable execution model language level पर देते हैं।

Real-time requirements और schedulabilityHard और soft real-time की deadline, period, WCET, jitter Ada Annex D के FIFO_Within_Priorities, Ceiling_Locking, delay until के साथ schedulability analysis में कैसे जुड़ते हैं।Real-time requirementsdeadline miss = catastrophic failureoccasional miss toleratedDeadlineComplete करने का absolute timePeriodRepeat intervalWCETWorst-case execution timeJitterPeriod की variationHard real-timeFlight controlAirbagPacemakerSoft real-timeVideo streamingGamesUIAda Annex DPredictability के mechanismsFIFO_Within_PrioritiesCeiling_Lockingdelay untilSchedulability analysisNecessary condition: WCET &lt;= deadlineSufficiency response-time analysis से confirm

Real-time systems में सबसे खतरनाक phenomena में से एक priority inversion है। यही problem 1997 में Mars Pathfinder पर असल में आई, और spacecraft बार-बार reset होता रहा।

Priority inversion कैसे बनता हैLow-priority task lock hold किए हुए, medium-priority task उसे preempt करे, और high-priority task अनिश्चित काल तक block रह जाए।Shared resourceMedium-priority taskHigh-priority taskLow-priority taskSchedulerShared resourceMedium-priority taskHigh-priority taskLow-priority taskSchedulerCritical section चल रही हैH wake होता है, scheduler L को suspend करता हैLock wait पर block! (L अभी hold किए हुए है)H lock wait पर है, इसलिए L फिर resumeLock release की तरफ जारी...M wake होता है, scheduler L को suspend करता हैL lock release नहीं कर सकताM चलता रहता है (H और L दोनों stuck)[priority inversion] High-priority अनिश्चित काल blockLock acquireLock acquire की कोशिश

Low-priority task lock hold किए हुए medium-priority task से preempt हो जाता है, और high-priority task अनिश्चित काल तक block रह जाता है। Mars Pathfinder पर असल mitigation VxWorks का priority inheritance enable करना था। Ada उसी class की problem के लिए अलग mechanism देती है — language feature Ceiling_Locking

3. Task priority की basics — FIFO_Within_Priorities

FIFO_Within_Priorities Ada Annex D में माँग सकने वाली standard priority-based dispatching policy है। Policy explicitly न लिखें तो default implementation-defined है; GNAT कई targets पर इसी परिवार की policy इस्तेमाल करता है। एक ही priority के अंदर FIFO (first-in, first-out) चलता है, और ऊँची priority वाला task निचली priority वाले को preempt (बीच में काट) करता है।

-- 01_task_priority.ada
-- Task priority और FIFO_Within_Priorities की basic form
-- Configuration pragma context clause से पहले रखें

pragma Task_Dispatching_Policy (FIFO_Within_Priorities);

with Ada.Text_IO;               use Ada.Text_IO;
with System;                    use System;
with Ada.Real_Time;             use Ada.Real_Time;

procedure Task_Priority_Demo is

   task High_Priority_Task is
      pragma Priority (Priority'Last);
      pragma Storage_Size (4 * 1024);
   end High_Priority_Task;

   task Low_Priority_Task is
      pragma Priority (Priority'First);
      pragma Storage_Size (4 * 1024);
   end Low_Priority_Task;

   task body High_Priority_Task is
   begin
      Put_Line ("[T=0.0s] High priority task started");
      delay until Clock + Milliseconds (100);
      Put_Line ("[T=0.1s] High priority task completed");
   end High_Priority_Task;

   task body Low_Priority_Task is
   begin
      Put_Line ("[T=0.0s] Low priority task started");
      delay until Clock + Milliseconds (500);
      Put_Line ("[T=0.5s] Low priority task completed");
   end Low_Priority_Task;

begin
   Put_Line ("=== Task Priority Demo (FIFO_Within_Priorities) ===");
   Put_Line ("Main: waiting for tasks to complete...");
   delay until Clock + Milliseconds (800);
   Put_Line ("Main: done");
end Task_Priority_Demo;

मुख्य बातें:

  • pragma Priority हर task को static priority देता है। Priority'Last सबसे ऊँची, Priority'First सबसे निचली।
  • इस demo के task bodies भारी computation नहीं करते; delay until से दिए समय तक wait करते हैं। यहाँ देखना यह है कि दोनों एक साथ runnable हों तो high-priority task को पहले execution मिलती है।
  • यह diagram FIFO_Within_Priorities का अलग-अलग priorities के बीच preemption वाला हिस्सा दिखाता है। एक ही priority के अंदर FIFO order देखने के लिए बराबर priority वाले कई tasks का अलग example चाहिए।
  • असल systems में System.Default_Priority को आधार मानकर relative priorities design करना आम है।
FIFO_Within_Priorities पर high-priority preemptionदोनों tasks runnable हों तो scheduler सबसे ऊँची priority चुनता है, delay until के बाद completion order 100ms फिर 500ms रहता है।Low-priority task(Priority=First)High-priority task(Priority=Last)Main taskSchedulerLow-priority task(Priority=First)High-priority task(Priority=Last)Main taskSchedulerT=0ms: दोनों tasks runnableStart log print करता हैStart log print करता हैT=100ms: HP wakeCompletion log print करता हैT=500ms: LP wakeCompletion log print करता है(T=800ms) Main endsTask createTask createसबसे ऊँची priority HP चुनता हैdelay until T+100ms पर blockफिर LP execute करता हैdelay until T+500ms पर blockHP execute करता हैLP execute करता है

Run example (GNAT 13.3.0 / Ubuntu 24.04, x86-64):

$ gnatchop -w 01_task_priority.ada .     # → task_priority_demo.adb
$ gnatmake task_priority_demo.adb
$ ./task_priority_demo
[T=0.0s] High priority task started
[T=0.0s] Low priority task started
=== Task Priority Demo (FIFO_Within_Priorities) ===
Main: waiting for tasks to complete...
[T=0.1s] High priority task completed
[T=0.5s] Low priority task completed
Main: done

ध्यान दें: दोनों tasks के start logs main के heading से पहले आ रहे हैं। Declarative part के tasks enclosing subprogram के body में enter होने से पहले activate होते हैं, इसलिए यह क्रम बन सकता है। और ये दो start-log lines हर run पर आपस में पलट भी सकती हैं। अध्याय 12 के मुताबिक pragma Priority असल scheduling पर कैसे map होता है, यह OS और GNAT runtime पर है; generic Linux पर priority के हिसाब से startup order guarantee नहीं है। इस example में स्थिर रूप से दिखने वाली बात delay until से तय 0.1s / 0.5s की completion order है।

Ada की priority range (GNAT default):
  Priority'First  = 0   (सबसे निचली)
  Priority'Last   = 30  (सबसे ऊँची; OS पर depend)

4. Ceiling_Locking — language खुद priority inversion रोकती है

Real-time systems की सबसे tricky problems में priority inversion है। High-priority task उस lock की wait करता है जो low-priority task hold किए हुए है, और वह low-priority task medium-priority task से preempt हो जाता है — नतीजा, high-priority task अनिश्चित काल तक block

Ada इस problem के लिए Ceiling_Locking protocol सीधे protected objects में बैठाती है।

-- 02_ceiling_locking.ada
-- Ceiling_Locking protocol से priority inversion रोकना
-- Configuration pragma context clause से पहले रखें

pragma Locking_Policy (Ceiling_Locking);

with Ada.Text_IO;               use Ada.Text_IO;
with System;                    use System;
with Ada.Real_Time;             use Ada.Real_Time;

procedure Ceiling_Locking_Demo is

   Ceiling : constant System.Any_Priority := System.Any_Priority'Last;

   protected Shared_Data is
      pragma Priority (Ceiling);
      procedure Write (V : Integer);
      function Read return Integer;
   private
      Value : Integer := 0;
   end Shared_Data;

   protected body Shared_Data is
      procedure Write (V : Integer) is
      begin
         Value := V;
      end Write;

      function Read return Integer is
      begin
         return Value;
      end Read;
   end Shared_Data;

   task Producer is
      pragma Priority (Priority'Last);
      pragma Storage_Size (4 * 1024);
   end Producer;

   task Consumer is
      pragma Priority (Priority'First);
      pragma Storage_Size (4 * 1024);
   end Consumer;

   task body Producer is
   begin
      Put_Line ("[T=0.0s] Producer (high prio): about to write");
      Shared_Data.Write (42);
      Put_Line ("[T=0.0s] Producer (high prio): write done");
      delay until Clock + Milliseconds (100);
   end Producer;

   task body Consumer is
   begin
      delay until Clock + Milliseconds (10);
      Put_Line ("[T=0.01s] Consumer (low prio): about to read");
      declare
         V : Integer;
      begin
         V := Shared_Data.Read;
         Put_Line ("[T=0.01s] Consumer (low prio): read done, got" &
                     Integer'Image (V));
      end;
      delay until Clock + Milliseconds (100);
   end Consumer;

begin
   Put_Line ("=== Ceiling_Locking Demo ===");
   Put_Line ("Main: producer priority = Last, consumer priority = First");
   Put_Line ("Ceiling = Any_Priority'Last, locking = Ceiling_Locking");
   delay until Clock + Milliseconds (300);
   Put_Line ("Main: done");
end Ceiling_Locking_Demo;

Ceiling_Locking कैसे काम करता है:

  1. Protected object पर pragma Priority (Ceiling) से ceiling priority सेट करें।
  2. कोई भी task protected object enter करे, enter करते ही automatically ceiling priority पर उठ जाता है
  3. इसलिए जो task protected object इस्तेमाल कर रहा है, उसे medium-priority task preempt नहीं कर सकता।
  4. Protected object से निकलते ही मूल priority वापस आ जाती है।

नीचे वाला diagram ठीक पहले वाले sample का strict time trace नहीं है। यह अवधारणा दिखाता है कि दूसरे diagram वाला priority inversion pattern Ceiling_Locking से कैसे रुकता है।

Ceiling_Locking priority inversion कैसे रोकता हैProtected object enter करते ही low-priority task ceiling 30 पर उठ जाता है, इसलिए medium-priority preempt नहीं कर पाता; high-priority ceiling check पास करके lock free होने का wait करता है।Protected object(ceiling priority=30)High-priority task(priority=30)Medium-priority task(priority=20)Low-priority task(priority=10)SchedulerProtected object(ceiling priority=30)High-priority task(priority=30)Medium-priority task(priority=20)Low-priority task(priority=10)SchedulerActive priority > ceiling वाले caller पर Program_ErrorDiagram का H(30) ceiling(30) के बराबर है, इसलिए enter कर सकता हैExecution priority 30 पर उठती हैM wake होता हैL ceiling priority 30 पर चल रहा हैM(20) preempt नहीं कर सकताH wake होता हैH(30) ceiling check पास करता हैलेकिन L PO इस्तेमाल कर रहा है, इसलिए waitPriority 10 पर लौटती हैPO free होने के बाद H execute होता हैH(30) = ceiling(30), contention resolve होने के बाद enter कर सकता हैProtected operation enter करता हैOperation चलाता हैProtected operation से निकलता हैProtected operation enter करता हैProtected operation से निकलता है

Design rule: Protected object की ceiling priority उस object इस्तेमाल करने वाले सभी tasks की सबसे ऊँची priority से कम नहीं होनी चाहिए। इसे तोड़कर, ceiling से ऊँची active priority वाला task protected operation call करे तो Ada Program_Error उठाकर design mistake detect कर सकती है।

C में pthread mutex से यही करने के लिए PTHREAD_PRIO_PROTECT attribute अलग से सेट करना पड़ता है। Ada में यह language का standard feature है।

5. delay until — periodic task बिना drift के

Real-time systems का basic pattern periodic task है। Fixed interval पर बार-बार चलने वाले task में cumulative timing error (drift) रोकना बहुत ज़रूरी है।

Ada का delay until इसी problem को साफ़ तरीके से हल करता है।

-- 03_periodic_task.ada
-- delay until से periodic task — cumulative drift रोकें

with Ada.Text_IO;               use Ada.Text_IO;
with System;                    use System;
with Ada.Real_Time;             use Ada.Real_Time;

procedure Periodic_Task_Demo is

   Period_MS : constant Time_Span := Milliseconds (200);
   Cycles    : constant Positive  := 5;

   task Sensor_Reader is
      pragma Priority (Priority'Last - 2);
      pragma Storage_Size (4 * 1024);
   end Sensor_Reader;

   task body Sensor_Reader is
      Start_Time  : constant Time := Clock;
      Next_Release : Time := Start_Time + Period_MS;
      Cycle_Count  : Natural := 0;
   begin
      Put_Line ("[Sensor] Periodic task starts, period=" &
                To_Duration (Period_MS)'Image & "s, cycles=" &
                Natural'Image (Cycles));

      for I in 1 .. Cycles loop
         delay until Next_Release;

         Cycle_Count := Cycle_Count + 1;
         Put_Line ("[Sensor] Cycle" & Natural'Image (Cycle_Count) &
                   " at" & Duration'Image (To_Duration (Clock - Start_Time)) & "s");

         Next_Release := Next_Release + Period_MS;
      end loop;

      Put_Line ("[Sensor] Periodic task finished. Actual elapsed:" &
                Duration'Image (To_Duration (Clock - Start_Time)) & "s");
   end Sensor_Reader;

begin
   Put_Line ("=== Periodic Task Demo (delay until) ===");
   Put_Line ("Main: waiting for" & Natural'Image (Cycles) & " cycles...");
   delay until Clock + Milliseconds (1500);
   Put_Line ("Main: done");
end Periodic_Task_Demo;

delay until क्यों:

Approach Problem
delay Period; हर iteration का processing time जुड़ता जाता है, period धीरे-धीरे खिसकती है (cumulative drift)
delay until Next_Release; Next_Release := Next_Release + Period; Absolute time पर टिका है; एक iteration देर से चले तो भी अगला release time सही रहता है

हाँ, delay until यह automatically guarantee नहीं करता कि processing period के अंदर समाएगी। अगर काम अगले wake time को पार कर चुका, तो वह delay until लगभग तुरंत लौट आता है — system को इसे deadline miss मानकर overload की तरह treat करना चाहिए।

delay के साथ:
  T=0ms → work(15ms) → delay 100ms → T=115ms → work(10ms) → ...
  Actual interval: 115ms, 110ms, ... (processing time जमा होता है)

delay until के साथ:
  Next_Release: 100ms, 200ms, 300ms, ... (absolute time)
  T=0ms → work(15ms) → delay until 100ms → T=100ms → work(10ms) → delay until 200ms
  Actual interval: 100ms, 100ms, ... (processing time से interval नहीं बदलता)

Run example (GNAT 13.3.0 / Ubuntu 24.04, x86-64):

$ gnatchop -w 03_periodic_task.ada .     # → periodic_task_demo.adb
$ gnatmake periodic_task_demo.adb
$ ./periodic_task_demo
[Sensor] Periodic task starts, period= 0.200000000s, cycles= 5
=== Periodic Task Demo (delay until) ===
Main: waiting for 5 cycles...
[Sensor] Cycle 1 at 0.200326876s
[Sensor] Cycle 2 at 0.400159550s
[Sensor] Cycle 3 at 0.600183089s
[Sensor] Cycle 4 at 0.800327451s
[Sensor] Cycle 5 at 1.000260472s
[Sensor] Periodic task finished. Actual elapsed: 1.000297359s
Main: done

हर cycle पर करीब 0.2–0.3 ms का wakeup delay दिखता है, लेकिन वह delay अगली period पर नहीं जाता। पाँचवीं cycle पर भी start time से फ़र्क 1 ms से कम है। अगर delay Period; लिखा होता, तो यही देरी हर बार जुड़कर पाँच cycles बाद नज़र आने वाला फ़र्क बन जाती। ये संख्याएँ generic Linux पर एक sample हैं; hard real-time environment की guarantee नहीं।

आगे के हर periodic task में यही delay until pattern इस्तेमाल होगा।

delay versus delay until और deadline missRelative delay cumulative drift लाता है, delay until absolute time पर टिका रहता है, और overrun पर delay until तुरंत लौट आता है।Period overrun - deadline misscompute 130msNext = T+100msdelay until T+100ms तुरंत लौटता हैDelay detect करके overload की तरह treat करेंdelay until - absolute timecompute 15msNext = T+100msdelay until T+100ms → 100ms पर wakecompute 10msNext = T+200ms → 200ms पर wakeActual interval: 100ms, 100ms...delay Period - cumulative driftdelay 100ms → 115ms पर wakeT=0ms: compute 15mscompute 10ms → 125msdelay 100ms → 225ms पर wakeActual interval: 115ms, 110ms...समय के साथ error जमा होता हैCumulative drift रुकता है

6. Ravenscar profile — verifiable real-time subset

Ada का tasking शक्तिशाली है, लेकिन safety-critical systems में “बहुत शक्तिशाली” खुद problem बन जाता है। Dynamic task creation, select statement, abort statement — ये WCET की static analysis मुश्किल कर देते हैं।

Ravenscar profile Ada का जवाब है। Tasking को statically analyzable, deterministic subset तक सीमित करता है।

-- 04_ravenscar_profile.ada
-- Ravenscar profile की basic form
-- Compile करते समय gnat.adc में pragma Profile (Ravenscar); लिखें
-- Build: gnatchop -w 04_ravenscar_profile.ada .
--         → ravenscar_state.ads / ravenscar_state.adb / ravenscar_demo.adb में split होता है
--         gnat.adc तैयार करके gnatmake ravenscar_demo.adb

with Ada.Text_IO;               use Ada.Text_IO;
with System;                    use System;
with Ada.Real_Time;             use Ada.Real_Time;

package Ravenscar_State is

   protected Signal is
      pragma Priority (System.Default_Priority + 5);
      entry Wait_For_Release;
      procedure Release;
   private
      Released : Boolean := False;
   end Signal;

   task Periodic_Worker is
      pragma Priority (System.Default_Priority + 1);
      pragma Storage_Size (4 * 1024);
   end Periodic_Worker;

   task Monitor is
      pragma Priority (System.Default_Priority);
      pragma Storage_Size (4 * 1024);
   end Monitor;

end Ravenscar_State;

with Ada.Text_IO;               use Ada.Text_IO;
with System;                    use System;
with Ada.Real_Time;             use Ada.Real_Time;

package body Ravenscar_State is

   protected body Signal is
      entry Wait_For_Release when Released is
      begin
         Released := False;
      end Wait_For_Release;

      procedure Release is
      begin
         Released := True;
      end Release;
   end Signal;

   task body Periodic_Worker is
      Start_Time   : constant Time := Clock;
      Next_Release : Time := Start_Time + Milliseconds (100);
      Period       : constant Time_Span := Milliseconds (100);
      Cycle_Count  : Natural := 0;
   begin
      Put_Line ("[Worker] Ravenscar periodic task starts");

      for I in 1 .. 4 loop
         delay until Next_Release;

         Cycle_Count := Cycle_Count + 1;
         Put_Line ("[Worker] Cycle" & Natural'Image (Cycle_Count) &
                   " at" & Duration'Image (To_Duration (Clock - Start_Time)) & "s");
         Signal.Release;
         Next_Release := Next_Release + Period;
      end loop;

       Put_Line ("[Worker] Finished demo, waiting (Ravenscar: No_Task_Termination)");
      loop
         delay until Clock + Seconds (1);
      end loop;
   end Periodic_Worker;

   task body Monitor is
   begin
      Put_Line ("[Monitor] Waiting for signals...");

      for I in 1 .. 4 loop
         Signal.Wait_For_Release;
         Put_Line ("[Monitor] Received signal" & Natural'Image (I));
      end loop;

      Put_Line ("[Monitor] All signals received, waiting (Ravenscar: No_Task_Termination)");
      loop
         delay until Clock + Seconds (1);
      end loop;
   end Monitor;

end Ravenscar_State;

with Ravenscar_State; use Ravenscar_State;
with Ada.Text_IO;     use Ada.Text_IO;
with Ada.Real_Time;   use Ada.Real_Time;

procedure Ravenscar_Demo is
begin
   Put_Line ("=== Ravenscar Profile Demo ===");
   Put_Line ("(compile with: gnatmake -gnatec=gnat.adc ravenscar_demo)");
   Put_Line ("Main: waiting for Ravenscar tasks...");
   delay until Clock + Milliseconds (800);
   Put_Line ("Main: demo window elapsed; waiting forever (Ravenscar: No_Task_Termination)");
   loop
      delay until Clock + Seconds (1);
   end loop;
end Ravenscar_Demo;

Ravenscar profile की restrictions:

Forbidden feature Reason
Dynamic task creation (new या access types) Runtime memory allocation non-deterministic है
select statement सिर्फ़ multiple alternatives नहीं; पूरा select control-flow analysis मुश्किल करता है
abort statement Asynchronous abort से state unpredictable हो जाती है
Ada.Task_Attributes Runtime-dynamic behaviour
Dynamic priority change Scheduling analysis की धारणा runtime पर बदल जाती है
Relative delay (delay) Cumulative drift पैदा हो जाता है, इसलिए absolute time वाला delay until इस्तेमाल करें
Protected object पर एक से ज़्यादा entries Blocking conditions और analysis cases बढ़ते हैं
Task termination Ravenscar सभी tasks को non-terminating मानता है
requeue statement Control-flow tracking जटिल हो जाता है

इन restrictions से Ravenscar-compliant program static timing analysis के अनुकूल बनता है। यही गुण DO-178C (aviation software) और ISO 26262 (automotive functional safety) जैसे safety standards माँगते हैं। नीचे सूची मुख्य restrictions का excerpt है; असल profile में No_Task_Hierarchy और Detect_Blocking जैसी runtime/analyzability वाली extra rules भी हैं।

Ravenscar restrictions और safety standardsRavenscar Ada tasking को restrictions और required policies से सीमित करता है ताकि static timing analysis आसान हो और DO-178C, ISO 26262, IEC 62304 की तरफ जाए।Complete Ada taskingRavenscar profileRestrictionsRequired policiesDynamic task creation मनाselect statement मनाabort statement मनाTask_Attributes मनाProtected object पर 1 entry की सीमाrequeue statement मनाRelative delay मनाdelay until इस्तेमाल करेंDynamic priority change मनाTask termination मनासभी tasks non-terminatingFIFO_Within_PrioritiesCeiling_Lockingइससे आसान होता है:static timing analysisDO-178CAviation softwareISO 26262Automotive functional safetyIEC 62304Medical device software

Ravenscar profile enable करने के लिए gnat.adc में यह लिखें:

pragma Profile (Ravenscar);

7. Timing events — बिना polling के time-driven wakeup

बहुत से real-time systems में बार-बार यही चाहिए: “दिए समय पर high-priority task को wake करो।” Naive implementation timer poll करती है। Ada इससे बेहतर mechanism देती है — timing events

-- 05_timing_events.ada
-- Timing events (Ada.Real_Time.Timing_Events)
-- High-priority task को बिना polling के wake करने का mechanism
-- Build: gnatchop -w 05_timing_events.ada .
--         → signal_pkg.ads / signal_pkg.adb / timing_events_demo.adb में split होता है
--         gnatmake timing_events_demo.adb

pragma Locking_Policy (Ceiling_Locking);

with Ada.Text_IO;               use Ada.Text_IO;
with System;                    use System;
with Ada.Real_Time;             use Ada.Real_Time;
with Ada.Real_Time.Timing_Events; use Ada.Real_Time.Timing_Events;

package Signal_Pkg is
   protected type Signal_Type is
      pragma Priority (System.Interrupt_Priority'Last);
      entry Wait_For_Event;
      procedure Fire (Event : in out Timing_Event);
   private
      Fired : Boolean := False;
   end Signal_Type;

   S : Signal_Type;
end Signal_Pkg;

with Ada.Text_IO;               use Ada.Text_IO;
with System;                    use System;
with Ada.Real_Time;             use Ada.Real_Time;
with Ada.Real_Time.Timing_Events; use Ada.Real_Time.Timing_Events;

package body Signal_Pkg is
   protected body Signal_Type is
      entry Wait_For_Event when Fired is
      begin
         Fired := False;
      end Wait_For_Event;

      procedure Fire (Event : in out Timing_Event) is
      begin
         Fired := True;
      end Fire;
   end Signal_Type;
end Signal_Pkg;

with Signal_Pkg; use Signal_Pkg;

with Ada.Text_IO;               use Ada.Text_IO;
with System;                    use System;
with Ada.Real_Time;             use Ada.Real_Time;
with Ada.Real_Time.Timing_Events; use Ada.Real_Time.Timing_Events;

procedure Timing_Events_Demo is

   pragma Priority (29);

   Timer_1 : Timing_Event;
   Timer_2 : Timing_Event;

   task Reactor is
      pragma Priority (System.Default_Priority + 5);
      pragma Storage_Size (4 * 1024);
   end Reactor;

   task body Reactor is
   begin
      Put_Line ("[Reactor] Waiting for timing events...");

      S.Wait_For_Event;
      Put_Line ("[Reactor] Got event #1");

      S.Wait_For_Event;
      Put_Line ("[Reactor] Got event #2");

      Put_Line ("[Reactor] Done");
   end Reactor;

begin
   Put_Line ("=== Timing Events Demo ===");
   Put_Line ("Scheduling two timers at +100ms and +250ms...");

   Set_Handler (Timer_1, Clock + Milliseconds (100), S.Fire'Access);
   Set_Handler (Timer_2, Clock + Milliseconds (250), S.Fire'Access);

   delay until Clock + Milliseconds (500);
   Put_Line ("Main: done");
end Timing_Events_Demo;

Timing event कैसे चलता है:

1. Set_Handler(Timer_1, T+100ms, S.Fire'Access)  — absolute time पर handler register करें
2. T+100ms बीतते ही — runtime S.Fire को **ceiling priority** पर call करता है
3. Fire, Fired flag True करता है — barrier खुल जाता है
4. Reactor task Wait_For_Event से wake होता है

ज़रूरी बात: इस example में Ceiling_Locking explicit है, और Fire handler protected object की procedure है, इसलिए ceiling priority पर चलती है। Timing-event handler के रूप में इस्तेमाल होने वाली protected procedure interrupt-level ceiling priority वाले protected object पर रखें — यहाँ System.Interrupt_Priority'Last। इससे timing event के handling के दौरान priority inversion नहीं बनता।

8. Protected object से real-time queue

Real-time में बार-बार दिखने वाला pattern producer–consumer है। Sensor data बनाता है, control task उसे consume करता है — यहाँ buffer का mutual exclusion और blocking efficiently चाहिए।

Ada के protected object और entry barrier से इसे barrier-based synchronization की तरह लिख सकते हैं। अंदर runtime mutual exclusion संभालता है, इसलिए application code में mutex या condition variable सीधे लिखने की ज़रूरत नहीं।

-- 06_protected_queue.ada
-- Protected object से real-time data sharing
-- Pipeline: Producer -> Bounded_Buffer -> Consumer
-- Compile करते समय gnat.adc में pragma Locking_Policy (Ceiling_Locking); लिखें

pragma Locking_Policy (Ceiling_Locking);

with Ada.Text_IO;               use Ada.Text_IO;
with System;                    use System;
with Ada.Real_Time;             use Ada.Real_Time;

procedure Protected_Queue_Demo is

   Buffer_Size : constant := 4;

   type Buf_Array is array (1 .. Buffer_Size) of Integer;

   protected Bounded_Buffer is
      pragma Priority (System.Any_Priority'Last);
      entry Put (Item : Integer);
      entry Get (Item : out Integer);
   private
      Buf    : Buf_Array;
      Count  : Natural := 0;
      Head   : Positive := 1;
      Tail   : Positive := 1;
   end Bounded_Buffer;

   protected body Bounded_Buffer is
      entry Put (Item : Integer) when Count < Buffer_Size is
      begin
         Buf (Tail) := Item;
         Tail := (Tail mod Buffer_Size) + 1;
         Count := Count + 1;
      end Put;

      entry Get (Item : out Integer) when Count > 0 is
      begin
         Item := Buf (Head);
         Head := (Head mod Buffer_Size) + 1;
         Count := Count - 1;
      end Get;
   end Bounded_Buffer;

   task Producer is
      pragma Priority (System.Default_Priority + 2);
      pragma Storage_Size (4 * 1024);
   end Producer;

   task Consumer is
      pragma Priority (System.Default_Priority + 1);
      pragma Storage_Size (4 * 1024);
   end Consumer;

   task body Producer is
      Next_Release : Time := Clock + Milliseconds (50);
      Period       : constant Time_Span := Milliseconds (50);
   begin
      for I in 1 .. 6 loop
         Bounded_Buffer.Put (I);
         Put_Line ("[Producer] Put" & Integer'Image (I));
         delay until Next_Release;
         Next_Release := Next_Release + Period;
      end loop;
      Put_Line ("[Producer] Done");
   end Producer;

   task body Consumer is
      Item         : Integer;
      Next_Release : Time := Clock + Milliseconds (80);
      Period       : constant Time_Span := Milliseconds (80);
   begin
      delay until Clock + Milliseconds (30);
      for I in 1 .. 6 loop
         Bounded_Buffer.Get (Item);
         Put_Line ("[Consumer] Got" & Integer'Image (Item));
         delay until Next_Release;
         Next_Release := Next_Release + Period;
      end loop;
      Put_Line ("[Consumer] Done");
   end Consumer;

begin
   Put_Line ("=== Protected Queue Demo (Ceiling_Locking) ===");
   Put_Line ("Buffer size = 4; Producer every 50ms, Consumer every 80ms");
   delay until Clock + Milliseconds (800);
   Put_Line ("Main: done");
end Protected_Queue_Demo;

Design की मुख्य बातें:

  • entry Put when Count < Buffer_Size — buffer full हो तो Producer automatically block होता है।
  • entry Get when Count > 0 — buffer empty हो तो Consumer automatically block होता है।
  • pragma Priority (System.Any_Priority'Last) — ceiling locking से Producer और Consumer के बीच priority inversion नहीं बनता
  • Barrier condition protected object की internal state (Count) से defined है, और lock release पर automatically फिर evaluate होती है।

इस code में application-level mutex, semaphore, या condition variable नहीं है। ज़रूरी wait protected object के entry barrier से लिखा गया है।

Bounded buffer empty, partial, fullPut और Get barrier Count से empty, partial, full states के बीच ले जाते हैं; empty पर Get और full पर Put block होते हैं।Initial statePut (1 item जोड़ा)Put / GetGet (आखिरी item निकाला)Put (आखिरी खाली slot भरा)Get (एक slot खाली)Get block (barrier Count=0)Put block (barrier Count=Buffer_Size)खाली / Count=0कुछ items / Count=1..Buffer_Size-1Full / Count=Buffer_Size

Put सफल होने पर waiting Get, और Get सफल होने पर waiting Put की barrier फिर evaluate होती है। Diagram जिस state पर हो, protected operation complete होते ही यही होता है।

9. Execution time मापना — runtime monitoring का पहला कदम

Real-time system की schedulability आंकने के लिए हर task का execution time (CPU time) सही जानना ज़रूरी है। Ada का Ada.Execution_Time package per-task CPU consumption देता है।

-- 07_execution_time.ada
-- Execution time control (Execution_Time)
-- हर task का CPU time measure करना

with Ada.Text_IO;               use Ada.Text_IO;
with System;                    use System;
with Ada.Real_Time;             use Ada.Real_Time;
with Ada.Execution_Time;
use type Ada.Execution_Time.CPU_Time;

procedure Execution_Time_Demo is

   package ET renames Ada.Execution_Time;

   task Busy_Worker is
      pragma Priority (System.Default_Priority + 1);
      pragma Storage_Size (4 * 1024);
   end Busy_Worker;

   task body Busy_Worker is
      Wall_Start : Time;
      Cpu_Start  : ET.CPU_Time;
      Dummy      : Integer := 0;
      pragma Volatile (Dummy);
   begin
      Wall_Start := Clock;
      Cpu_Start := ET.Clock;

      Put_Line ("[Worker] Starting compute-bound work...");
      for I in 1 .. 20_000_000 loop
         Dummy := Dummy + 1;
      end loop;
      Put_Line ("[Worker] Dummy =" & Integer'Image (Dummy));

      declare
         Wall_Elapsed : constant Duration :=
            To_Duration (Clock - Wall_Start);
         Cpu_Span     : constant Time_Span :=
            ET.Clock - Cpu_Start;
      begin
         Put_Line ("[Worker] Done, wall time:" &
                   Duration'Image (Wall_Elapsed) & "s");
         Put_Line ("[Worker] CPU time consumed:" &
                   Duration'Image (To_Duration (Cpu_Span)) & "s");
      end;
   end Busy_Worker;

   Cpu_Start_Main : constant ET.CPU_Time := ET.Clock;

begin
   Put_Line ("=== Execution Time Demo ===");

   delay until Clock + Milliseconds (500);

   declare
      Cpu_Span : constant Time_Span := ET.Clock - Cpu_Start_Main;
   begin
      Put_Line ("Main: CPU time consumed after 500ms:" &
                Duration'Image (To_Duration (Cpu_Span)) & "s");
   end;

   Put_Line ("Main: done");
end Execution_Time_Demo;

Wall-clock time बनाम CPU time:

Wall-clock time (Wall Clock): Ada.Real_Time.Clock
  → असल elapsed time। Blocked या preempted रहने का समय भी शामिल है।

CPU time (Execution Time): Ada.Execution_Time.Clock
  → सिर्फ़ वह समय जब task CPU पर वास्तव में चल रहा था।
  → Blocked / preempted time count नहीं होता।

यह फ़र्क execution-time monitoring और WCET validation की शुरुआत है। Busy_Worker जब delay until पर wait करता है तो CPU time नहीं बढ़ता — सिर्फ़ असल computation के दौरान बढ़ता है। Main task के delay until Clock + Milliseconds(500) के दौरान भी CPU time लगभग शून्य होना चाहिए। हाँ, CPU time का measurement true WCET guarantee नहीं करता। Cache, pipeline, memory contention समेत WCET के लिए अलग से static analysis या target पर validation चाहिए।

Wall-clock time बनाम CPU timeWall clock में wait, block, preemption शामिल हैं; CPU time सिर्फ़ असल computation गिनता है, measurement true WCET नहीं है।CPU timeBreakdown: actual computation onlyCPU total: 120msWall-clock timeBreakdown: compute + wait + blocked + preemptedElapsed total: 500msफ़र्क = wait / block / preemption timeCPU time असल compute cost देखता हैWCET validation और monitoring में सहायकWait, block, preemption time निकाल देता हैसावधानीMeasurement true WCET guarantee नहीं करताStatic analysis या target validation जरूरी है

10. Integration demo — multi-periodic real-time system

अब तक के सारे टुकड़े — priority, Ceiling_Locking, delay until, protected object — जोड़कर एक typical multi-periodic real-time system बनाते हैं।

-- 08_multiperiodic.ada
-- Multi-periodic real-time system का integration demo
-- Fast period (100ms) वाला sensor-read task
-- Slow period (400ms) वाला control task
-- Ceiling_Locking से data sharing

pragma Locking_Policy (Ceiling_Locking);

with Ada.Text_IO;               use Ada.Text_IO;
with System;                    use System;
with Ada.Real_Time;             use Ada.Real_Time;

procedure Multiperiodic_Demo is

   package Int_IO is new Ada.Text_IO.Integer_IO (Integer);

   protected Shared_Sensor is
      pragma Priority (System.Any_Priority'Last);
      procedure Write (V : Integer);
      function Read return Integer;
   private
      Value : Integer := 0;
   end Shared_Sensor;

   protected body Shared_Sensor is
      procedure Write (V : Integer) is
      begin
         Value := V;
      end Write;

      function Read return Integer is
      begin
         return Value;
      end Read;
   end Shared_Sensor;

   task Fast_Sensor is
      pragma Priority (System.Default_Priority + 3);
      pragma Storage_Size (4 * 1024);
   end Fast_Sensor;

   task body Fast_Sensor is
      Next_Release : Time := Clock + Milliseconds (100);
      Period       : constant Time_Span := Milliseconds (100);
      Cycle        : Natural := 0;
   begin
      Put_Line ("[Fast] Sensor reader starts (100ms period)");

      for I in 1 .. 12 loop
         delay until Next_Release;
         Cycle := Cycle + 1;
         Shared_Sensor.Write (Cycle * 10);
         Next_Release := Next_Release + Period;
      end loop;
      Put_Line ("[Fast] Done");
   end Fast_Sensor;

   task Slow_Controller is
      pragma Priority (System.Default_Priority + 2);
      pragma Storage_Size (4 * 1024);
   end Slow_Controller;

   task body Slow_Controller is
      Next_Release : Time := Clock + Milliseconds (150);
      Period       : constant Time_Span := Milliseconds (400);
      Cycle        : Natural := 0;
      Raw          : Integer;
   begin
      Put_Line ("[Slow] Controller starts (400ms period)");

      for I in 1 .. 3 loop
         delay until Next_Release;
         Cycle := Cycle + 1;
         Raw := Shared_Sensor.Read;
         Put_Line ("[Slow] Cycle" & Natural'Image (Cycle) &
                   " reads sensor =" & Integer'Image (Raw));
         Next_Release := Next_Release + Period;
      end loop;
      Put_Line ("[Slow] Done");
   end Slow_Controller;

begin
   Put_Line ("=== Multiperiodic Real-Time System Demo ===");
   Put_Line ("Fast sensor (100ms) x 12 + Slow controller (400ms) x 3");
   Put_Line ("Ceiling_Locking prevents priority inversion on shared data");
   delay until Clock + Milliseconds (2000);
   Put_Line ("Main: done");
end Multiperiodic_Demo;

System की बनावट:

नीचे वाला diagram sample code के release times (fast sensor 100ms period, slow control 150ms offset पर 400ms period) पर, समझाने के लिए execution times मानकर बना schedule है। Code में 80ms का control computation नहीं है, इसलिए यह measured trace नहीं। Fast sensor की priority ऊँची हो तो slow control के चलते हुए fast sensor का release आने पर slow control बीच में रुकता है। Diagram में पढ़ने की आसानी के लिए हर slow-control cycle पर एक representative preemption दिखाई है; असल run में हर 100ms boundary पर fast sensor release होता है।

Fast sensor और slow control का illustrative schedule100ms fast sensor ऊँची priority से 400ms slow control को preempt करता है; हर slow cycle पर एक representative preemption दिखाई है।Slow control cycle 3 (release=950ms)Slow control cycle 2 (release=550ms)Slow control cycle 1 (release=150ms)1000-1010msFast sensor #10P+3 इसलिए preempt950-1000msSlow control #3 part A1010-1040msSlow control #3 part B600-610msFast sensor #6P+3 इसलिए preempt550-600msSlow control #2 part A610-640msSlow control #2 part B150-200msSlow control #1 part A100-110msFast sensor #1200-210msFast sensor #2P+3 इसलिए preempt210-240msSlow control #1 part BExample assumptionFast sensor: 10ms workSlow control: 80ms work

यह pattern industrial control और robot control में आम “fast sensor acquisition + slow control loop” की typical संरचना है।

11. जहाँ Ada के real-time features काम आते हैं

Ada के real-time features इन क्षेत्रों में खास मूल्य देते हैं।

Annex D जिन domains में काम आता हैAda Annex D aerospace, railway, automotive, medical devices, industrial control और defense में safety standards के साथ जुड़ता है।Ada Annex DReal-time featuresAerospaceDO-178CRailwayEN 50128 familyAutomotiveISO 26262Medical devicesIEC 62304Industrial controlIEC 61508 familyDefense / high-integrity systemsFlight controlProven application areaSatellite / spacecraft controlSignalling systemsAutomatic train controlSafety-related ECU candidateC / MISRA-C वाले mainstream मेंlimited, selective usePacemakerInfusion pumpRobot controlNC machine toolsMission computersLong-life operational systems

Diagram में सिर्फ़ automotive पर “limited, selective use” लिखा है, क्योंकि वजह भाषा की fitment से ज़्यादा existing ecosystem का आकार है। Vehicle software में AUTOSAR जैसे industry-standard API, supplier से आने वाला code, certified compiler और verification tools, और engineers की आबादी तक — सब C और MISRA-C को आधार मानकर जमा हुआ है। भाषा बदलना, भले एक component की बात हो, उसके आसपास के tools, procurement और verification process को एक साथ फिर से खड़ा करने के बराबर है। इसलिए Ada पूरे vehicle का default बनने से ज़्यादा, खास तौर पर ऊँची guarantee चाहिए वाले कुछ components पर, या जहाँ Ada की assets और development setup पहले से है, वहाँ selective रूप से इस्तेमाल होती है। इसका उलटा यह है कि aerospace और railway जैसे क्षेत्रों में, जहाँ ecosystem पहले से high-integrity तरफ झुका है, यह रुकावट शुरू से नहीं होती।

12. सावधानियाँ और सीमाएँ

Ada के real-time features शक्तिशाली हैं, लेकिन हर problem का हल नहीं।

1. Platform dependence:

  • pragma Priority का असल mapping execution environment (OS + GNAT runtime) पर depend करता है। Linux पर यह SCHED_FIFO पर map होता है, लेकिन Windows पर पूरी preemption guarantee नहीं हो सकती।

2. Ravenscar की सीमाएँ:

  • Dynamic task creation मना है, इसलिए startup पर सभी tasks statically declare करने पड़ते हैं। इससे design की आज़ादी सीमित होती है।

3. WCET measurement की सीमा:

  • Ada.Execution_Time measurement है, guarantee नहीं। Cache miss और pipeline hazard समेत true WCET static analysis tools से अलग verify करना पड़ता है।

4. Overhead:

  • Protected object की barrier evaluation entry complete/cancel होने पर, और protected object से निकलते समय automatically चलती है। बार-बार call होने वाले protected objects पर इस overhead का हिसाब रखना चाहिए।

5. Toolchain barrier:

  • Ada के real-time features पूरा इस्तेमाल करने के लिए सही cross-compiler और runtime चाहिए। खासकर embedded targets पर vendor-supplied runtime पर depend रहना पड़ता है।

13. सार

इस लेख में Ada Annex D के real-time features 8 code examples से step-by-step देखे।

Feature क्या देता है
Task priority Preemptive, priority-based scheduling
Ceiling_Locking Language में बसी priority inversion prevention
delay until Cumulative drift रोके periodic execution
Ravenscar profile Static analysis के अनुकूल tasking subset
Timing events बिना polling के time-driven wakeup
Protected queue Protected object की barrier-based synchronization
Execution time measurement Per-task CPU time monitoring
Multi-periodic integration अलग-अलग periods वाले tasks को साथ चलाने का design

Ada के real-time features का सार यही है कि वे बाद में जोड़े गए नहीं हैं। Priority inversion दबाने वाले locking नियम, periodic execution के लिए absolute time, execution-time monitoring — ये language specification का हिस्सा हैं। Deadline हासिल करना अभी भी design और analysis से confirm होता है, लेकिन उसके लिए ज़रूरी आधार language runtime दे देता है — यही बड़ी ताकत है।

अगला कदम: Ada में real-time development खुद आज़माने के लिए Alire से GNAT toolchain install करें, और इस लेख का sample code gnatchop + gnatmake से build करें।

Ada concurrency की basics (task, rendezvous, protected object) पिछले लेख “Ada में सुरक्षित concurrency” में हैं।

14. संदर्भ

निकटवर्ती विषयों में गहराई से जाने के लिए समान टैग वाले नवीनतम लेख।

ये पृष्ठ विषय को सेवाओं और निर्णयों के व्यापक संदर्भ में रखते हैं।

अक्सर पूछे जाने वाले प्रश्न

इस लेख के विषय पर परामर्श में अक्सर पूछे जाने वाले प्रश्न।

Ada का Annex D क्या है?
Ada language specification का हिस्सा, real-time systems के लिए standard किया गया feature set है। इसमें FIFO_Within_Priorities से priority-based preemptive scheduling, priority inversion रोकने वाला Ceiling_Locking protocol, delay until से absolute time पर periodic execution, Ravenscar profile, timing events, और Ada.Execution_Time से per-task execution time measurement शामिल हैं। खास बात यह है कि ये किसी library से बाद में जोड़े नहीं गए — language runtime में ही बने हैं।
Priority inversion क्या है? Ada इसे कैसे रोकती है?
Low-priority task lock hold किए हुए रहता है, उसे medium-priority task preempt कर देता है, और उसी lock की wait कर रहा high-priority task अनिश्चित काल तक block रह जाता है — यही priority inversion है। 1997 में Mars Pathfinder पर यही हुआ और spacecraft बार-बार reset होता रहा। Ada में Ceiling_Locking protocol language feature है: protected object enter करते ही task automatically ceiling priority पर उठ जाता है, इसलिए medium-priority task उसे preempt नहीं कर पाता।
Ravenscar profile क्या है?
Safety-critical systems के लिए Ada के tasking को statically analyzable, deterministic subset तक सीमित करने वाला profile है। Dynamic task creation, select statement, abort statement, relative delay, requeue statement वगैरह मना हैं। इन restrictions से static timing analysis आसान होता है, और DO-178C (aviation software) या ISO 26262 (automotive functional safety) जैसे safety standards की properties पूरा करना आसान पड़ता है। GNAT में gnat.adc में pragma Profile (Ravenscar) लिखकर इसे enable करते हैं।
Periodic task में delay की जगह delay until क्यों?
Relative delay में हर iteration का processing time जुड़ता जाता है, इसलिए period धीरे-धीरे खिसकती है — cumulative drift। delay until अगला release time absolute time से तय करता है, इसलिए एक बार processing देर से चली तो भी बाद के release times सही रहते हैं। हाँ, अगर processing अगले wake time को पार कर जाए तो delay until लगभग तुरंत लौट आता है; उसे deadline miss मानकर overload की तरह handle करने का अलग design चाहिए।

लेखक की प्रोफ़ाइल

लेख के लेखक का परिचय पृष्ठ।

Go Komura

KomuraSoft LLC के प्रतिनिधि

Windows सॉफ़्टवेयर विकास, तकनीकी परामर्श और बग जाँच में विशेषज्ञ, विशेष रूप से मौजूदा सिस्टम वाली परियोजनाओं और पुनरुत्पादन में कठिन बग में।

सार्वजनिक लिंक

ब्लॉग पर लौटें