A2Sequencers.Mod 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. MODULE A2Sequencers; (** AUTHOR "negelef"; PURPOSE "Generic A2 Sequencer"; *)
  2. (*
  3. This module provides a generic sequencer base class that allows deriving active objects to communicate sequentially over messages.
  4. Messages are handled sequentially and provide atomic and exclusive access to the state of a sequencer. Requests are special messages
  5. which allow the caller to block and wait for the sequencer to handle the request. This is useful to retrieve a set of states of the sequencer.
  6. Code in procedures of a sequencer must make sure that they are called by their own sequencer object (using the SequencerCalledThis
  7. procedure) and have to add a corresponding message otherwise. If sequencers share variables, they can also put it into property objects
  8. which support atomic access to their values and a registration mechanism for notification handlers.
  9. *)
  10. IMPORT Machine, Streams, Objects, Kernel;
  11. CONST
  12. NoDelay* = 0;
  13. MaxHandlers = 10;
  14. TYPE
  15. (* generic property object that provides lock-free access to its value *)
  16. Property* = OBJECT
  17. VAR
  18. locks: WORD;
  19. container*: OBJECT;
  20. PROCEDURE &InitProperty;
  21. BEGIN locks := 0; container := NIL;
  22. END InitProperty;
  23. PROCEDURE AcquireRead;
  24. VAR locks: WORD;
  25. BEGIN
  26. LOOP
  27. locks := SELF.locks;
  28. IF (locks >= 0) & (Machine.AtomicCAS (SELF.locks, locks, locks + 1) = locks) THEN EXIT END;
  29. Objects.Yield;
  30. END;
  31. END AcquireRead;
  32. PROCEDURE ReleaseRead;
  33. BEGIN Machine.AtomicDec (locks);
  34. END ReleaseRead;
  35. PROCEDURE AcquireWrite;
  36. VAR locks: WORD;
  37. BEGIN
  38. LOOP
  39. locks := SELF.locks;
  40. IF (locks = 0) & (Machine.AtomicCAS (SELF.locks, locks, locks - 1) = locks) THEN EXIT END;
  41. Objects.Yield;
  42. END;
  43. END AcquireWrite;
  44. PROCEDURE ReleaseWrite;
  45. BEGIN Machine.AtomicInc (locks);
  46. END ReleaseWrite;
  47. PROCEDURE ToStream*(w : Streams.Writer);
  48. END ToStream; (* abstract *)
  49. PROCEDURE FromStream*(r : Streams.Reader);
  50. END FromStream; (* abstract *)
  51. END Property;
  52. Boolean* = OBJECT (Property)
  53. VAR
  54. value: BOOLEAN;
  55. handlers: ARRAY MaxHandlers OF BooleanHandler;
  56. PROCEDURE &InitBoolean* (value: BOOLEAN);
  57. BEGIN InitProperty; SELF.value := value;
  58. END InitBoolean;
  59. PROCEDURE Get* (): BOOLEAN;
  60. VAR value: BOOLEAN;
  61. BEGIN AcquireRead; value := SELF.value; ReleaseRead; RETURN value;
  62. END Get;
  63. PROCEDURE Set* (value: BOOLEAN);
  64. VAR changed: BOOLEAN;
  65. BEGIN AcquireWrite; changed := SELF.value # value; SELF.value := value; ReleaseWrite; IF changed THEN Changed (value) END;
  66. END Set;
  67. PROCEDURE Changed (value: BOOLEAN);
  68. VAR i: SIZE;
  69. BEGIN i := 0; WHILE handlers[i] # NIL DO handlers[i] (SELF, value); INC (i) END;
  70. END Changed;
  71. PROCEDURE AddHandler* (handler: BooleanHandler);
  72. VAR i: SIZE;
  73. BEGIN i := 0; WHILE handlers[i] # NIL DO INC (i) END; handlers[i] := handler;
  74. END AddHandler;
  75. END Boolean;
  76. Integer* = OBJECT (Property)
  77. VAR
  78. value: WORD;
  79. handlers: ARRAY MaxHandlers OF IntegerHandler;
  80. PROCEDURE &InitInteger* (value: WORD);
  81. BEGIN InitProperty; SELF.value := value;
  82. END InitInteger;
  83. PROCEDURE Get* (): WORD;
  84. VAR value: WORD;
  85. BEGIN AcquireRead; value := SELF.value; ReleaseRead; RETURN value;
  86. END Get;
  87. PROCEDURE Set* (value: WORD);
  88. VAR changed: BOOLEAN;
  89. BEGIN AcquireWrite; changed := SELF.value # value; SELF.value := value; ReleaseWrite; IF changed THEN Changed (value) END;
  90. END Set;
  91. PROCEDURE Inc* (step: WORD);
  92. VAR changed: BOOLEAN;
  93. BEGIN AcquireWrite; changed := step # 0; INC (value, step); ReleaseWrite; IF changed THEN Changed (value) END;
  94. END Inc;
  95. PROCEDURE Dec* (step: WORD);
  96. VAR changed: BOOLEAN;
  97. BEGIN AcquireWrite; changed := step # 0; DEC (value, step); ReleaseWrite; IF changed THEN Changed (value) END;
  98. END Dec;
  99. PROCEDURE Changed (value: WORD);
  100. VAR i: SIZE;
  101. BEGIN i := 0; WHILE handlers[i] # NIL DO handlers[i] (SELF, value); INC (i) END;
  102. END Changed;
  103. PROCEDURE AddHandler* (handler: IntegerHandler);
  104. VAR i: SIZE;
  105. BEGIN i := 0; WHILE handlers[i] # NIL DO INC (i) END; handlers[i] := handler;
  106. END AddHandler;
  107. END Integer;
  108. Real* = OBJECT (Property)
  109. VAR
  110. value: REAL;
  111. handlers: ARRAY MaxHandlers OF RealHandler;
  112. PROCEDURE &InitReal* (value: REAL);
  113. BEGIN InitProperty; SELF.value := value;
  114. END InitReal;
  115. PROCEDURE Get* (): REAL;
  116. VAR value: REAL;
  117. BEGIN AcquireRead; value := SELF.value; ReleaseRead; RETURN value;
  118. END Get;
  119. PROCEDURE Set* (value: REAL);
  120. VAR changed: BOOLEAN;
  121. BEGIN AcquireWrite; changed := SELF.value # value; SELF.value := value; ReleaseWrite; IF changed THEN Changed (value) END;
  122. END Set;
  123. PROCEDURE Changed (value: REAL);
  124. VAR i: SIZE;
  125. BEGIN i := 0; WHILE handlers[i] # NIL DO handlers[i] (SELF, value); INC (i) END;
  126. END Changed;
  127. PROCEDURE AddHandler* (handler: RealHandler);
  128. VAR i: SIZE;
  129. BEGIN i := 0; WHILE handlers[i] # NIL DO INC (i) END; handlers[i] := handler;
  130. END AddHandler;
  131. END Real;
  132. Set* = OBJECT (Property)
  133. VAR
  134. value: SET;
  135. handlers: ARRAY MaxHandlers OF SetHandler;
  136. PROCEDURE &InitSet* (value: SET);
  137. BEGIN InitProperty; SELF.value := value;
  138. END InitSet;
  139. PROCEDURE Get* (): SET;
  140. VAR value: SET;
  141. BEGIN AcquireRead; value := SELF.value; ReleaseRead; RETURN value;
  142. END Get;
  143. PROCEDURE Set* (value: SET);
  144. VAR changed: BOOLEAN;
  145. BEGIN AcquireWrite; changed := SELF.value # value; SELF.value := value; ReleaseWrite; IF changed THEN Changed (value) END;
  146. END Set;
  147. PROCEDURE Incl* (element: WORD);
  148. VAR changed: BOOLEAN;
  149. BEGIN AcquireWrite; changed := ~(element IN value); INCL (value, element); ReleaseWrite; IF changed THEN Changed (value) END;
  150. END Incl;
  151. PROCEDURE Excl* (element: WORD);
  152. VAR changed: BOOLEAN;
  153. BEGIN AcquireWrite; changed := element IN value; EXCL (value, element); ReleaseWrite; IF changed THEN Changed (value) END;
  154. END Excl;
  155. PROCEDURE Changed (value: SET);
  156. VAR i: SIZE;
  157. BEGIN i := 0; WHILE handlers[i] # NIL DO handlers[i] (SELF, value); INC (i) END;
  158. END Changed;
  159. PROCEDURE AddHandler* (handler: SetHandler);
  160. VAR i: SIZE;
  161. BEGIN i := 0; WHILE handlers[i] # NIL DO INC (i) END; handlers[i] := handler;
  162. END AddHandler;
  163. END Set;
  164. String* = OBJECT (Property)
  165. VAR
  166. value: POINTER TO ARRAY OF CHAR;
  167. handlers: ARRAY MaxHandlers OF StringHandler;
  168. PROCEDURE &InitString* (CONST value: ARRAY OF CHAR; length: SIZE);
  169. BEGIN InitProperty; NEW (SELF.value, length); COPY (value, SELF.value^);
  170. END InitString;
  171. PROCEDURE Get* (VAR value: ARRAY OF CHAR);
  172. BEGIN AcquireRead; COPY (SELF.value^, value); ReleaseRead;
  173. END Get;
  174. PROCEDURE Set* (CONST value: ARRAY OF CHAR);
  175. VAR changed: BOOLEAN;
  176. BEGIN AcquireWrite; changed := SELF.value^ # value; COPY (value, SELF.value^); ReleaseWrite; IF changed THEN Changed (value) END;
  177. END Set;
  178. PROCEDURE Changed (CONST value: ARRAY OF CHAR);
  179. VAR i: SIZE;
  180. BEGIN i := 0; WHILE handlers[i] # NIL DO handlers[i] (SELF, value); INC (i) END;
  181. END Changed;
  182. PROCEDURE AddHandler* (handler: StringHandler);
  183. VAR i: SIZE;
  184. BEGIN i := 0; WHILE handlers[i] # NIL DO INC (i) END; handlers[i] := handler;
  185. END AddHandler;
  186. END String;
  187. (* generic message to be handled by the sequencer *)
  188. Message* = OBJECT
  189. VAR
  190. next: Message; time: LONGINT;
  191. PROCEDURE &InitMessage*;
  192. BEGIN SELF.next := NIL; time := NoDelay;
  193. END InitMessage;
  194. PROCEDURE Handle*;
  195. END Handle; (* abstract *)
  196. END Message;
  197. TYPE ProcedureMessage* = OBJECT (Message)
  198. VAR
  199. procedure: Procedure;
  200. PROCEDURE &InitProcedureMessage* (procedure: Procedure);
  201. BEGIN InitMessage; SELF.procedure := procedure;
  202. END InitProcedureMessage;
  203. PROCEDURE Handle*;
  204. BEGIN procedure;
  205. END Handle;
  206. END ProcedureMessage;
  207. TYPE BooleanMessage* = OBJECT (Message)
  208. VAR
  209. value: BOOLEAN;
  210. procedure: BooleanProcedure;
  211. PROCEDURE &InitBooleanMessage* (value: BOOLEAN; procedure: BooleanProcedure);
  212. BEGIN InitMessage; SELF.value := value; SELF.procedure := procedure;
  213. END InitBooleanMessage;
  214. PROCEDURE Handle*;
  215. BEGIN procedure (value);
  216. END Handle;
  217. END BooleanMessage;
  218. TYPE IntegerMessage* = OBJECT (Message)
  219. VAR
  220. value: WORD;
  221. procedure: IntegerProcedure;
  222. PROCEDURE &InitIntegerMessage* (value: WORD; procedure: IntegerProcedure);
  223. BEGIN InitMessage; SELF.value := value; SELF.procedure := procedure;
  224. END InitIntegerMessage;
  225. PROCEDURE Handle*;
  226. BEGIN procedure (value);
  227. END Handle;
  228. END IntegerMessage;
  229. TYPE IntegerIntegerMessage* = OBJECT (Message)
  230. VAR
  231. value0, value1: WORD;
  232. procedure: IntegerIntegerProcedure;
  233. PROCEDURE &InitIntegerIntegerMessage* (value0, value1: WORD; procedure: IntegerIntegerProcedure);
  234. BEGIN InitMessage; SELF.value0 := value0; SELF.value1 := value1; SELF.procedure := procedure;
  235. END InitIntegerIntegerMessage;
  236. PROCEDURE Handle*;
  237. BEGIN procedure (value0, value1);
  238. END Handle;
  239. END IntegerIntegerMessage;
  240. TYPE RealMessage* = OBJECT (Message)
  241. VAR
  242. value: REAL;
  243. procedure: RealProcedure;
  244. PROCEDURE &InitRealMessage* (value: REAL; procedure: RealProcedure);
  245. BEGIN InitMessage; SELF.value := value; SELF.procedure := procedure;
  246. END InitRealMessage;
  247. PROCEDURE Handle*;
  248. BEGIN procedure (value);
  249. END Handle;
  250. END RealMessage;
  251. TYPE SetMessage* = OBJECT (Message)
  252. VAR
  253. value: SET;
  254. procedure: SetProcedure;
  255. PROCEDURE &InitSetMessage* (value: SET; procedure: SetProcedure);
  256. BEGIN InitMessage; SELF.value := value; SELF.procedure := procedure;
  257. END InitSetMessage;
  258. PROCEDURE Handle*;
  259. BEGIN procedure (value);
  260. END Handle;
  261. END SetMessage;
  262. TYPE StringMessage* = OBJECT (Message)
  263. VAR
  264. value: POINTER TO ARRAY OF CHAR;
  265. procedure: StringProcedure;
  266. PROCEDURE &InitStringMessage* (CONST value: ARRAY OF CHAR; procedure: StringProcedure);
  267. VAR length: SIZE;
  268. BEGIN
  269. InitMessage; length := 0;
  270. WHILE value[length] # 0X DO INC (length); END;
  271. NEW (SELF.value, length); COPY (value, SELF.value^); SELF.procedure := procedure;
  272. END InitStringMessage;
  273. PROCEDURE Handle*;
  274. BEGIN procedure (value^);
  275. END Handle;
  276. END StringMessage;
  277. (* generic request that allows to wait for the message to be handled*)
  278. Request* = OBJECT (Message)
  279. VAR
  280. handled: BOOLEAN;
  281. PROCEDURE &InitRequest*;
  282. BEGIN InitMessage; handled := FALSE;
  283. END InitRequest;
  284. (* IMPORTANT: to be called at the end of overriding procedures *)
  285. PROCEDURE Handle*;
  286. BEGIN {EXCLUSIVE} handled := TRUE
  287. END Handle;
  288. (* awaits handling by sequencer *)
  289. PROCEDURE Await;
  290. BEGIN {EXCLUSIVE} AWAIT (handled);
  291. END Await;
  292. END Request;
  293. IntegerRequest* = OBJECT (Request)
  294. VAR
  295. value: WORD;
  296. procedure: IntegerProcedure;
  297. PROCEDURE &InitIntegerRequest* (value: WORD; procedure: IntegerProcedure);
  298. BEGIN InitRequest; SELF.value := value; SELF.procedure := procedure;
  299. END InitIntegerRequest;
  300. PROCEDURE Handle*;
  301. BEGIN procedure (value); Handle^;
  302. END Handle;
  303. END IntegerRequest;
  304. RequestBoolean* = OBJECT (Request)
  305. VAR
  306. procedure: ProcedureBoolean;
  307. result-: BOOLEAN;
  308. PROCEDURE &InitRequestBoolean* (procedure: ProcedureBoolean);
  309. BEGIN InitRequest; SELF.procedure := procedure;
  310. END InitRequestBoolean;
  311. PROCEDURE Handle*;
  312. BEGIN result := procedure (); Handle^;
  313. END Handle;
  314. END RequestBoolean;
  315. RequestInteger* = OBJECT (Request)
  316. VAR
  317. procedure: ProcedureInteger;
  318. result-: WORD;
  319. PROCEDURE &InitRequestInteger* (procedure: ProcedureInteger);
  320. BEGIN InitRequest; SELF.procedure := procedure;
  321. END InitRequestInteger;
  322. PROCEDURE Handle*;
  323. BEGIN result := procedure (); Handle^;
  324. END Handle;
  325. END RequestInteger;
  326. RequestReal* = OBJECT (Request)
  327. VAR
  328. procedure: ProcedureReal;
  329. result-: REAL;
  330. PROCEDURE &InitRequestReal* (procedure: ProcedureReal);
  331. BEGIN InitRequest; SELF.procedure := procedure;
  332. END InitRequestReal;
  333. PROCEDURE Handle*;
  334. BEGIN result := procedure (); Handle^;
  335. END Handle;
  336. END RequestReal;
  337. IntegerRequestBoolean* = OBJECT (Request)
  338. VAR
  339. value: WORD;
  340. procedure: IntegerProcedureBoolean;
  341. result-: BOOLEAN;
  342. PROCEDURE &InitIntegerRequestBoolean* (value: WORD; procedure: IntegerProcedureBoolean);
  343. BEGIN InitRequest; SELF.value := value; SELF.procedure := procedure;
  344. END InitIntegerRequestBoolean;
  345. PROCEDURE Handle*;
  346. BEGIN result := procedure (value); Handle^;
  347. END Handle;
  348. END IntegerRequestBoolean;
  349. RealRequestInteger* = OBJECT (Request)
  350. VAR
  351. value: REAL;
  352. procedure: RealProcedureInteger;
  353. result-: WORD;
  354. PROCEDURE &InitRealRequestInteger* (value: REAL; procedure: RealProcedureInteger);
  355. BEGIN InitRequest; SELF.value := value; SELF.procedure := procedure;
  356. END InitRealRequestInteger;
  357. PROCEDURE Handle*;
  358. BEGIN result := procedure (value); Handle^;
  359. END Handle;
  360. END RealRequestInteger;
  361. (* generic base message sequencer class *)
  362. Sequencer* = OBJECT
  363. VAR
  364. handling, woken: BOOLEAN; first: Message; timer: Objects.Timer;
  365. PROCEDURE &InitSequencer*;
  366. BEGIN handling := TRUE; woken := FALSE; first := NIL; NEW (timer);
  367. END InitSequencer;
  368. (* check wether current procedure was called by sequencer or by other active objects *)
  369. PROCEDURE SequencerCalledThis* (): BOOLEAN;
  370. BEGIN RETURN Objects.ActiveObject() = SELF;
  371. END SequencerCalledThis;
  372. PROCEDURE HandleMessages;
  373. VAR message: Message;
  374. BEGIN {EXCLUSIVE}
  375. WHILE first # NIL DO
  376. IF (first.time # NoDelay) & (first.time - Kernel.GetTicks () > 0) THEN RETURN END;
  377. message := first; first := message.next; message.next := NIL; message.Handle;
  378. END;
  379. END HandleMessages;
  380. PROCEDURE Add*(message: Message; time: LONGINT);
  381. VAR prev, next: Message;
  382. BEGIN
  383. BEGIN {EXCLUSIVE}
  384. ASSERT (~SequencerCalledThis ());
  385. ASSERT (message.next = NIL);
  386. prev := NIL; next := first;
  387. WHILE (next # NIL) & (next.time <= time) DO prev := next; next := next.next END;
  388. IF prev = NIL THEN first := message; woken := time # NoDelay; ELSE prev.next := message END;
  389. message.next := next; message.time := time;
  390. END;
  391. IF message IS Request THEN message(Request).Await END;
  392. END Add;
  393. PROCEDURE AddMessage* (procedure: Procedure);
  394. VAR message: ProcedureMessage;
  395. BEGIN NEW (message, procedure); Add (message, NoDelay);
  396. END AddMessage;
  397. PROCEDURE AddBooleanMessage* (value: BOOLEAN; procedure: BooleanProcedure);
  398. VAR message: BooleanMessage;
  399. BEGIN NEW (message, value, procedure); Add (message, NoDelay);
  400. END AddBooleanMessage;
  401. PROCEDURE AddIntegerMessage* (value: WORD; procedure: IntegerProcedure);
  402. VAR message: IntegerMessage;
  403. BEGIN NEW (message, value, procedure); Add (message, NoDelay);
  404. END AddIntegerMessage;
  405. PROCEDURE AddRealMessage* (value: REAL; procedure: RealProcedure);
  406. VAR message: RealMessage;
  407. BEGIN NEW (message, value, procedure); Add (message, NoDelay);
  408. END AddRealMessage;
  409. PROCEDURE AddSetMessage* (value: SET; procedure: SetProcedure);
  410. VAR message: SetMessage;
  411. BEGIN NEW (message, value, procedure); Add (message, NoDelay);
  412. END AddSetMessage;
  413. PROCEDURE AddStringMessage* (CONST value: ARRAY OF CHAR; procedure: StringProcedure);
  414. VAR message: StringMessage;
  415. BEGIN NEW (message, value, procedure); Add (message, NoDelay);
  416. END AddStringMessage;
  417. PROCEDURE AddIntegerIntegerMessage* (value0, value1: WORD; procedure: IntegerIntegerProcedure);
  418. VAR message: IntegerIntegerMessage;
  419. BEGIN NEW (message, value0, value1, procedure); Add (message, NoDelay);
  420. END AddIntegerIntegerMessage;
  421. PROCEDURE AddIntegerRequest* (value: WORD; procedure: IntegerProcedure);
  422. VAR request: IntegerRequest;
  423. BEGIN NEW (request, value, procedure); Add (request, NoDelay);
  424. END AddIntegerRequest;
  425. PROCEDURE AddRequestBoolean* (procedure: ProcedureBoolean): BOOLEAN;
  426. VAR request: RequestBoolean;
  427. BEGIN NEW (request, procedure); Add (request, NoDelay); RETURN request.result;
  428. END AddRequestBoolean;
  429. PROCEDURE AddRequestInteger* (procedure: ProcedureInteger): WORD;
  430. VAR request: RequestInteger;
  431. BEGIN NEW (request, procedure); Add (request, NoDelay); RETURN request.result;
  432. END AddRequestInteger;
  433. PROCEDURE AddRequestReal* (procedure: ProcedureReal): REAL;
  434. VAR request: RequestReal;
  435. BEGIN NEW (request, procedure); Add (request, NoDelay); RETURN request.result;
  436. END AddRequestReal;
  437. PROCEDURE AddIntegerRequestBoolean* (value: WORD; procedure: IntegerProcedureBoolean): BOOLEAN;
  438. VAR request: IntegerRequestBoolean;
  439. BEGIN NEW (request, value, procedure); Add (request, NoDelay); RETURN request.result;
  440. END AddIntegerRequestBoolean;
  441. PROCEDURE AddRealRequestInteger* (value: REAL; procedure: RealProcedureInteger): WORD;
  442. VAR request: RealRequestInteger;
  443. BEGIN NEW (request, value, procedure); Add (request, NoDelay); RETURN request.result;
  444. END AddRealRequestInteger;
  445. PROCEDURE Remove*(message: Message);
  446. VAR prev, next: Message;
  447. BEGIN
  448. ASSERT (SequencerCalledThis ());
  449. IF message = NIL THEN RETURN END;
  450. prev := NIL; next := first;
  451. WHILE (next # NIL) & (next # message) DO prev := next; next := next.next END;
  452. IF next = message THEN
  453. IF prev = NIL THEN first := message.next; woken := TRUE; ELSE prev.next := message.next END;
  454. END;
  455. message.next := NIL;
  456. END Remove;
  457. (* this procedure is called sequentially and can be overridden in order to do contiguous work *)
  458. PROCEDURE Handle*;
  459. BEGIN
  460. IF (first # NIL) & (first.time # NoDelay) THEN Objects.SetTimeoutAt (timer, Wakeup, first.time) END;
  461. AWAIT ((first # NIL) & (first.time = NoDelay) OR ~handling OR woken);
  462. Objects.CancelTimeout (timer); woken := FALSE;
  463. END Handle;
  464. PROCEDURE Wakeup;
  465. BEGIN {EXCLUSIVE} woken := TRUE;
  466. END Wakeup;
  467. PROCEDURE Stop*;
  468. BEGIN {EXCLUSIVE} handling := FALSE;
  469. END Stop;
  470. BEGIN {ACTIVE}
  471. WHILE handling DO HandleMessages; BEGIN {EXCLUSIVE} Handle END END;
  472. END Sequencer;
  473. (* helper types *)
  474. BooleanHandler = PROCEDURE {DELEGATE} (property: Boolean; value: BOOLEAN);
  475. IntegerHandler = PROCEDURE {DELEGATE} (property: Integer; value: WORD);
  476. RealHandler = PROCEDURE {DELEGATE} (property: Real; value: REAL);
  477. SetHandler = PROCEDURE {DELEGATE} (property: Set; value: SET);
  478. StringHandler = PROCEDURE {DELEGATE} (property: String; CONST value: ARRAY OF CHAR);
  479. Procedure = PROCEDURE {DELEGATE};
  480. BooleanProcedure = PROCEDURE {DELEGATE} (value: BOOLEAN);
  481. IntegerProcedure = PROCEDURE {DELEGATE} (value: WORD);
  482. IntegerIntegerProcedure = PROCEDURE {DELEGATE} (value0, value1: WORD);
  483. RealProcedure = PROCEDURE {DELEGATE} (value: REAL);
  484. SetProcedure = PROCEDURE {DELEGATE} (value: SET);
  485. StringProcedure = PROCEDURE {DELEGATE} (CONST value: ARRAY OF CHAR);
  486. ProcedureBoolean = PROCEDURE {DELEGATE} (): BOOLEAN;
  487. ProcedureInteger = PROCEDURE {DELEGATE} (): WORD;
  488. ProcedureReal = PROCEDURE {DELEGATE} (): REAL;
  489. IntegerProcedureBoolean = PROCEDURE {DELEGATE} (value: WORD): BOOLEAN;
  490. RealProcedureInteger = PROCEDURE {DELEGATE} (value: REAL): WORD;
  491. (* helper function for delayed execution *)
  492. PROCEDURE Delay* (delay: LONGINT): LONGINT;
  493. BEGIN RETURN delay + Kernel.GetTicks ();
  494. END Delay;
  495. END A2Sequencers.
  496. Open issues:
  497. - first parameter of event procedures concrete or abstract property type?
  498. - no concrete request types implemented
  499. - serializable interface of properties not implemented