This is the mail archive of the guile@cygnus.com mailing list for the guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Process communication with Guile


Recently, I wrote:
; The problems I am interested in (solving of partial differential
; equations) usually can be decomposed in such a way that a rather small
; set of basic operations operating on large amounts of data are
; combined to more complicated constructs.  This seems to be a perfect
; place for using Guile as control language.  But since the interpreter
; is quite large I would prefer to do it in such a way, that Guile is
; sort of a client process to a server process written in C or C++ which
; does the hard work.  This construction would also allow to execute the
; client and server on different machines which might be very useful.

Andrew Archibald wrote back some tips and closed with:
> Good luck --- and tell us what you end up doing. 
>
> Andrew

which is what I want to do now. First a short review of messages
addressed directly to me (and maybe of interest to all):

1) Aleksandar Bakic told me about an extension to Guile that allows
   reading/writing in-memory XDR streams (a project finishing in the
   next time).  This sounds good, and might be useful also for me
   later on.  For the moment, I want something more basic.

2) Julian Satchell recommended to use sockets, and described his
   access very carefully.  Thanks to that I have managed to install a
   client/server pair using send/recv!.  I am not yet satisfied with
   this, since I would like to use Guile read/write over ports.  And
   it seems to be tricky to make the server safe: anyone can access it
   via the socket.

3) Telford Tendys pointed out to me the Sockets-FAQ-Homepage
   http://kipper.york.ac.uk/~vic/sock-faq which helped me to finish
   the socket example.

In spite of the advices for sockets, my favorite solution at the
moment is the following process communication via pipes.  If the
server process is on a remote computer one uses rsh or ssh to
communicate with it:

---
A simple C-server using stdin/stdout:
#include <stdio.h>
#include <strings.h>

#define MAXBUFF 1024

int main (void)
{
	char buffer[MAXBUFF];
	while (fgets(buffer, MAXBUFF, stdin)!=NULL)
	{
		if (strcmp(buffer, "quit\n")==0)
			break;
		fputs(buffer, stdout);
		fflush(stdout);
	}
	return(0);
}

---
The Guile procedures:

;; definition of procedures
;;
;; open-connection executes a remote-process and returns
;; a triple (childpid input-port . output-port)
;; write-message, read-message and close connection
;; then use this triple to perform their operation

(define (open-connection)
  (let* ((to-pipe (pipe))
		 (from-pipe (pipe))
		 (childpid (primitive-fork)))
	(if (< childpid 0)
		(display "Could not fork!\n")
	  (if (> childpid 0)

		  (begin
		   ;; parent
		   ;; close what we don't need
		   (close (car to-pipe))
		   (close (cdr from-pipe))

		   ;; return (childpid input-port . output-port)
		   (cons childpid 
				 (cons (car from-pipe) (cdr to-pipe)))
		   )
		
		(begin
		 ;; child
		 ;; close what we don't need
		 (close (cdr to-pipe))
		 (close (car from-pipe))

		 ;; set stdin/stdout to the pipes
		 (dup->inport (car to-pipe) 0)
		 (dup->outport (cdr from-pipe) 1)

		 ;; and give control to our remote process via ssh
		 (execl "/usr/local/bin/ssh" "eiger" "/tmp_mnt/hosts/mango/neuss/test"))
		)) ) )

(define (write-message process object)
  (begin
   (write object (cddr process))
   (newline (cddr process))
   (force-output (cddr process))
   ))

(define (read-message process)
  (begin
   (read (cadr process))
   ))

(define (close-connection process)
  (begin
   ;; send quit command to process
   (display "quit" (cddr process))
   (newline (cddr process))
   (force-output (cddr process))

   ;; close io-channels
   (close (cadr process))
   (close (cddr process))
   ))

---

It seems to work quite fine, only one problem is left: after

(define conn (open-connection))
(write-message conn "Hello")
(read-message conn)
(close-connection conn)

the connection is not completely terminated, i.e. "ps -u neuss" lists
the former ssh-process with name <defunct> on my machine, which can't
be killed (error: no such job).  It's not ssh's fault since it occurs
also when using a local server process.  It vanishes when I leave
Guile.  Does anyone know how it can be done better?

Yours, Nicolas Neuss.

P.S.: Also other suggestions are welcome, of course.  I'm a beginner
in LISP.