1% BEGIN LICENSE BLOCK 2% Version: CMPL 1.1 3% 4% The contents of this file are subject to the Cisco-style Mozilla Public 5% License Version 1.1 (the "License"); you may not use this file except 6% in compliance with the License. You may obtain a copy of the License 7% at www.eclipse-clp.org/license. 8% 9% Software distributed under the License is distributed on an "AS IS" 10% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 11% the License for the specific language governing rights and limitations 12% under the License. 13% 14% The Original Code is The ECLiPSe Constraint Logic Programming System. 15% The Initial Developer of the Original Code is Cisco Systems, Inc. 16% Portions created by the Initial Developer are 17% Copyright (C) 2006 Cisco Systems, Inc. All Rights Reserved. 18% 19% Contributor(s): 20% 21% END LICENSE BLOCK 22 23:- comment(alias, "Event Handling"). 24:- comment(summary, "Built-ins to handle events and interrupts"). 25:- comment(categories, ["Built-In Predicates"]). 26 27:- tool(error / 2). 28:- tool(error / 3). 29:- tool(event_create / 3). 30:- tool(set_event_handler / 2). 31:- tool(set_interrupt_handler / 2). 32 33:- comment(cancel_after_event / 2, [ 34 summary:"Cancel all pending instances of after event Event", 35 amode:(cancel_after_event(+,-) is det), 36 desc:html(" All instances of the pending after event Event is 37 cancelled so that the event will not be triggered. A pending after event 38 is an event which is setup by either event_after/2, event_after/3 or 39 event_after_every/2, and which is waiting to be raised 40 (event_after_every/2 will always be pending as it is raised repeatedly). 41<P> 42 CancelledEvents is the list of after events that have been cancelled. 43 Each element of CancelledEvents is of the form of an event specified 44 in Events of events_after / 1. As a result, CancelledEvents can be 45 reposted using events_after(CancelledEvents). If there was no event 46 to cancel, CancelledEvents will be bound to the empty list. 47<P> 48 Note that the processing of an already raised, but as yet unprocessed 49 event will not be cancelled by this predicate (but you can use 50 event_disable/1 to achieve this). 51"), 52 args:["Event" : "Atom or Handle", "CancelledEvents" : "Variable"], 53 exceptions:[5 : "Event is not an atom."], 54 eg:" 55 % setup an after event and cancel immediatedly 56 ?- event_create(writeln(hi), [], E), 57 event_after(E, 3.2), 58 cancel_after_event(E, Cancelled). 59 E = 'EVENT'(16'ed980a58) 60 Cancelled = ['EVENT'(16'ed980a58) - 3.1999999999999886] 61 Yes (0.00s cpu) 62 63 % no after-event requested, nothing to cancel 64 ?- event_create(writeln(hi), [], E), 65 cancel_after_event(E, Cancelled). 66 E = 'EVENT'(16'ed980a58) 67 Cancelled = [] 68 Yes (0.00s cpu) 69 70 % setup an after event and cancel immediatedly 71 ?- event_create(writeln(hi), [], E1), 72 event_after_every(E1, 1), 73 event_create((cancel_after_event(E1, C1), writeln(cancelled(C1))), [], E2), 74 event_after(E2, 5), 75 repeat, fail. 76 hi 77 hi 78 hi 79 hi 80 cancelled(['EVENT'(16'edbc0cc0) - every(1)]) 81 82", 83 see_also:[event_after / 2, event_after / 3, event_disable/1, 84 event_after_every / 2, event / 1, set_event_handler / 2, 85 current_after_events / 1, event_create / 3, event_retrieve / 3]]). 86 87:- comment(current_error / 1, [ 88 summary:"Succeeds if N unifies with a valid error number. 89 90", 91 amode:(current_error(+) is semidet), 92 amode:(current_error(-) is multi), 93 desc:html(" Used to generate on backtracking all the current valid error numbers. N 94 is a variable. 95 96<P> 97 Also used to check that N is a valid error number. N is an integer. 98 99<P> 100"), 101 args:["N" : "Positive integer or variable."], 102 fail_if:"Fails if N is not a valid error number.", 103 exceptions:[5 : "N is instantiated, but not to an integer."], 104 eg:" 105Success: 106 ?- current_error(N). 107 N = 1 More? (;) % type `;' 108 N = 2 More? (;) 109 N = 4 More? (;) 110 N = 5 More? (;) % carriage return typed 111 yes. 112 113 ?- [user]. 114 list_error1(String, N, Message) :- 115 current_error(N), 116 error_id(N, Message), 117 substring(Message, String, _). 118 user compiled 208 bytes in 0.03 seconds 119 120 ?- list_error1(\"def\",N,M). 121 N = 21 122 M = \"undefined arithmetic expression\" More? (;) 123 yes. 124 125Fail: 126 current_error(3). 127 128Error: 129 current_error(1.0). (Error 5). 130 131 132 133", 134 see_also:[error_id / 2]]). 135 136:- comment(error_id / 2, [ 137 summary:"Succeeds if Message unifies with the error message string defined for error 138number N. 139 140", 141 amode:(error_id(+,-) is det), 142 desc:html(" This predicate unifies Message with the message string defined for error 143 number N. 144 145<P> 146"), 147 args:["N" : "Positive integer.", "Message" : "String or variable."], 148 exceptions:[4 : "N is not instantiated.", 5 : "N is instantiated, but not to an integer.", 5 : "Message is instantiated, but not to a string."], 149 eg:" 150Success: 151 error_id(80,M). 152 (gives M=\"not a module\"). 153 error_id(70,M). 154 (gives M=\"accessing an undefined dynamic procedure\"). 155 error_id(60,M). 156 (gives M=\"accessing an undefined procedure\"). 157 error_id(90,M). 158 (gives M=\"declaration not at module beginning\"). 159 160 ?- [user]. 161 warning_handler(X, Where) :- 162 write('(warning) '), 163 error_id(X, Message), 164 write(Message), 165 write(' in '), 166 write(Where). 167 user compiled 332 bytes in 0.05 seconds 168 169 ?- warning_handler(60,dummy). 170 (warning) accessing an undefined procedure in dummy 171 yes. 172 173 ?- [user]. 174 fail_warning(N, Where) :- 175 write(\"Warning: Failure due to \"), 176 error_id(N, Errmsg), 177 write(Errmsg), 178 write(\":\"-Where), 179 fail. 180 user compiled 328 bytes in 0.00 seconds 181 yes. 182 183 ?- set_event_handler(68, fail_warning/2). 184 yes. 185 186 ?- p. 187 Warning: Failure due to calling an undefined procedure: - p 188 no. 189Fail: 190 error_id(60,\"procedure not defined\"). 191Error: 192 error_id(N,\"not a module\"). (Error 4). 193 error_id(1.0,M). (Error 5). 194 error_id(1,atom). (Error 5). 195 196 197", 198 see_also:[]]). 199 200:- comment(current_after_events / 1, [ 201 summary:" Check or find currently pending after events. 202 203", 204 amode:(current_after_events(-) is det), 205 desc:html("\ 206 207 If Events is a variable, then all the currently pending 208 events are returned as a list. The list elements are of the 209 form due(EventName - PostTime, DueTime) for an event raised with 210 event_after/2 and event_after/3 and of the form 211 due(EventName - every(Interval), NextDueTime) for an event raised 212 with event_after_every/2. An event will appear as many times as it 213 has been setup. EventName is the name of the after event. PostTime is 214 the time at which the event was posted, and DueTime the time at which it 215 is to be raised. For a repeating after event, Interval is the period 216 between events, and NextDueTime is the next time at which it is to be raised. 217 218<P> 219 Note that this predicate simply returns a snapshot of the current pending 220 after events. It is therefore possible that an after event returned in Events 221 has already been raised. 222<P> 223"), 224 args:["Events" : "List of due / 2 structures or variable"], 225 eg:" 226 setup :- 227 set_event_handler(hi, hi/0), 228 event_after_every(hi, 3.2). 229 230 hi :- 231 current_after_events(Es), 232 writeln(hi), 233 writeln('Pending events'-Es). 234 235 % just spinning after the setup for events to be raised. 236 ?- setup, repeat, fail. 237 hi 238 Pending events - [due(hi - every(3.2), 30.51)] 239 hi 240 Pending events - [due(hi - every(3.2), 33.72)] 241 hi 242 Pending events - [due(hi - every(3.2), 36.93)] 243 ... 244", 245 see_also:[event_after / 2, event_after / 3, event_after_every / 2, 246 event / 1, set_event_handler / 2, event_create / 3, 247 event_retrieve / 3]]). 248 249 250:- comment(get_event_handler / 3, [ 251 summary:"Returns the event handler for event/error Event and its home module Module.", 252 amode:(get_event_handler(+,-,-) is semidet), 253 desc:html(" Given the event name/error number Event, Predspec is unified with the specification 254 (i.e. a term of the form name/arity) of the current handler for 255 event; Module is unified with its home module. 256 257<p> 258 The events which exist are user defined; the errors which exist are 259 implementation defined. 260 261 262<p> 263"), 264 args:["Event" : "atom or integer.", "Predspec" : "term which unifies with atom/integer.", "Module" : "atom or variable."], 265 fail_if:"Fails if Event is not an event", 266 exceptions:[4 : "Event is not instantiated.", 5 : "Event is not an atom nor integer.", 5 : "PredSpec is neither a variable nor of the form Atom/Integer."], 267 see_also:[set_event_handler / 2, event/ 1]]). 268 269:- comment(get_interrupt_handler / 3, [ 270 summary:"Succeeds if PredSpec unifies with the specification of the current handler 271for interrupt IntId and Module unifies with its home module. 272 273", 274 amode:(get_interrupt_handler(+,-,-) is semidet), 275 desc:html(" Provided IntId is a valid interrupt identifier, unifies PredSpec with 276 the specification (i.e. a term of the form name/arity) of the current 277 handler for interrupt IntId, and Module with the module in which it is 278 defined. 279<P> 280 The interrupts which exist are machine dependent. The interrupts which 281 can be caught or trapped are implementation defined. 282 283<P> 284"), 285 args:["IntId" : "Integer or atom.", "PredSpec" : "Term which unifies with atom/integer.", "Module" : "Atom or variable."], 286 fail_if:"Fails if no handler has been set for the interrupt IntId", 287 exceptions:[4 : "IntId is not instantiated.", 5 : "IntId is not an atom or integer.", 5 : "PredSpec does not unify with atom/integer.", 6 : "IntId is not a valid interrupt name or number."], 288 eg:" 289Success: 290 ?- get_interrupt_handler(18,M,N). 291 M = pause/0 292 N = sepia_kernel 293 yes. 294 295 ?- set_interrupt_handler(18,true/0), kill(0, 18), 296 > get_interrupt_handler(18,true/0,sepia_kernel). 297 yes. 298Fail: 299 get_interrupt_handler(16, true/0, sepia_kernel). 300Error: 301 get_interrupt_handler(N,true/0,sepia_kernel). (Error 4). 302 get_interrupt_handler(5.0,true/0,sepia_kernel). (Error 5). 303 get_interrupt_handler(-1,X,sepia_kernel). (Error 6). 304", 305 see_also:[current_interrupt / 2, set_interrupt_handler / 2, kill/2]]). 306 307:- comment(reset_error_handlers / 0, [ 308 summary:"All error handlers are reset, cancelling any redefinition. 309 310", 311 amode:(reset_error_handlers is det), 312 desc:html(" All error handlers are reset, cancelling any redefinition. 313 314<P> 315 The errors which exist are implementation defined. 316 317<P> 318"), 319 args:[], 320 eg:" 321Success: 322 ?- string_list(S,L). 323 instantiation fault in string_list(_g50, _g52) 324 325 ?- atom_length(\"atom\",L). 326 type error in atom_length(\"atom\", _g52). 327 328 ?- set_event_handler(4,fail/0), string_list(S,L). 329 no (more) solution. 330 331 ?- set_event_handler(5,abort/0),atom_length(\"atom\",L). 332 Aborting execution.... 333 334 ?- reset_error_handlers, string_list(S,L). 335 instantiation fault in string_list(_g62, _g64) 336 337 ?- atom_length(\"atom\",L). 338 type error in atom_length(\"atom\", _g52). 339 340", 341 see_also:[reset_event_handler / 1]]). 342 343:- comment(event / 1, [ 344 summary:"The event EventId is raised and the corresponding error handler is 345executed. 346 347", 348 amode:event(+), 349 desc:html(" The event EventId is raised and the corresponding error handler is 350 executed. 351 352<P> 353 Other ways to raise events are by 354<PRE> 355 - one of the builtins error/2 or error/3. 356 - posting an event from external code using ec_post_event(). 357 - an interrupt whose handler has been specified as event/1. 358</PRE> 359 The latter two have the effect of dynamically inserting an event/1 360 goal into the current execution at the next synchronous point, 361 which is usually just before the next predicate call. 362 363<P> 364"), 365 args:["EventId" : "Atom or event Handle, or a list of atoms and/or event handles."], 366 resat:"Resatisfiable if the handler is resatisfiable", 367 fail_if:"Fails if the handler fails", 368 exceptions:[ 369 4 : "EventId is not ground", 370 5 : "EventId is instantiated, but neither an atom nor an event handle, or a list of them", 371 32 : "No handler is associated to an atomic EventId"], 372 eg:" 373 ?- event(hello). 374 warning: no handler for event in hello 375 yes. 376 377 ?- set_event_handler(hello, writeln/1). 378 yes. 379 380 ?- event(hello). 381 hello 382 yes. 383 384 ?- event([hello,hello]). 385 hello 386 hello 387 Yes (0.00s cpu) 388 389", 390 see_also:[event_create/3, is_event/1, error / 2, error / 3, reset_event_handler / 1, set_event_handler / 2, set_interrupt_handler / 2]]). 391 392:- comment(reset_event_handler / 1, [ 393 summary:"Resets the handler for the event EventId to its default value", 394 amode:(reset_event_handler(+) is det), 395 desc:html(" If EventId is an error number, the error handler is reset to 396 its default value, cancelling any previous redefinition. 397 398<P> 399 If EventId is an atom, any previously installed handler is uninstalled, 400 and future occurrences of the event will cause an error (32). 401 402<P> 403"), 404 args:["EventId" : "Atom or Integer."], 405 exceptions:[4 : "EventId is not instantiated.", 5 : "EventId is neither atom nor integer.", 6 : "EventId is integer, but not a valid error number."], 406 eg:" 407Success: 408 ?- event(hello). 409 warning: no handler for event in hello 410 yes. 411 412 ?- set_event_handler(hello, writeln/1). 413 yes. 414 415 ?- event(hello). 416 hello 417 418 ?- reset_event_handler(hello). 419 yes. 420 421 ?- event(hello). 422 warning: no handler for event in hello 423 yes. 424 425", 426 see_also:[current_error / 1, get_event_handler / 3, error / 2, error / 3, event / 1, set_event_handler / 2]]). 427 428:- comment(set_event_handler / 2, [ 429 summary:"Set an event handler PredSpec for the event EventId. 430 431", 432 amode:(set_event_handler(+, ++) is det), 433 desc:html(" Assigns the procedure specified by PredSpec as the event handler 434 for the event specified by EventId. The event name can be either 435 an arbitrary atom or a valid error number (as returned by 436 current_error/1). 437 438<P> 439 An event handler which is used as an error handler can have 4 440 optional arguments: 441 <UL> 442 <LI>the 1st argument is the event number/identifier itself 443 <LI>the 2nd argument is the culprit (a structure corresponding to 444 the call which caused it) 445 <LI>the 3rd argument is the context module (or the lookup module 446 if the context module is unknown) 447 <LI>the 4th argument is the lookup module for the call 448 </UL> 449 The error handler is free to use less than 4 arguments. 450 </UL> 451 452<P> 453 Handlers for events raised by event/1 or posted to the system from 454 the outside usually have no arguments or just the event name. 455 456<P> 457 Events can be raised by 458<PRE> 459 - one of the builtins event/1, error/2 or error/3. 460 - posting an event from external code using ec_post_event(). 461 - an interrupt whose handler has been specified as event/1. 462</PRE> 463 The latter two have the effect of dynamically inserting an event/1 464 goal into the current execution at the next synchronous point, 465 which is usually just before the next predicate call. 466 467<P> 468 If the handler is specified as defers(Name/Arity), then the event has 469 the defer-property. This means that event handling is automatically 470 deferred on entering the event's handler, thus preventing other events 471 from interrupting the handler. Such handlers must always explicitly invoke 472 events_nodefer/0 before exiting in order to reenable event handling. 473<P> 474"), 475 args:["EventId" : "Atom or Integer.", 476 "PredSpec" : "Term of the form Atom/Integer, or defers(Atom/Integer)."], 477 exceptions:[4 : "Either EventId or PredSpec is not instantiated.", 478 5 : "EventId is neither atom nor integer.", 479 5 : "PredSpec is not of the form Atom/Integer or defers(Atom/Integer).", 480 6 : "EventId is integer, but not a valid error number.", 481 6 : "PredSpec specifies an illegal handler arity." 482 ], 483 eg:" 484Success: 485 ?- event(hello). 486 warning: no handler for event in hello 487 yes. 488 489 ?- set_event_handler(hello, writeln/1). 490 yes. 491 492 ?- event(hello). 493 hello 494 yes. 495", 496 see_also:[current_error / 1, get_event_handler / 3, error / 2, error / 3, event / 1, reset_event_handler / 1, events_nodefer/0]]). 497 498:- comment(current_interrupt / 2, [ 499 summary:"Succeeds if N unifies with the number and IntID unifies with the mnemonic 500name of a valid interrupt. 501 502", 503 amode:(current_interrupt(-,-) is multi), 504 amode:(current_interrupt(+,-) is semidet), 505 amode:(current_interrupt(-,+) is semidet), 506 desc:html(" This predicate unifies N with the signal number and IntID with the 507 mnemonic name of an existing interrupt type. This predicate can be used 508 to find the signal number related to a mnemonic interrupt name and vice 509 versa, or to return all valid interrupts on backtracking. 510 511<P> 512"), 513 args:["N" : "Positive integer or variable.", "IntID" : "Atom or variable."], 514 fail_if:"N or IntID do not unify with the interrupt number resp. the mnemonic name of a valid interrupt", 515 exceptions:[5 : "N is instantiated, but not to an integer.", 5 : "IntID is instantiated, but not to an atom."], 516 eg:" 517Success: 518 current_interrupt(2, X) (gives X = int) 519 current_interrupt(X, kill) (gives X = 9) 520 current_interrupt(N, Int) 521Fail: 522 current_interrupt(43, Int) 523 current_interrupt(N, noint) 524Error: 525 current_interrupt(1.0, Int). (Error 5). 526 current_interrupt(N, \"int\"). (Error 5). 527 528 529 530", 531 see_also:[current_error / 1, kill / 2]]). 532 533:- comment(error / 2, [ 534 summary:"An error or event EventId is raised and the corresponding error handler is executed", 535 amode:error(+, ?), 536 desc:html("\ 537 The event or error EventId with Culprit as its culprit goal is raised. 538 EventId is either an integer error number, or an atomic event name. 539 The error handler which is associated with EventId is invoked, 540 with its first argument set to EventId, its second argument to Culprit, 541 and its third argument and fourth argument are the context module in 542 which error/2 is invoked. If the handler has less than four arguments, 543 the extra information is lost. 544<P> 545 This simulates an occurrence of the error EventId inside a call 546 to Culprit. The valid error numbers are those returned by 547 current_error/1. Event names can be any atom as long as an event handler 548 has been defined for them. 549<P> 550 If EventId is a structure with functor default/1, the structure's argument 551 is taken as the error number and the default handler is executed, even 552 if the error handler has been redefined using set_event_handler/2. 553 This is useful for writing user error handlers. 554<P> 555 If the event handler succeeds, possibly binding some variables 556 inside Culprit, then error/2 succeeds as well. If the handler fails 557 or calls exit_block/1, then so does error/2. 558"), 559 args:["EventId" : "Atom, integer or structure with functor default/1.", "Culprit" : "Prolog term."], 560 resat:"Resatisfiable if the handler is resatisfiable", 561 fail_if:"Fails if the handler fails", 562 exceptions:[4 : "EventId is not instantiated.", 5 : "EventId is not an error specification.", 563 6 : "EventId is a number but not a valid error number.", 564 32 : "No handler is associated to EventId"], 565 eg:" 566Success: 567 568 % Writing a predicate with type checking 569 ?- [user]. 570 is_positive(N) :- 571 number(N), 572 !, 573 N >= 0. 574 is_positive(N) :- 575 error(5, is_positive(N)). 576 user compiled 244 bytes in 0.02 seconds 577 yes. 578 579 ?- is_positive(a). 580 type error in is_positive(a) 581 582 % changing the behaviour of a built-in by redefining a handler 583 ?- //(1,0,X). % change this behaviour 584 arithmetic exception in //(1, 0, X) 585 586 ?- [user]. % define the new handler 587 my_handler(_, //(_,_,Result)) :- 588 !, 589 Result = infinity. 590 my_handler(Err, Goal) :- 591 error(default(Err), Goal). 592 user compiled 212 bytes in 0.00 seconds 593 yes. 594 595 ?- set_event_handler(20, my_handler/2). 596 yes. 597 598 ?- //(1,0,X). % check if it works 599 X = infinity 600 yes. 601 602 ?- sqrt(-1,X). % other culprits: as before 603 arithmetic exception in sqrt(-1, _g36) 604 605Error: 606 error(N,dummy(1)). (Error 4). 607 error(5.0,dummy(1)). (Error 5). 608 error(-2,dummy(1)). (Error 6). 609 610 611 612", 613 see_also:[error / 3, event/1, current_error / 1, error_id / 2, get_event_handler / 3, reset_event_handler / 1, reset_error_handlers / 0, set_event_handler / 2]]). 614 615:- comment(error / 3, [ 616 summary:"An error EventId is raised with Culprit and context module Module, and the corresponding error handler is executed", 617 amode:error(++, ?, +), 618 desc:html("\ 619 The event or error EventId with Culprit as its culprit goal is raised. 620 EventId is either an integer error number, or an atomic event name. 621 The error handler which is associated with EventId is invoked, 622 with its first argument set to EventId, its second argument to Culprit, 623 its third argument to Module, and its fourth argument to the context module 624 in which error/3 is invoked. If the handler has less than four arguments, 625 the extra information is lost. 626<P> 627 This simulates an occurrence of the error EventId inside a call 628 to Culprit in Module. The valid error numbers are those returned by 629 current_error/1. Event names can be any atom as long as an event handler 630 has been defined for them. 631<P> 632 If EventId is a structure with functor default/1, the structure argument 633 is taken as the error number and the default handler is executed, even 634 if the error handler has been redefined using set_event_handler/2. 635 This is useful for writing user error handlers. 636<P> 637 If the event handler succeeds, possibly binding some variables 638 inside Culprit, then error/3 succeeds as well. If the handler fails 639 or calls exit_block/1, then so does error/3. 640<P> 641 Not that when the error handler ignores the module (ie. has arity less 642 than three), then error/2 and error/3 are equivalent. 643<P> 644"), 645 args:["EventId" : "Atom, integer or structure with functor default/1.", "Culprit" : "Prolog term.", "Module" : "Atom."], 646 resat:"Resatisfiable if the handler is resatisfiable", 647 fail_if:"Fails if the handler fails", 648 exceptions:[4 : "EventId is not instantiated.", 5 : "EventId is not an error specification.", 649 6 : "EventId is a number but not a valid error number.", 650 32 : "No handler is associated to EventId"], 651 eg:" 652Success: 653 654 ?- error(68, length(X, Y), lists). 655 calling an undefined procedure eclipse:length(X, Y) in module lists 656 657 % writing an alternative error handler for undefined predicates: 658 ?- arg(1,2). % we want to change this 659 calling an undefined procedure arg(1, 2) in module eclipse 660 661 ?- [user]. % compile the new handler 662 663 undef_handler(_, Goal, _Context, Module) :- 664 functor(Goal, Name, BadArity), 665 ( 666 current_predicate(Name/Arity)@Module 667 ; 668 current_built_in(Name/Arity)@Module 669 ), 670 !, 671 printf(\"%w does not exist, but there is %w\\n\", 672 [Name/BadArity, Name/Arity]), 673 fail. 674 undef_handler(Err, Goal, Context, Module) :- 675 error(default(Err), Goal, Context, Module). 676 user compiled 592 bytes in 0.02 seconds 677 yes. 678 679 ?- set_event_handler(68, undef_handler/4). 680 yes. 681 682 ?- arg(1,2). % check if it works 683 arg / 2 does not exist, but there is arg / 3 684 685 no. 686 687Error: 688 error(N,dummy(1),eclipse). (Error 4). 689 error(5.0,dummy(1),eclipse). (Error 5). 690 error(-2,dummy(1),eclipse). (Error 6). 691 error(95,dummy(1),eclipse). (Error 6). 692 693 694 695", 696 see_also:[error / 2, event/1, current_error / 1, error_id / 2, get_event_handler / 3, reset_event_handler / 1, reset_error_handlers / 0, set_event_handler / 2]]). 697 698:- comment(event_after / 2, [ 699 summary:" Set up an event Event which is triggered after Time seconds have 700 elapsed. 701 702", 703 amode:(event_after(+, +) is det), 704 desc:html("\ 705 The event Event is raised after Time seconds of elapsed time from when 706 the predicate is executed. Every call to event_after/2 will cause exactly 707 one corresponding event, if the same event is requested several times, it 708 will be raised several times. The event mechanism is safe with respect to 709 backtracking: once an after-event has been requested, it will be raised, 710 even when execution fails across the point where it was requested. 711<P> 712 Time can be a real number, but the actual granularity of how fine 713 the elapsed time is measured is operating system dependent, and the 714 triggering condition is actually that at least Time seconds have 715 elapsed. 716<P> 717 In addition, the processing of an event may not happen immediately 718 upon the raising the event, as events are processed synchronously: 719 An event can only be handled at a point where an ECLiPSe goal can 720 be executed. This can delay the handling of an event when ECLiPSe is 721 performing some uninterruptible task, e.g. waiting for I/O, or executing 722 external code. 723<P> 724 The use of after-events requires some thought because after-events can 725 be raised at unpredictable (even though well-defined) points during 726 program execution. As long as the handlers succeed, this poses no 727 particular problem, because execution is allowed to continue after the 728 handler succeeds. By design, the possibilities of an event handler to 729 interact with the interrupted execution are limited (the handler can 730 access global data structures, use a symbolic trigger, etc). 731<P> 732 More problematic are applications where the handler is allowed to 733 abort using exit_block/1. Due to the timed execution, the exact 734 program point where the abort happens is unpredictable. It must be 735 made sure that the abort is safely caught in all cases, and that 736 nonlogical data is not left in an inconsistent state. In such cases, 737 it is possible to use events_defer/0 and events_nodefer/0 to protect 738 critical code sequences from being interrupted by event handling. 739 Note that it never makes sense to let after-event handlers fail. 740<P> 741 Another problem that may occur with timed events is that a new 742 event may be raised while another one is still being handled. To 743 stop event handlers from being interrupted by others, it is possible 744 to give events the defer-property. This means that event handling 745 is automatically deferred on entering the event's handler, thus 746 preventing other events from interrupting the handler. Such handlers 747 must always explicitly invoke events_nodefer/0 before exiting in order 748 to reenable event handling. 749<P> 750 The timer used by measuring elapsed time is specified by the environment 751 flag after_event_timer: virtual means that elapsed user cpu time is 752 used, real means elapsed real time. The default is real. On 753 systems that cannot support CPU time measurement, such as Microsoft 754 Windows, one may not set the timer to virtual: an error is raised 755 if this is attempted. The time relevant for event handling can be 756 obtained by calling statistics(event_time, Now). 757"), 758 args:["Event" : "Atom or Handle", "Time" : "Positive number"], 759 exceptions:[5 : "Event is neither an atom nor a handle or Time is not a positive number."], 760 eg:" 761 ?- event_create(writeln(hi), [], E), 762 event_after(E, 3.2), 763 event_create(abort, [], E1), 764 event_after(E1, 5), 765 repeat, fail. 766 hi % after 3.2 seconds 767 Aborting execution ... % after 5 seconds 768 Abort 769", 770 see_also:[event_after / 3, event_after_every / 2, 771 cancel_after_event / 2, events_after/1, event / 1, 772 set_event_handler / 2, current_after_events / 1, 773 event_create / 3, event_retrieve / 3, get_flag / 2, statistics/2]]). 774 775 776:- comment(event_after / 3, [ 777 summary:"Set up an event Event which is triggered at DueTime, after Time seconds have elapsed", 778 amode:(event_after(+, +, -) is det), 779 desc:html("\ 780 The event Event is raised after Time seconds of elapsed time from when 781 the predicate is executed. This is identical to event_after/2, except 782 that DueTime gets bound to the time at which the event will be raised. 783 This time can be compared to the the current event_time as returned by 784 statistics/2. 785<P> 786 For more details, see event_after/2. 787"), 788 args:["Event" : "Atom or Handle", "Time" : "Positive number", 789 "DueTime" : "Variable, will be bound to a float"], 790 exceptions:[5 : "Event is neither an atom nor a handle or Time is not a positive number."], 791 eg:" 792 % With the following the handler definition 793 report_due(DueTime) :- 794 Remaining is DueTime - statistics(event_time), 795 printf(\"Event is due in %w seconds%n\", [Remaining]). 796 797 ?- event_create(abort, [], E1), 798 event_after(E1, 5, Due), 799 event_create(report_due(Due), [], E2), 800 event_after_every(E2, 1), 801 repeat, fail. 802 Event is due in 3.98999999999999 seconds 803 Event is due in 2.98 seconds 804 Event is due in 1.97 seconds 805 Event is due in 0.959999999999994 seconds 806 Aborting execution ... 807 Abort 808", 809 see_also:[event_after / 2, event_after_every / 2, 810 cancel_after_event / 2, events_after/1, event / 1, 811 set_event_handler / 2, current_after_events / 1, 812 event_create / 3, event_retrieve / 3, get_flag / 2, statistics/2]]). 813 814 815:- comment(event_after_every / 2, [ 816 summary:" Set up an event Event which is triggered after every Time seconds have 817 elapsed. 818 819", 820 amode:(event_after_every(+, +) is det), 821 desc:html("\ 822 The event Event is raised after every Time seconds of elapsed time from when 823 the predicate is executed. The difference from event_after/2 and event_after/3 824 is that event_after_every/2 raises the event Event at regular Time intervals 825 once it is initiated, whereas event_after/2 and event_after/3 826 raise the event once (per event_after/2 and event_after/3) only. The time 827 for the next event starts counting from the moment the previous event is 828 raised. This means that the time between the raising of two events will 829 never fall below the Time interval, even if there is a delay in raising 830 one of the events. The event mechanism is safe with respect to 831 backtracking: once an after-event has been requested, it will be raised, 832 even when execution fails across the point where it was requested. 833 The only way to stop further after-every-events being raised is to cancel 834 them using cancel_after_event/2. 835<P> 836 Time can be a real number, but the actual granularity of how fine 837 the elapsed time is measured is operating system dependent, and the 838 triggering condition is actually that at least Time seconds have 839 elapsed. 840<P> 841 In addition, the processing of an event may not happen immediately 842 upon the raising the event, as events are processed synchronously: 843 An event can only be handled at a point where an ECLiPSe goal can 844 be executed. This can delay the handling of an event when ECLiPSe is 845 performing some uninterruptible task, e.g. waiting for I/O, or executing 846 external code. 847<P> 848 The use of after-events requires some thought because after-events can 849 be raised at unpredictable (even though well-defined) points during 850 program execution. As long as the handlers succeed, this poses no 851 particular problem, because execution is allowed to continue after the 852 handler succeeds. By design, the possibilities of an event handler to 853 interact with the interrupted execution are limited (the handler can 854 access global data structures, use a symbolic trigger, etc). 855<P> 856 More problematic are applications where the handler is allowed to 857 abort using exit_block/1. Due to the timed execution, the exact 858 program point where the abort happens is unpredictable. It must be 859 made sure that the abort is safely caught in all cases, and that 860 nonlogical data is not left in an inconsistent state. In such cases, 861 it is possible to use events_defer/0 and events_nodefer/0 to protect 862 critical code sequences from being interrupted by event handling. 863 Note that it never makes sense to let after-event handlers fail. 864<P> 865 Another problem that may occur with timed events is that a new 866 event may be raised while another one is still being handled. To 867 stop event handlers from being interrupted by others, it is possible 868 to give events the defer-property. This means that event handling 869 is automatically deferred on entering the event's handler, thus 870 preventing other events from interrupting the handler. Such handlers 871 must always explicitly invoke events_nodefer/0 before exiting in order 872 to reenable event handling. 873<P> 874 The timer used by measuring elapsed time is specified by the environment 875 flag after_event_timer: virtual means that elapsed user cpu time is 876 used, real means elapsed real time. The default is real. On 877 systems that cannot support CPU time measurement, such as Microsoft 878 Windows, one may not set the timer to virtual: an error is raised 879 if this is attempted. The time relevant for event handling can be 880 obtained by calling statistics(event_time, Now). 881"), 882 args:["Event" : "Atom or Handle", "Time" : "Positive number"], 883 exceptions:[5 : "Event is neither an atom nor a handle or Time is not a positive number."], 884 eg:" 885 ?- event_create((statistics(event_time,T),writeln(now(T))), [], E), 886 event_after_every(E, 1), 887 repeat,fail. 888 now(4.61) % after 1 second 889 now(5.62) % after 2 seconds 890 now(6.63) 891 now(7.64) 892 now(8.65) 893 ... 894", 895 see_also:[event_after / 2, event_after / 3, events_after/1, 896 cancel_after_event / 2, event / 1, set_event_handler / 2, 897 current_after_events / 1, event_create / 3, event_retrieve / 3, 898 get_flag / 2]]). 899 900 901:- comment(events_after / 1, [ 902 summary:" Set up a series of after events Events. 903 904", 905 amode:(events_after(++) is det), 906 desc:html("\ 907 Events is a list of after events where each element of the list 908 specifies one after event. Each element is either in the form of 909 EventName-Time or EventName-every(Time) where the first form is 910 equivalent to event_after(EventName, Time) and the second to 911 event_after_every(EventName, Time). The difference between using 912 a single events_after/1 and multiple calls to event_after/2, 913 event_after/3 and event_after_every/2 to set up a series of after 914 events is that with events_after/1, all the events are set up as a 915 unit, and it is guaranteed that the relative orderings between the 916 events are preserved, and that no after events will be raised until 917 all the specified events have been set up. 918<P> 919 The main use of events_after/1 is for restart event that have been 920 cancelled previously with cancel_after_event/2. 921<P> 922 See event_after/2, event_after/3 or event_after_every/2 for more details 923 on after events. 924"), 925 args:["Events" : "A list of the form Event-Time or Event-every(Time)"], 926 exceptions:[ 927 4 : "Events is not instantiated.", 928 5 : "Events is not a list of after events of the form Event-Time or Event-every(Time), where Event is an atom or a handle and Time is a positive (non-breal) number." 929 ], 930 eg:" 931 % set event handlers to write the event name 932 ?- set_event_handler(e1, writeln/1), 933 set_event_handler(e2, writeln/1). 934 Yes (0.00s cpu) 935 936 ?- events_after([e1-every(0.2), e2-0.5]), 937 repeat,fail. 938 e1 939 e1 940 e2 941 e1 942 e1 943 e1 944 ^C 945 interruption: type a, b, c, e, or h for help : ? a 946 abort 947 Aborting execution ... 948 Abort 949 950 % cancel further e1 events 951 ?- cancel_after_event(e1, Cancelled). 952 Cancelled = [e1 - every(0.2)] 953 Yes (0.00s cpu) 954 955 % e2 was already raised, nothing to cancel 956 ?- cancel_after_event(e2, Cancelled). 957 Cancelled = [] 958 Yes (0.00s cpu) 959 960 % restart the cancelled events 961 ?- events_after([e1 - every(0.2)]), 962 repeat, fail. 963 e1 964 e1 965 e1 966 e1 967 ... 968", 969 see_also:[event_after / 2, event_after/3, event_after_every/2, 970 cancel_after_event / 2, events_after/1, event / 1, 971 set_event_handler / 2, current_after_events / 1, event_create / 3, 972 event_retrieve / 3, get_flag / 2] 973]). 974 975:- comment(set_interrupt_handler / 2, [ 976 summary:"Sets an interrupt handler PredSpec for the interrupt IntId", 977 amode:(set_interrupt_handler(+, ++) is det), 978 desc:html(" 979 Assigns the procedure specified by PredSpec as the interrupt handler for 980 the interrupt whose name or number is given by IntId. 981<P> 982 See the ECLiPSe User Manual for details on the operation of 983 interrupt handlers. 984<P> 985 The interrupt handlers of the following interrupts cannot be modified, 986 since they cannot be caught by ECLiPSe . 987<PRE> 988 No. Code Description Example 989 9 SIGKILL kill kill process from keyboard 990 17 SIGSTOP stop cannot be caught, blocked, ignored 991</PRE> 992 The interrupts which can be caught or trapped are implementation 993 defined. 994<P> 995 The following interrupt handlers have a special meaning and can be 996 used even with the embedded library version of Eclipse: 997<PRE> 998 Handler Meaning 999 ------- ------- 1000 true/0 ignore the interrupt (SIG_IGN). 1001 default/0 take the default operating system action when the 1002 interrupt occurs (SIG_DFL). 1003 event/1 handle the signal by posting a (synchronous) event. The 1004 symbolic name of the interrupt will be used as the event name. 1005 throw/1 invoke exit_block/1 with the interrupt's symbolic name. 1006 abort/0 invoke exit_block(abort) 1007 halt/0 halt Eclipse and terminate the process 1008 internal/0 the signal is used by Eclipse to implement internal 1009 functionality (e.g. profiler) 1010</PRE> 1011 All other handler specifications cause the specified predicate to 1012 be called in a nested invocation of the Eclipse engine. This is 1013 not supported on some hardware/OS platforms, e.g. Windows. 1014"), 1015 args:["IntId" : "Integer or atom.", "PredSpec" : "Term of the form Atom/Integer."], 1016 exceptions:[4 : "Either IntId or PredSpec is not instantiated.", 1017 5 : "IntId is not an atom or integer.", 1018 5 : "PredSpec is neither a variable nor of the form Atom/Integer.", 1019 6 : "IntId is not a valid interrupt name or number.", 1020 6 : "PredSpec is of the form Atom/Integer, but the integer is greater than 3.", 1021 60 : "PredSpec is of the form Atom/Integer, but no such predicate has been defined.", 1022 170 : "The interrupt cannot be caught."], 1023 eg:" 1024Success: 1025 ?- get_interrupt_handler(alrm,M,N). 1026 M = event / 1 1027 N = sepia_kernel 1028 yes. 1029 1030 ?- set_interrupt_handler(alrm,true/0), interrupt(alrm). 1031 yes. 1032 1033 ?- kill(0, alrm). 1034 yes. 1035 1036 ?- get_interrupt_handler(alrm,M,N). 1037 M = true / 0 1038 N = sepia_kernel 1039 yes. 1040 1041 ?- [user]. 1042 a :- write(log_output, \"interrupt 16\"), fail. 1043 user compiled 136 bytes in 0.00 seconds 1044 1045 ?- set_interrupt_handler(16,a/0). 1046 yes. 1047 1048 ?- kill(0, 16). 1049 interrupt 16 1050 yes. 1051 1052Error: 1053 set_interrupt_handler(N,true/0). (Error 4). 1054 set_interrupt_handler(15,P). (Error 4). 1055 set_interrupt_handler(15.0,true/0). (Error 5). 1056 set_interrupt_handler(1000,X). (Error 6). 1057 set_interrupt_handler(-1,X). (Error 6). 1058 set_interrupt_handler(6,a/4). (Error 6). % arity > 3. 1059 set_interrupt_handler(6,t/2). (Error 60). % no t/2. 1060 set_interrupt_handler(9,true/0). (Error 170). 1061 set_interrupt_handler(17,true/0). (Error 170). 1062 1063 1064", 1065 see_also:[event / 1, set_event_handler / 2, current_interrupt / 2, get_interrupt_handler / 3]]). 1066 1067 1068:- comment(event_create / 3, [ 1069 summary:"Create an ECLiPSe event from an arbitrary goal.", 1070 desc:html("\ 1071 This creates an event from the goal provided, which can be raised 1072 with the standard event handling predicates (e.g. event / 1, event_after / 2 1073 and event_after_every / 2) using the associated handle. 1074 <P> 1075 The event creation requires non-logical copying of the goal. 1076 As a result, if the goal contains variables, they lose their identity 1077 and are replaced with fresh ones. 1078 <P> 1079 The intended use of such events are for localised event handling 1080 or when it is necessary to pass ground parameters to the event goal, 1081 i.e. when the use of a global event handler is unnecessary or does not suffice. 1082 <P> 1083 It should be noted that the event handle is the only way to uniquely 1084 identify a given event. E.g. if an event has been scheduled as an 1085 after-event (using event_after/3 or events_after/2), it can only be 1086 cancelled by invoking cancel_after_event/2 with the correct handle. 1087 <P> 1088 The following options are recognised: 1089 <DL> 1090 <DT><B>defers</B></DT> 1091 <DD>Give the event the defers-property. This means that event 1092 handling is automatically deferred on entering the event's handler, 1093 thus preventing other events from interrupting the handler. 1094 Such handlers must always explicitly invoke events_nodefer/0 1095 before exiting in order to reenable event handling.</DD> 1096 </DL> 1097 "), 1098 amode:(event_create(+,++,-) is det), 1099 args:["Goal":"An arbitrary goal", "Options":"A list of atoms.", "EventHandle":"A free variable"], 1100 exceptions:[4: "Goal is not instantiated", 1101 5 : "Goal is not a valid goal", 1102 5 : "EventHandle is not a free variable", 1103 5 : "Options is not a list of atoms", 1104 6 : "Some element of Options is not a valid option"], 1105 eg:"\ 1106 % Create and raise a single event 1107 ?- event_create(writeln('Goodbye cruel world!'), [], Event), 1108 writeln('Hello world!'), 1109 event(Event). 1110 Hello world! 1111 Goodbye cruel world! 1112 Event = 'EVENT'(16'503f0238) 1113 Yes (0.00s cpu) 1114 1115 1116 % Raise events via a timer 1117 ?- event_create(writeln('e1'), [], E1Event), 1118 event_create(writeln('e2'), [], E2Event), 1119 events_after([E1Event-every(0.2), E2Event-0.5]), 1120 repeat, fail. 1121 e1 1122 e1 1123 e2 1124 e1 1125 e1 1126 ^C 1127 interruption: type a, b, c, e, or h for help : ? e1 1128 abort 1129 Aborting execution ... 1130 1131 1132 % By default, event handlers are allowed to interrupt each other, 1133 % which can make it seem that they are handled in reverse order: 1134 ?- event_create(writeln('e1'), [], E1Event), 1135 event_create(writeln('e2'), [], E2Event), 1136 event([E1Event,E2Event]). % raise both events together 1137 e2 1138 e1 1139 E1Event = 'EVENT'(16'ed9b0010) 1140 E2Event = 'EVENT'(16'ed770b20) 1141 Yes (0.00s cpu) 1142 1143 1144 % By default, event handlers are allowed to interrupt each other, 1145 % which can make it seem that they are handled in reverse order: 1146 ?- event_create((writeln('e1'),events_nodefer), [defers], E1Event), 1147 event_create((writeln('e2'),events_nodefer), [defers], E2Event), 1148 event([E1Event,E2Event]). % raise both events together 1149 e1 1150 e2 1151 E1Event = 'EVENT'(16'ed9b0010) 1152 E2Event = 'EVENT'(16'ed770b20) 1153 Yes (0.00s cpu) 1154 ", 1155 see_also:[event_retrieve / 3, event /1, event_after / 2, event_after / 3, 1156 event_after_every / 2, set_event_handler / 2, current_after_events / 1, 1157 cancel_after_event / 2, is_event/1, events_nodefer/0] 1158 ]). 1159 1160 1161:- comment(event_retrieve / 3, [ 1162 summary:"Given the handle with which an event is associated, retrieve the event goal and module", 1163 desc:html("\ 1164 The goal associated with an event handle, created using event_create/3, 1165 is retrieved using this predicate. It also returns the context module 1166 in which the event was created (and where the goal should be called). 1167 <P> 1168 Like event creation, retrieval of the goal produces a copy of the 1169 goal. As a result, if the goal contains variables, they lose their 1170 identity and are replaced with fresh ones. 1171 <P> 1172 If the event was disabled, the goal 'true' is retrieved instead of the 1173 original goal. 1174 "), 1175 amode:(event_retrieve(+,-,-) is det), 1176 args:["EventHandle":"An event handle", 1177 "Goal":"A free variable or goal to unify", 1178 "Module":"A free variable or module name"], 1179 exceptions:[4: "EventHandle is un-instantiated", 1180 5 : "EventHandle is not a handle"], 1181 eg:"\ 1182 ?- event_create(writeln('Hello world!'), [], Event), 1183 event_retrieve(Event, EventGoal, Module). 1184 1185 Event = 'EVENT'(16'50421bd0) 1186 EventGoal = writeln('Hello world!') 1187 Module = eclipse 1188 Yes (0.00s cpu) 1189 ", 1190 see_also:[event_create / 3, event /1, event_after / 2, event_after / 3, 1191 event_after_every / 2, set_event_handler / 2, current_after_events / 1, 1192 cancel_after_event / 2, is_event/1, event_disable/1, event_enable/1] 1193 ]). 1194 1195 1196:- comment(event_disable / 1, [ 1197 summary:"Disable the given event", 1198 desc:html("<P>\ 1199 The given event is disabled. A disabled events behaves as if its 1200 handler was the goal 'true': 1201 <UL> 1202 <LI>Retrieving the goal using event_retrieve/3 returns 'true'</LI> 1203 <LI>When the event is raised (e.g. posted via event/1), nothing happens</LI> 1204 <LI>If the event gets disabled after it was raised, but before its handler 1205 execution has started, handler execution will be suppressed.</LI> 1206 </UL> 1207 </P><P> 1208 Note that disabling and enabling events are nonlogical operations 1209 which are not undone on backtracking. 1210 </P> 1211 "), 1212 amode:(event_disable(+) is det), 1213 args:["EventHandle":"An event handle"], 1214 exceptions:[4: "EventHandle is un-instantiated", 1215 5 : "EventHandle is not a handle"], 1216 eg:"\ 1217 ?- event_create(writeln(hello), [], E), 1218 event_disable(E), writeln(disabled), 1219 event(E), % does nothing 1220 event_enable(E), writeln(enabled), 1221 event(E). 1222 disabled 1223 enabled 1224 hello 1225 ", 1226 see_also:[event_create / 3, event /1, event_enable/1, event_retrieve/3] 1227 ]). 1228 1229 1230 1231:- comment(event_enable / 1, [ 1232 summary:"Enable the given event", 1233 desc:html("<P>\ 1234 The given event is (re-)enabled. Since events are enabled by default, 1235 this only makes sense if the event had been previously disabled. 1236 </P><P> 1237 A disabled events behaves as if its handler was the goal 'true': 1238 <UL> 1239 <LI>Retrieving the goal using event_retrieve/3 returns 'true'</LI> 1240 <LI>When the event is raised (e.g. posted via event/1), nothing happens</LI> 1241 <LI>If the event gets disabled after it was raised, but before its handler 1242 execution has started, handler execution will be suppressed.</LI> 1243 </UL> 1244 </P><P> 1245 Note that disabling and enabling events are nonlogical operations 1246 which are not undone on backtracking. 1247 </P> 1248 "), 1249 amode:(event_enable(+) is det), 1250 args:["EventHandle":"An event handle"], 1251 exceptions:[4: "EventHandle is un-instantiated", 1252 5 : "EventHandle is not a handle"], 1253 eg:"\ 1254 ?- event_create(writeln(hello), [], E), 1255 event_disable(E), writeln(disabled), 1256 event(E), % does nothing 1257 event_enable(E), writeln(enabled), 1258 event(E). 1259 disabled 1260 enabled 1261 hello 1262 ", 1263 see_also:[event_create / 3, event /1, event_disable/1, event_retrieve/3] 1264 ]). 1265 1266 1267 1268:- comment(events_defer / 0, [ 1269 summary:"Defer event handling", 1270 amode:(events_defer is semidet), 1271 fail_if:"Fails iff event handling is already deferred", 1272 desc:html("<P>\ 1273 Defer event handling until a subsequent call to events_nodefer/0. 1274 The purpose of this feature is to 1275 <UL> 1276 <LI>sequence event handlers so they don't interrupt each other</LI> 1277 <LI>protect accesses to global data structures from being interrupted 1278 or preempted by events.</LI> 1279 </UL> 1280 Events whose handling will be deferred are: 1281 <UL> 1282 <LI>events raised by the builtin event/1</LI> 1283 <LI>events posted from external code using ec_post_event()</LI> 1284 <LI>events raised by interrupts whose handler is event/1</LI> 1285 </UL> 1286 Events that are raised while event handling is deferred will be 1287 queued and handled later. 1288 </P><P> 1289 Event handling is also automatically deferred when entering the 1290 event handlers of events that have the defer-property set (see 1291 event_create/3 and set_event_handler/2). 1292 </P><P> 1293 The predicate fails (and has no further effect) if event handling 1294 is already deferred. This feature should be used to make sure that 1295 event handling is not accidentally reenabled in a nested situation. 1296 E.g. 1297 <PRE> 1298 ..., 1299 ( events_defer -> 1300 <manipulate protected data> 1301 events_nodefer 1302 ; 1303 % events already deferred 1304 <manipulate protected data> 1305 ), 1306 ... 1307 </PRE> 1308 1309 </P><P> 1310 CAUTION: events_defer/0 is a low-level primitive that must be 1311 used with great care. Part of ECLiPSe's functionality (e.g. timeout, 1312 branch-and-bound) relies on event handling and will not work 1313 properly while event handling is deferred. Deferring and undeferring 1314 events are nonlogical operations which are not undone on backtracking. 1315 The programmer must therefore make sure that every time event handling 1316 is deferred, it is eventually reenabled by a call to events_nodefer/0, 1317 even in case of failure or abort in the deferred code sequence. 1318 </P> 1319 "), 1320 eg:"\ 1321 ?- event_create(writeln(hello), [], E), 1322 event(E), 1323 writeln(deferring), 1324 events_defer, 1325 event(E), 1326 writeln(nodeferring), 1327 events_nodefer. 1328 hello 1329 deferring 1330 nodeferring 1331 hello 1332 ", 1333 see_also:[event_create / 3, event /1, events_nodefer/0, set_event_handler/2] 1334 ]). 1335 1336 1337:- comment(events_nodefer / 0, [ 1338 summary:"Allow event handling", 1339 amode:(events_nodefer is det), 1340 desc:html("<P>\ 1341 Reenable event handling after it was previously deferred by 1342 <UL> 1343 <LI>entering the handler for an event with the defer-property 1344 (see event_create/3 and set_event_handler/2).</LI> 1345 <LI>a call to events_defer/0</LI> 1346 </UL> 1347 The purpose of this feature is to 1348 <UL> 1349 <LI>sequence event handlers so they don't interrupt each other</LI> 1350 <LI>protect accesses to global data structures from being interrupted 1351 or preempted by events.</LI> 1352 </UL> 1353 Events whose handling will be deferred are: 1354 <UL> 1355 <LI>events raised by the builtin event/1</LI> 1356 <LI>events posted from external code using ec_post_event()</LI> 1357 <LI>events raised by interrupts whose handler is event/1</LI> 1358 </UL> 1359 Events that are raised while event handling is deferred will be 1360 queued and handled later. A handler for an event with the defer- 1361 property must always call events_nodefer/0 before exiting, e.g. 1362 <PRE> 1363 deferring_event_handler :- 1364 writeln(\"This event handler\"), 1365 writeln(\"will not be interrupted\"), 1366 writeln(\"by other events!\"), 1367 events_nodefer. 1368 </PRE> 1369 </P><P> 1370 CAUTION: events_nodefer/0 is a low-level primitive that must be 1371 used with great care. Part of ECLiPSe's functionality (e.g. timeout, 1372 branch-and-bound) relies on event handling and will not work 1373 properly while event handling is deferred. Deferring and undeferring 1374 events are nonlogical operations which are not undone on backtracking. 1375 The programmer must therefore make sure that every time event handling 1376 is deferred, it is eventually reenabled by a call to events_nodefer/0, 1377 even in case of failure or abort in the deferred code sequence. 1378 </P> 1379 "), 1380 eg:"\ 1381 % Without deferring, event handlers interrupt each other, which 1382 % makes it seem as if events were handled in reverse order: 1383 1384 simple_handler(E) :- 1385 writeln(simple_handling(E)). 1386 1387 ?- set_event_handler(e1, simple_handler/1), 1388 set_event_handler(e2, simple_handler/1), 1389 set_event_handler(e3, simple_handler/1). 1390 Yes (0.00s cpu) 1391 1392 ?- event([e1,e2,e3]). 1393 simple_handling(e3) 1394 simple_handling(e2) 1395 simple_handling(e1) 1396 Yes (0.00s cpu) 1397 1398 1399 % With deferring, event handlers are sequenced, i.e. every 1400 % handler is allowed to finish before the next one executes: 1401 1402 deferred_handler(E) :- 1403 writeln(defered_handling(E)), 1404 events_nodefer. 1405 1406 ?- set_event_handler(e1, defers(deferred_handler/1)), 1407 set_event_handler(e2, defers(deferred_handler/1)), 1408 set_event_handler(e3, defers(deferred_handler/1)). 1409 Yes (0.00s cpu) 1410 1411 ?- event([e1,e2,e3]). 1412 defered_handling(e1) 1413 defered_handling(e2) 1414 defered_handling(e3) 1415 Yes (0.00s cpu) 1416 ", 1417 see_also:[event_create / 3, event /1, events_defer/0, set_event_handler/2] 1418 ]). 1419 1420