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, "External Interface"). 24:- comment(summary, "Built-ins to access functions and data from foreign languages"). 25:- comment(desc, html("For more information, see the Embedding and Interfacing Manual")). 26:- comment(categories, ["Built-In Predicates","Interfacing"]). 27 28:- tool(b_external / 1). 29:- tool(b_external / 2). 30:- tool(external / 1). 31:- tool(external / 2). 32:- tool(remote_connect / 3). 33:- tool(remote_connect_accept / 6). 34 35:- comment(external / 2, [ 36 summary:"Defines PredSpec to be a deterministic external predicate linked to the C 37function whose system name is CName. 38 39", 40 amode:(external(++, +) is det), 41 desc:html(" Declares PredSpec to be a deterministic external predicate (in the 42 caller module) linked to the ``C'' function whose system name is CName. 43 44<P> 45 If the visibility of PredSpec is not declared, it is set to local. 46 47<P> 48 If necessary, an underscore is prepended to CName to get its form as 49 used by the C compiler. 50 51<P> 52 If a call to PredSpec has already been compiled as a Prolog call or a 53 non-deterministic external call, error 62 is raised (``inconsistent 54 procedure redefinition''). This can be prevented by defining the 55 external before compiling any call to it or by using the declaration 56 predicate external/1. 57 58<P> 59"), 60 args:["PredSpec" : "Of the form Atom/Integer (predicate name/arity).", 61 "CName" : "Atom or string."], 62 exceptions:[4 : "Either PredSpec or CName is not instantiated.", 5 : "PredSpec is not of the form Atom/Integer.", 5 : "CName is not an atom or a string.", 62 : "A call to PredSpec has already been compiled as a Prolog call or a non-deterministic external call.", 211 : "External function does not exist."], 63 eg:" 64Assume we have the C++ file eg_cc_external.cc: 65 66 #include \"eclipseclass.h\" 67 extern \"C\" int 68 p_sumlist() 69 { 70 int res; 71 long x, sum = 0; 72 EC_word list(EC_arg(1)); 73 EC_word car,cdr; 74 75 for ( ; list.is_list(car,cdr) == EC_succeed; list = cdr) 76 { 77 res = car.is_long(&x); 78 if (res != EC_succeed) return res; 79 sum += x; 80 } 81 res = list.is_nil(); 82 if (res != EC_succeed) return res; 83 return unify(EC_arg(2), EC_word(sum)); 84 } 85 86 87Compile that into a dynamic library, e.g. using g++ on a Linux machine: 88 89 g++ -I/usr/local/eclipse/include/i386_linux -shared \\ 90 -o eg_cc_external.so eg_cc_external.cc 91 92 93Load the .so file dynamically into Eclipse and declare the external: 94 95 ?- load('eg_cc_external.so'). 96 yes. 97 98 ?- external(sumlist/2, p_sumlist). 99 yes. 100 101 ?- sumlist([1,2,3,4,5],S). 102 S = 15 103 yes. 104 105 106Errors: 107 external(PredSpec, \"p_member\"). (Error 4). 108 external(p/0, S). (Error 4). 109 external('p/0', p_p0). (Error 5). 110 external(p/0, 123). (Error 5). 111 external(prmsg/1, nosuchfunc). (Error 211). 112 113 ?- [user]. 114 p :- a. 115 user compiled 32 bytes in 0.00 seconds 116 yes. 117 ?- external(a/0, c_a). (Error 62). 118", 119 see_also:[external / 1, load / 1]]). 120 121:- comment(load / 1, [ 122 summary:"The object code or loadable library File is loaded into the running system. 123 124", 125 amode:(load(++) is det), 126 desc:html(" Used to load the object code file File into the ECLiPSe system. 127 The object code would normally contain functions that implement 128 ECLiPSe predicates via the external language interface. 129 Such code can currently be written in C or C++. 130 See the Embedding and Interfacing Manual for more detail. 131 132<P> 133 On modern UNIX systems shared objects are used and loading is done using 134 dlopen(). The argument of load/1 must be a shared object (.so file). 135 136<P> 137 On Windows systems dynamic libraries are used. The argument of 138 load/1 must be a .dll file. 139 140<P> 141 For old BSD systems, File specifies one or more object files, libraries 142 and/or options in the form accepted by the UNIX linker ld(1). The 143 argument is passed literally to the loader; the command executed is 144 145<P> 146<PRE> 147 bin/ld -N -A <binary> -T <addr> -o /tmp/eclipse.<pid>.N <File> -lc 1>&2 148 2>&2 149</PRE> 150 where <pid> is the process ID of the ECLiPSe process and N is an integer 151 that starts as zero and that is incremented after each dynamic loading. 152 153<P> 154 To write portable programs, it is possible to query the value of the 155 flag object_suffix. It gives the correct file extensions for the loadable 156 objects on the current platform (e.g. \"o\", \"so\", \"dll\"). 157 158<P> 159"), 160 args:["File" : "Atom or a string."], 161 exceptions:[4 : "File is not instantiated.", 162 5 : "File is instantiated, but not to an atom or a string.", 163 177 : "A shared library object (or one of its dependencies) could not be found" 164 ], 165 166 eg:" 167Success: 168 169 % See the msg.c example source in external/2. 170 % eclipse 171 172 % load the .o file dynamically into the system 173 [eclipse]: load('msg.so'). 174 yes. 175 [eclipse]: get_flag(prmsg/1,visibility,Vis). 176 accessing an undefined procedure 177 178 % link the object file with a predicate definition. 179 [eclipse]: external(prmsg/1,\"p_prmsg\"). 180 yes. 181 182 % check on existence and flags of prmsg/1. 183 [eclipse]: get_flag(prmsg/1,type,V), 184 get_flag(prmsg/1,tool,T), 185 get_flag(prmsg/1,visibility,Vis). 186 V = user 187 T = off 188 Vis = local More? (;) 189 yes. 190 191Error: 192 [eclipse]: load('msg.c'). 193 system interface error: Unknown system error 194 % not loading an object file. 195 196 [eclipse]: load('msg.o'). 197 system interface error: No such file or directory 198 % no compilation of msg.c to give msg.o 199 200 load(F). (Error 4). 201 load(msg(o)). (Error 5). 202 203 204 205", 206 see_also:[call_c / 2, external/1, external / 2, get_flag / 2]]). 207 208:- comment(external / 1, [ 209 summary:"Declares PredSpec to be a deterministic external predicate. 210 211", 212 amode:(external(++) is det), 213 desc:html(" Declares the (may be not yet visible) predicate PredSpec to be a 214 deterministic external predicate. 215 216<P> 217 This declaration is needed to compile calls to an external predicate 218 before it is actually defined with external/2. 219 220<P> 221"), 222 args:["PredSpec" : "Of the form Atom/Integer (predicate name/arity)."], 223 exceptions:[4 : "PredSpec is not instantiated.", 5 : "PredSpec is not of the form Atom/Integer.", 62 : "A call to PredSpec has already been compiled as a Prolog call or a non-deterministic external call."], 224 eg:" 225Success: 226 227 % compiling a call to an external before its definition (see description 228 % of external/2 for detail on creating external predicates). 229 [eclipse]: [user]. 230 :- import prmsg/1 from msg_lib. 231 :- external(prmsg/1). % declare its call_type 232 hello :- prmsg(\"hello\"). 233 user compiled 216 bytes in 0.03 seconds 234 235 % definition of sines/2 will not raise an inconsistent type definition 236 % thanks to the proper declaration above. 237 [eclipse]: sh(\"cat msg_lib.pl\"). 238 :- module(msg_lib). 239 :- load('msg.o', \"-lm\"). % see example in external/2 240 :- external(prmsg/1, p_prmsg). 241 :- export prmsg/1. 242 243 yes 244 [eclipse]: [msg_lib]. 245 msg_lib.pl compiled 0 bytes in 0.18 seconds 246 yes. 247 [eclipse]: hello. 248 message: hello 249 yes. 250 251Error: 252 external(PredSpec). (Error 4). 253 external(\"p/0\"). (Error 5). 254 255 [eclipse]: [user]. 256 p :- a. 257 user compiled 32 bytes in 0.00 seconds 258 yes. 259 [eclipse]: external(a/0). (Error 62). 260 261 262 263", 264 see_also:[external / 2, load / 1]]). 265 266:- comment(call_c / 2, [ 267 summary:"Invoke the C function Function and unify its return code with Code. 268 269", 270 amode:(call_c(+, ?) is det), 271 desc:html(" This predicate allows to call C functions directly from Prolog. The 272 arguments of Function are translated as follows: 273 274<P> 275 * integers and floats are passed directly 276 277<P> 278 * strings and atoms are passed as C strings 279 280<P> 281 * terms Name/Arity are interpreted as arrays and a pointer to the first 282 array's element is passed 283 284<P> 285 * structures in the form ar(M, N, K) are interpreted as array elements 286 and a pointer to this array element is passed. 287 288<P> 289 C numbers and strings are thus mapped directly on Prolog constants, C 290 structures are mapped on Prolog arrays. If Code is a variable or an 291 integer, it will be unified with the (integer) return code of the 292 function. If the function return value is of another type, it must be 293 specified in the Code as follows: 294 295<P> 296 * integer(Code) denotes an integer 297 298<P> 299 * float(Code) denotes a (double precision) floating point number 300 301<P> 302 * string(Code) denotes a string 303 304<P> 305 After Function finishes, Code is unified with its return code. If 306 Function is a system function and the return code is -1, the flag 307 last_errno contains the errno value set by the command. Function can 308 have at most 10 arguments (floating-point arguments count as two). Note 309 that only functions linked with the current session can be called. 310 Other functions can be dynamically linked using the load/1 predicate. 311 The first time a function is called it takes longer because the system 312 has to find the function in the symbol table of the binary. Its address 313 is remembered and thus next calls are faster. 314 315<P> 316"), 317 args:["Function" : "Atom or structure", "Code" : "Variable, integer or structure"], 318 exceptions:[4 : "Function is not instantiated.", 5 : "Function is neither an atom nor a structure.", 5 : "An argument of Function has a type which cannot be translated.", 20 : "Arithmetic exception in the function or when converting a single-precision float to a double.", 31 : "Arity of Function exceeds 10.", 41 : "The array argument of Function does not exist.", 211 : "The specified C function does not exist."], 319 eg:" 320Success: 321 [eclipse 16]: make_array(time(4), integer). 322 323 yes. 324 [eclipse 17]: call_c(gettimeofday(time/1, time(2)), X). 325 326 X = 0 327 yes. 328 [eclipse 18]: getval(time(0), Sec1Jan70), getval(time(2), MinWest), 329 getval(time(3), DstTime). 330 331 Sec1Jan70 = 733148538 332 MinWest = -60 333 DstTime = 4 334 yes. 335 [eclipse 19]: call_c(ctime(time(0)), string(Date)). 336 337 Date = \"Fri Mar 26 13:22:18 1993\\n\" 338 yes. 339 [eclipse 20]: call_c(sinh(1.5), float(X)). 340 External function does not exist in call_c(sinh(1.5), float(X)) 341 [eclipse 21]: load(\"-u _sinh -lm\"), call_c(sinh(1.5), float(X)). 342 343 X = 2.12927938 344 yes. 345 346Error: 347 call_c(nofunc, X). (Error 211). 348 call_c(getrusage(noarray/1, 0) (Error 41). 349 350 351 352", 353 see_also:[exec / 2, system / 1]]). 354 355:- comment(xget / 3, [ 356 summary:"Get the Index-th field of an external data structure (referenced by Handle). 357 358", 359 amode:(xget(+, +, -) is det), 360 desc:html(" ECLiPSe can manipulate external data structures via handles. 361 An external data handle can only be created by external code. 362 It consists of a pointer to the external data and a descriptor 363 for this data (a method table). ECLiPSe can then perform certain 364 operations on the data using this method table. 365 366<P> 367 The xget/3 predicate invokes one of the methods, the get-method. 368 The intended meaning is that it gets a field of the external data 369 structure (indicated by Index) and unifies it with Value. 370 The details of how the index is interpreted and how the field's 371 value is converted to an ECLiPSe term is dependent on the 372 get-method supplied by external code. 373 374<P> 375"), 376 args:["Handle" : "An external data handle.", "Index" : "An integer.", "Value" : "A variable."], 377 exceptions:[4 : "Handle or Index is uninstantiated.", 378 5 : "Handle is not a handle, or Index is not an integer.", 379 6 : "Index is out of range (if check implemented by method).", 380 141 : "The get-method is not implemented for this handle."], 381 eg:" 382 /* C code with embedded ECLiPSe call, passing data via C ararys */ 383 #include \"eclipse.h\" 384 385 #define N 5 386 double data_in[N] = {1.1,2.2,3.3,4.4,5.5}; 387 double data_out[N]; 388 389 main() 390 { 391 pword call; 392 int i; 393 394 ec_init(); 395 ec_post_string(\"[my_code]\"); 396 ec_post_goal( 397 ec_term(ec_did(\"process\", 3), 398 ec_long(N), 399 ec_handle(&ec_xt_double_arr, (t_ext_ptr) data_in), 400 ec_handle(&ec_xt_double_arr, (t_ext_ptr) data_out) 401 ) 402 ); 403 if (ec_resume() == PSUCCEED) 404 { 405 for (i=0; i<N; i++) 406 printf(\"%f,\", data_out[i]); 407 } 408 ec_cleanup(); 409 } 410 411 412 /* ECLiPSe code in file my_code.pl */ 413 414 process(0, _, _) :- !. 415 process(N, In, Out) :- 416 N1 is N-1, 417 xget(In, N1, X), 418 Y is sqrt(X), 419 xset(Out, N1, Y), 420 process(N1, In, Out). 421 422 423 /* Sample run */ 424 425 % main 426 1.048809,1.483240,1.816590,2.097618,2.345208, 427 428 429 430 431", 432 see_also:[xset / 3, setarg / 3]]). 433 434:- comment(xset / 3, [ 435 summary:"Set the Index-th field of an external data structure (referenced by Handle) to Value. 436 437", 438 amode:(xset(+, +, +) is semidet), 439 desc:html(" ECLiPSe can manipulate external data structures via handles. 440 An external data handle can only be created by external code. 441 It consists of a pointer to the external data and a descriptor 442 for this data (a method table). ECLiPSe can then perform certain 443 operations on the data using this method table. 444 445<P> 446 The xset/3 predicate invokes one of the methods, the set-method. 447 The intended meaning is that a field of the external data structure 448 (indicated by Index) is set to the given Value. This setting 449 qualifies as a side-effect (similar to writing to a file) and is 450 not undone on backtracking. The details of how the index is 451 interpreted and which values are allowed depend on the set-method 452 supplied by external code. 453 454<P> 455"), 456 args:["Handle" : "An external data handle.", "Index" : "An integer.", "Value" : "A term."], 457 fail_if:"Fails if the set-method specifies failure for certain arguments", 458 exceptions:[4 : "Handle or Index is uninstantiated.", 459 5 : "Handle is not a handle, or Index is not an integer.", 460 141 : "The set-method is not implemented for this handle.", 461 other : "The set-method can raise any exception"], 462 eg:" 463 /* C code with embedded ECLiPSe call, passing data via C ararys */ 464 #include \"eclipse.h\" 465 466 #define N 5 467 double data_in[N] = {1.1,2.2,3.3,4.4,5.5}; 468 double data_out[N]; 469 470 main() 471 { 472 pword call; 473 int i; 474 475 ec_init(); 476 ec_post_string(\"[my_code]\"); 477 ec_post_goal( 478 ec_term(ec_did(\"process\", 3), 479 ec_long(N), 480 ec_handle(&ec_xt_double_arr, (t_ext_ptr) data_in), 481 ec_handle(&ec_xt_double_arr, (t_ext_ptr) data_out) 482 ) 483 ); 484 if (ec_resume() == PSUCCEED) 485 { 486 for (i=0; i<N; i++) 487 printf(\"%f,\", data_out[i]); 488 } 489 ec_cleanup(); 490 } 491 492 493 /* ECLiPSe code in file my_code.pl */ 494 495 process(0, _, _) :- !. 496 process(N, In, Out) :- 497 N1 is N-1, 498 xget(In, N1, X), 499 Y is sqrt(X), 500 xset(Out, N1, Y), 501 process(N1, In, Out). 502 503 504 /* Sample run */ 505 506 % main 507 1.048809,1.483240,1.816590,2.097618,2.345208, 508 509 510 511 512", 513 see_also:[xget / 3, subscript / 3]]). 514 515:- comment(yield / 2, [ 516 summary:"Yield control to the C/C++ main program that has invoked ECLiPSe. 517The arguments are used for passing data in and out. 518 519", 520 amode:(yield(+, -) is det), 521 desc:html(" When ECLiPSe is used as an embedded component within an application 522 written in C/C++, the ECLiPSe execution is conceptually a thread. 523 Therefore, a yield-resume control flow model is used. 524 On the C/C++ side, the ec_resume()/EC_resume() functions pass 525 control to the ECLiPSe thread, while on the ECLiPSe side, the 526 yield/2 predicate is used to pass control back. 527 Data can be passed both ways: the ToC argument of yield/2 is passed 528 to C/C++ via the second argument of ec_resume()/EC_resume() when it 529 returns. Similarly a ec_resume()/EC_resume() first argument is 530 passed to ECLiPSe as the FromC argument of yield/2. 531 532<P> 533 This mechanism is supposed to be used such that an ECLiPSe server 534 loop is set up, and the host program resumes ECLiPSe repeatedly 535 to have a request served. 536 537<P> 538 Note that, by default, ECLiPSe is set up as a server which calls 539 posted goals. This is such a general mechanism that it is often 540 not necessary to write a special-purpose server loop. 541 542<P> 543"), 544 args:["ToC" : "A term.", "FromC" : "A variable."], 545 eg:" 546 % ECLiPSe server code 547 start_server :- 548 eclipse_server(dummy). 549 550 eclipse_server(PrevResult) :- 551 yield(PrevResult, Request), 552 process_request(Request, NewResult), 553 eclipse_server(NewResult). 554 555 556 // C++ client code 557 ec_init(); 558 post_goal(\"start_server\"); 559 if (EC_resume() == EC_yield) 560 { 561 for(;;) 562 { 563\t // create a request 564 ... 565 if (EC_resume(request, result) != EC_yield); 566 break; 567 ... 568 // use the result 569 } 570 } 571 572 573 574", 575 see_also:[xget / 3, xset / 3]]). 576 577:- comment(remote_connect/3, [ 578 args: ["Address": "Address for remote connection (Host/Port or variable)", 579 "Peer": "Remote Peer name (atom or variable)", 580 "InitGoal": "Initialisation Goal (goal or variable)" 581 ], 582 amode:(remote_connect(?,-,?) is det), 583 amode:(remote_connect(?,+,?) is semidet), 584 summary: "Initiate a remote interface connection", 585 fail_if: "Peer is an existing peer name.", 586 desc: html("\ 587 588 <P> 589 Initiate a remote interface connection and sets up a remote peer 590 Peer. ECLiPSe will listen for a remote connection from another 591 process at the Address. Address can be either a variable, or 592 HostName/Port, where either HostName or Port can be variables. The 593 host name and port number are printed on log_output so that the 594 other process can use them. The other process must be able to form a 595 remote interface connection with ECLiPSe. When the predicate 596 returns, the remote process will have attached to the ECLiPSe 597 session. This predicate will block until the remote connection 598 is established, and the remote side hands over control. 599 600 <P> 601 Once the Address is printed by the predicate, this information can 602 then be used on the remote side to establish the remote connection, 603 according to the remote interface connection protocol described in 604 the Embedding and Interfacing manual. Once the connection is 605 established, the optional user initialisation is performed on the 606 ECLiPSe side before any further interactions. This is specified by 607 InitGoal: If InitGoal is not a variable, it gives the goal that will 608 be executed for the initialisation. If InitGoal is a variable, then 609 no user initialisation is done before the two sides can 610 interact. Initially, the remote side has control after the 611 connection, so the predicate will return only when the remote side 612 hands over control. Note that the predicate will not fail even if 613 InitGoal fails or aborts. 614 615 <P> 616 If Host and Port are initially not variables, they must be valid for 617 forming a socket connection. 618 619 <P> 620 This predicate is implemented by remote_connect_setup/3 and 621 remote_connect_accept/6. These two predicates can be used to 622 implement the remote connection, allowing for more flexibility. 623"), 624 see_also: [remote_disconnect/1, remote_yield/1, remote_connect_setup/3, remote_connect_accept/6], 625 eg: " 626 627% with the following definition for disconnect/0 628disconnect :- writeln(bye). 629 630% the following will cause `bye' to be printed when the remote connection 631% is disconnected 632 633remote_connect(_Address, Peer, set_event_handler(Control, disconnect/0)). 634", 635 exceptions: [5: "Host, Port or Peer not of correct type", 636 141: "The remote protocols of the remote and ECLiPSe sides are incompatible.", 637 170: "Port is not a valid port number" 638 ] 639]). 640 641:- comment(remote_connect_setup/3, [ 642 args: ["Address": "Address for remote connection (Host/Port or variable)", 643 "Peer": "Remote Peer name (atom or variable)", 644 "Socket": "Server socket stream number (variable)" 645 ], 646 amode:(remote_connect_setup(?,-,-) is det), 647 amode:(remote_connect_setup(?,+,-) is semidet), 648 summary: "First half of initiating a remote interface connection.", 649 desc: html("\ 650 <P> 651 Set up the initial stage for a remote interface connection. This 652 predicate type checks the arguments and creates a socket server at 653 address Host/Port. This socket server will accept the socket stream 654 connections from the remote process that is to be attached. The socket 655 server stream is returned in Socket. Peer should be the name of the new 656 remote Peer; if it is a variable, the predicate will assign a new name 657 to the Peer. If Peer is an atom, the predicate will fail if Peer is an 658 existing peer name (including names which has been created using 659 remote_connect_setup/3, but not yet attached by remote_connect_accept/6). 660 </P><P> 661 When the predicate returns, the remote process can make its socket 662 connections at Host/Port. The connecting request will suspend until 663 they are accepted on the ECLiPSe side by calling 664 remote_connect_accept/6. 665 </P><P> 666 This predicate should always be followed by a call to 667 remote_connect_accept/6, which completes the remote connection. The 668 predicates are separated to allow the user to start the connecting 669 request on the remote process. This can be done for example via exec/3. 670 </P><P> 671 If Host and Port are not initially variables, they must be valid for 672 forming a socket connection. If Host is `localhost', then the remote 673 connection would be restricted to the same host as the ECLiPSe process. 674 </P><P> 675 The predicates remote_connect_setup/3 and remote_connect_accept/6 are 676 used to implement remote_connect/3. 677"), 678 fail_if: "Peer is an existing peer name.", 679 exceptions: [5: "Arguments are not of the correct type"], 680 see_also: [remote_connect_accept/6, remote_disconnect/1, 681 remote_yield/1, remote_connect/3, exec/3] 682]). 683 684:- comment(remote_connect_accept/6, [ 685 args: ["Peer": "Remote peer name (atom)", 686 "Socket": "Server socket stream number (integer)", 687 "TimeOut": "Time out interval (atomic)", 688 "InitGoal": "Initialisation Goal (goal or variable)", 689 "PassTerm": "`PassTerm' for authenticating connection (term)", 690 "InitRes": "Result of executing the InitGoal (variable)" 691 ], 692 amode:(remote_connect_accept(+,+,+,?,+,-) is semidet), 693 summary: "Second half of initiating a remote interface connection.", 694 desc: html("\ 695 696 <P> 697 This predicate completes the remote interface connection started by 698 remote_connect_setup/3, which must be called before. The Peer and 699 Socket arguments should be the same as those in the call to 700 remote_connect_setup/3. 701 702 </P><P> 703 This predicate will accept the remote socket stream connections 704 according to the remote interface protocol described in the embedding 705 and interfacing manual. Peer is the name of the new remote peer. 706 TimeOut is used to specify the amount of time, in seconds, that the 707 predicate will wait for the remote connection. If TimeOut is the atom 708 block, then it will wait indefinitely for the connection from the 709 remote process. The predicate will fail if the interval specified in 710 TimeOut has elapsed while waiting for any of the connections with the 711 remote side (including any subsequent peer queue connections). 712 PassTerm is used for a simple authentication of the remote process: 713 once the control connection is established, but before the rest of the 714 creation of the ec_rpc link, the remote process must send a ECLiPSe 715 term that matches (the comparison is performed using ==/2) PassTerm. If 716 the terms fail to match, then the connection is closed and an out of 717 range exception raised. The term is specified in EXDR format on the 718 remote side. With the Tcl remote interface, the command to establish 719 the connection sends a default PassTerm that is the empty string. This 720 can be overridden by the programmer with a more complicated term. 721 After establishing the connection, InitGoal will be executed to perform 722 any user-defined initialisation on the ECLiPSe side, before any further 723 interactions between the two sides. The result of executing the goal is 724 passed back in InitRes; InitRes is set to fail and throw respectively 725 if the goal fails or throws an exception. 726 727 </P><P> 728 The socket server Socket will be closed upon successful completion of 729 the connection. It will also be closed if the predicate times out. 730 731 </P><P> 732 Once the connection is established, the optional user initialisation is 733 performed on the ECLiPSe side before any further interactions. This is 734 specified by InitGoal: If InitGoal is not a variable, it gives the 735 goal that will be executed for the initialisation. If 736 InitGoal is a variable, then no user initialisation is done before the 737 two sides can interact. The result of executing the goal is returned in 738 InitRes: the goal with its bindings if it was successful, the atom fail 739 if the goal failed, and the atom throw if an exception occurred. 740 InitRes should be uninstantiated initially; otherwise, InitGoal will 741 not be executed. 742 743 </P><P> 744 After the optional initialisation, the remote interface is 745 established. Initially, the remote side has control, and the predicate 746 will block, and returns when the remote side hands over control. 747 748"), 749 fail_if: "\ 750 TimeOut second has elapsed without a connection request; 751 Peer is not a remote peer name which is waiting to complete a remote connection.", 752 exceptions:[1: "PassTerm fails to match the term sent by the remote side.", 753 754 6: "Handshaking timed-out after 100 seconds.", 755 141: "The remote protocols of the remote and ECLiPSe sides are incompatible.", 756 193: "Socket is not a valid server socket." 757 ], 758 see_also: [remote_connect_setup/3, remote_disconnect/1, remote_yield/1, remote_connect/3] 759]). 760 761:- comment(remote_disconnect/1, [ 762 args: ["Peer": "Remote Peer (atom)"], 763 amode:(remote_disconnect(+) is det), 764 summary: "Disconnect the remote peer Peer", 765 desc: html("\ 766 767 <P> 768 If Peer is the name for a current remote peer, this predicate will 769 initiate a disconnection. Otherwise, the predicate succeeds without 770 performing any action."), 771 772 see_also: [remote_connect/3, remote_yield/1] 773]). 774 775:- comment(remote_yield/1, [ 776 args: ["Peer": "Remote peer (atom)"], 777 amode:(remote_yield(+) is semidet), 778 summary: "Explicitly yield to the remote peer Peer", 779 desc: html("\ 780 781 <P> 782 If Peer is a valid current remote peer, this predicate will cause the control to be 783 transfer to that peer, i.e. the ECLiPSe will yield to the remote 784 side. This predicate returns when ECLiPSe side resumes control. 785 If the remote side initiates disconnection while it has control, 786 remote_yield/1 will abort after the disconnection. 787"), 788 exceptions: [peer_abort_disconnected : "Peer has disconnected.", 789 peer_abort_error : "Some internal error has occured (this should be reported as an ECLiPSe bug to the ECLiPSe team)." 790 ], 791 fail_if: "Peer is not a valid current remote peer.", 792 see_also: [remote_connect/3, remote_disconnect/1] 793]). 794 795:- comment(peer/1, [ 796 args: ["Peer": "Peer name (atom or variable)."], 797 amode:(peer(-) is nondet), 798 amode:(peer(+) is semidet), 799 summary: "Checks or enumerates peer names", 800 desc: html("\ 801 <P> 802 If Peer is a variable, this predicate enumerates the current peers 803 (remote and embedded). If Peer is an atom, it checks if that is the name 804 of a current peer. 805 "), 806 fail_if: "Peer is not a current peer.", 807 exceptions: [5: "Peer is neither an atom or a variable."], 808 see_also: [peer_get_property/3] 809]). 810 811:- comment(peer_get_property/3, [ 812 args: ["Peer": "Peer name (atom).", 813 "Property": "Property name (atom or variable).", 814 "Value": "Value of property Property for Peer." 815 ], 816 amode:(peer_get_property(+,+,-) is semidet), 817 amode:(peer_get_property(+,-,-) is nondet), 818 summary: "Returns the properties of the peer Peer.", 819 desc: html("\ 820 <P> 821 If Property is a variable, this predicate will enumerate on backtracking 822 all the properties of peer Peer. If Property is instantiated to a valid 823 property name, the value of the property for Peer is unified with Value. 824 825 <P> 826 Property is one of the following: 827 828<P> 829<PRE> 830 type peer type (remote or embed) 831 language peer language (e.g. \"tcl\" or \"java\") 832 connect connection information. Either: 833 remote(LocalHost,PeerHost,TimeOut) or 834 embed(Host,Host,block) 835 queues current peer queues (list of stream ids) 836</PRE> 837<P> 838 'connect' returns the information on the connection for the peer. This 839 information is mainly relevant only for remote peers, but is provided 840 for the embedded peer for compatibility. The arguments for the remote 841 and embedded cases are equivalent, and are: 842<PRE> 843 LocalHost Original local Host specification at peer creation 844 PeerHost Host for the Peer 845 TimeOut Time-out interval for creating new peer queues 846</PRE> 847 For remote peers, LocalHost specifies how the local hostname will be 848 specified when setting up a connection between the peer and ECLiPSe. It 849 is the same as how the hostname was specified initially when the peer 850 was set up: it can be either a variable, the actual hostname, or the 851 special name 'localhost'. The specification may place restrictions on how 852 the peer side client connection is specified. In particular, 'localhost' 853 would restrict the peer to be on the same host as ECLiPSe. PeerHost is 854 either the hostname of the machine the peer is running on, or 855 'localhost'. TimeOut is the time-out interval (in seconds) for accepting 856 peer queues, or the atom 'block' if there is no time-limit. 857<P> 858 The LocalHost and PeerHost are identical for the embedded peer, and is 859 the hostname Host of the machine. There are no time-outs, so TimeOut 860 argument is the the atom 'block'. 861 862 "), 863 fail_if: "Peer is not a current peer; Property is not a valid property.", 864 see_also: [peer/1], 865 exceptions: [5: "Peer or Property not of the right type."] 866]). 867 868:- comment(peer_queue_create / 5, [ 869 args: ["Queue": "Name of peer queue (atom)", 870 "Peer": "Peer name (atom)", 871 "QueueType": "Queue type (sync or async)", 872 "Direction": "Queue direction (fromec, toec or bidirect)", 873 "Event": "Event for peer queue (atom or event handle)" 874 ], 875 amode:(peer_queue_create(+,+,+,+,+) is semidet), 876 summary: "Create a new peer queue Queue for Peer from ECLiPSe side.", 877 desc: html("\ 878<P> 879 Creates a new peer queue Queue for peer Peer from ECLiPSe 880 side. The nature of queue created is specified by the other arguments 881 (see the Embedding and interfacing manual for more details on peer queues): 882 883<DL> 884<DT>QueueType<DD> 885 Type of the queue: either synchronous (sync) or asynchronous (async). 886 887<DT>Direction<DD> 888 Direction of the synchronous queue: either from ECLiPSe to remote 889 (fromec) or to ECLiPSe from remote (toec). This argument is ignored 890 for asynchronous queues, which are bidirectional. 891 892<DT>Event<DD> 893 Name or handle of event that will be raised on the ECLiPSe side when 894 data arrives. Applicable only for data sent from remote side to ECLiPSe. 895 If Event is the empty atom '', then no event will be associated with 896 the peer queue. 897</DL> 898<P> 899 This predicate will cause the queue to be created (if permitted by 900 the remote side) on both the ECLiPSe and remote sides. Alternatively, 901 the queue can be created from the remote side. Note in either case, 902 the creation is done only on one side, and the created queue appears 903 on the other side without an explicit creation there. Note also that 904 if the queue is created on the ECLiPSe side, there is no way to name 905 the handler on the remote side for data arriving on the remote side. 906<P> 907 In the case of a remote peer, the queue is connected by a socket 908 connection between the two sides. The server socket is created on the 909 ECLiPSe side, and it will wait at most TimeOut seconds for the remote 910 side to make the connection. TimeOut is the time specified in 911 remote_connect_accept/6 when the remote peer was created. In 912 addition, when the client socket connection is accepted, ECLiPSe 913 checks to ensure that the client's host is the same as the one that 914 formed the attachment. If not, then the connection is from someone 915 else, and ECLiPSe will reject and close the queue connection. 916 "), 917 exceptions:[5: "QueueName, Peer or Event not of the correct type.", 918 6: "QueueType or Direction not of permitted values." 919 ], 920 see_also: [peer_queue_close/1, peer_queue_get_property/3, remote_connect_accept/6, 921 event_create/3], 922 fail_if: "Peer is not a current peer." 923]). 924 925 926:- comment(peer_queue_close/1, [ 927 args: ["Queue": "Peer queue (atom or integer)"], 928 amode:(peer_queue_close(+) is semidet), 929 summary: "Closes the peer queue Queue from ECLiPSe side.", 930 desc: html("\ 931<P> 932 Close the peer queue Queue from ECLiPSe side. When this predicate 933 returns, the peer queue would be closed on both the ECLiPSe and remote 934 sides, and book-keeping information on both sides updated to exclude the 935 queue. As with creating a peer queue, closing a peer queue is performed 936 explicitly from one side only. 937 938<P> 939 The user should not close a peer queue with close/1. This will only 940 close the ECLiPSe end of the queue, and would not remove the 941 book-keeping information. Note that peer_queue_close/1 will still remove 942 the book-keeping information if some of the underlying streams 943 associated with the peer queue are already unexpectedly closed. 944 "), 945 fail_if: "Queue is not a current peer queue.", 946 see_also: [peer_queue_create/5, peer_queue_get_property/3], 947 exceptions: [5: "Queue is not an atom or integer."] 948]). 949 950 951:- comment(peer_queue_get_property/3, [ 952 args: ["Queue": "Peer queue (atom or integer).", 953 "Property": "Queue property name (atom or variable).", 954 "Value": "Value of property Property." 955 ], 956 amode:(peer_queue_get_property(+,+,-) is semidet), 957 amode:(peer_queue_get_property(+,-,-) is nondet), 958 summary: "Get or enumerate properties of a peer queue Queue.", 959 desc: html("\ 960<P> 961 Get or enumerate properties of a peer queue Queue. If Property is a 962 variable, the properties of the queue will be enumerated on 963 backtracking. Otherwise, if Property is a property name, the value for 964 that property for Queue is unified with Value. The properties are: 965 966<P> 967<PRE> 968 type type of queue: 969 sync(SId): synchronous queue 970 SId is Socket Id for remote peers, 971 Stream Id for the embedded peer 972 async: asynchronous queue 973 direction direction of queue: 974 fromec: from ECLiPSe to remote 975 toec: to ECLiPSe from remote 976 bidirect: bidirectional 977 peer_type type of the peer that Queue belongs to: 978 embed : for embedded peer 979 remote : for remote peer 980 peer_name name of the peer that Queue belongs to. 981</PRE> 982 "), 983 fail_if: "Queue is not a current peer queue.", 984 see_also: [peer_queue_create/5, peer_queue_close/1] 985]). 986 987 988:- comment(peer_register_multitask/2, [ 989 args: ["Peer": "Existing peer name (atom)", 990 "MsgQ": "From ECLiPSe Multitasking message queue (variable)" 991 ], 992 amode:(peer_register_multitask(+,-) is semidet), 993 see_also: [peer_do_multitask/1, peer_multitask_terminate/0, 994 peer_multitask_confirm/0, peer_deregister_multitask/1], 995 summary: "Registers the peer Peer for peer multitasking.", 996 exceptions: [6: "Peer is not an existing peer name"], 997 fail_if: "Peer is already registered for multitasking.", 998 desc: html("\ 999<P> 1000 This predicate is intended for use only in implementing peer 1001 multitasking for an external language interface. 1002</P><P> 1003 Registers the existing peer Peer as a multitask peer. A peer 1004 queue MsgQ for Peer is created to control the multitasking. 1005 Only peers which are registered as a multitasking peer participate in 1006 the multitasking phase.") 1007]). 1008 1009:- comment(peer_deregister_multitask/1, [ 1010 args: ["Peer": "Existing multitasking peer name (atom)"], 1011 amode:(peer_deregister_multitask(+) is semidet), 1012 see_also: [peer_register_multitask/2, peer_do_multitask/1, peer_multitask_terminate/0, peer_multitask_confirm/0], 1013 summary: "Deregisters and removes the peer Peer from peer multitasking.", 1014 exceptions: [6: "Peer is not an existing peer name"], 1015 fail_if: "Peer is a peer, but not registered for multitasking.", 1016 desc: html("\ 1017<P> 1018 This predicate is intended for use only in implementing peer 1019 multitasking for an external language interface. 1020</P><P> 1021 Deregisters the existing multitasking peer Peer as a multitask peer. 1022 The multitasking control peer queue for Peer, created when the peer was 1023 registered for multitasking, is closed. Peer will no longer be involved 1024 in future multitasking phases. 1025</P><P> 1026 Note that while information associated with the multitasking for Peer is 1027 removed from the ECLiPSe side, any information on the external side is 1028 not touched. It is the responsibility of the external language interface 1029 to remove any multitasking information on the external side, before or 1030 after using this predicate.") 1031]). 1032 1033:- comment(peer_do_multitask/1, [ 1034 args: ["Type": "User defined term (term)"], 1035 amode:(peer_do_multitask(+) is det), 1036 summary: "Perform a multitasking phase.", 1037 exceptions: [peer_multitask_empty: "No peer is currently registered for" 1038 " multitasking."], 1039 1040 see_also: [peer_register_multitask/2, peer_multitask_terminate/0, peer_multitask_confirm/0], 1041 desc: html("\ 1042<P> 1043 This predicate is intended for use only in implementing peer 1044 multitasking for an external language interface. 1045</P><P> 1046 Multitasking is done within this predicate. That is, a multitasking 1047 phase is initiated when the predicate is called, and when the multitasking 1048 phase is finished, the predicate returns. If the abort exception is 1049 raised during the multitasking phase, the multitasking phase is properly 1050 terminated before the abort continues. 1051</P><P> 1052 Type is a user defined term that is passed to all the multitasking 1053 peers when the multitasking phase is initiated. This allows the 1054 programming of different types of multitasking situations. Type must be 1055 representable as an EXDR term. 1056</P><P> 1057 This is the only way to initiate multitasking, so if the user wishes to 1058 to initiate multitasking from a peer, they should call this goal 1059 via an ERPC. 1060</P><P> 1061 During a multitasking phase, multitasking peers are each given a 1062 time-slice in round-robin fashion. They are allowed to perform ERPC 1063 during the time-slice. (More precisely: they are allow to execute 1064 peer-side code that contains ERPCs). 1065</P><P> 1066 To participate in peer multitasking, a peer should first be registered 1067 using peer_register_multitask/2. A peer can then initiate multitasking 1068 by calling peer_do_multitask/1 while the peer has control. The 1069 multitasking phase is started, and all registered peer will be informed 1070 during their time-slice that a multitasking phase has started. If the 1071 peer is interested in this particularly multitasking phase (as specified 1072 in Type), they should execute peer_multitask_confirm/0. The multitasking 1073 phase can be terminated by any peer by calling 1074 peer_multitask_terminate/0. 1075 ") 1076]). 1077 1078:- comment(peer_multitask_confirm/0, [ 1079 summary: "Confirm a peer multitasking phase.", 1080 amode:(peer_multitask_confirm is det), 1081 desc: html("\ 1082<P> 1083 This predicate is intended for use only in implementing peer 1084 multitasking for an external language interface. 1085</P><P> 1086 A multitasking phase is confirmed by this predicate. That is, when a 1087 multitasking phase is initiated by a call to peer_do_multitask/1, this 1088 predicate should be executed for the multitasking phase to continue. If 1089 this predicate is not executed, the multitasking phase will be 1090 terminated. It is intended that this predicate is executed via an ERPC 1091 by a peer when the multitasking phase is initiated, if that peer is 1092 interested in the phase. A multitasking phase will be ended when 1093 peer_multitask_terminate/0 is called. 1094 "), 1095 see_also: [peer_do_multitask/1, peer_multitask_terminate/0] 1096]). 1097 1098:- comment(peer_multitask_terminate/0, [ 1099 summary: "Terminate a peer multitasking phase.", 1100 amode:(peer_multitask_terminate is det), 1101 desc: html("\ 1102<P> 1103 This predicate is intended for use only in implementing peer 1104 multitasking for an external language interface. 1105</P><P> 1106 A multitasking phase is terminated by this predicate. That is, when this 1107 predicate is executed, then the end of the multitasking phase is 1108 initiated. ECLiPSe will then inform all the multitasking peers that 1109 the current multitasking phase is over. It is intended that this 1110 predicate be executed via an ERPC by a peer when it wants to initiate 1111 the end of a multitasking phase. 1112 "), 1113 see_also: [peer_multitask_confirm/0] 1114]). 1115 1116 1117 1118