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 &lt;binary&gt; -T &lt;addr&gt; -o /tmp/eclipse.&lt;pid&gt;.N &lt;File&gt; -lc 1&gt;&amp;2
148   2&gt;&amp;2
149</PRE>
150   where &lt;pid&gt; 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