The 2-way pipe works only in interactive mode?

Started by pjot, October 06, 2004, 12:27:02 PM

Previous topic - Next topic

pjot

Hi Lutz,



With your new version 8.2.1 I have been struggling with the new pipe structure for the process command.



I found something very interesting. It appears that from the newLisp program side, there are actually 2 filehandles, 1 for read, and 1 for write. From the executed process however, stdin and stdout are seen as the same pipe!



When starting a process like this:



# Start the process

(map set '(in out) (pipe))

(process "bc" in out)



...newlisp will fork itself, and then setup a popen to the BC binary. Schematically,  this leads to the following result:



 +-----------+   in    +----------------+         +--------+
  |           |---------+                |  in&out |        |
  | newLisp   |         | forked newlisp |---------+ binary |
  |           |---------+                |         |        |
  +-----------+   out   +----------------+         +--------+

This has an unpleasant side effect. For the forked newlisp and the started binary cannot distinguish between stdin or stdout. If you run the program below you will see what I mean:

#!/usr/bin/newlisp
#
# Start the process
(map set '(in out) (pipe))
(process "bc" in out)

# Execute calculations
(write-line "3 + 4" out)
(println (read-line in))

(write-line "2 + 4" out)
(println (read-line in))

(write-line "1 + 4" out)
(println (read-line in))

(write-line "0 + 4" out)
(println (read-line in))

(exit)

The result of this program is:



3 + 4

2 + 4

1 + 4

0 + 4



Of course this is the result! The forked newlisp will read off the pipe immediately, before the BC binary even has time to catch the input.



I experience the same problem with my GTK-server. Here, the GTK-server will print a result to the pipe, but it reads off the stdin pipe immediately after that, so it reads it's own result again. That is because stdin and stdout are in fact the same pipe.



Concluded: your "process <str> in out" cannot be used in an actual program, but only in interactive mode.....



Is there a way to work around this?



Peter

pjot

#1
PS I forgot: in the documentation the "process" command is described as:



syntax: (process str-command int-in int-pipe-in int-pipe-out)



So what does "int-in" means? Your examples do not mention this...?

Lutz

#2
In your case you need two pipes:



#!/usr/bin/newlisp
#
# Start the process
(map set '(myin bcout) (pipe))
(map set '(bcin myout) (pipe))
(process "bc" bcin bcout)

# Execute calculations
(write-line "3 + 4" myout)
(println (read-line myin))

(write-line "2 + 4" myout)
(println (read-line myin))

(write-line "1 + 4" myout)
(println (read-line myin))

(write-line "0 + 4" myout)
(println (read-line myin))

(exit)


This gives you (FreeBSD):



7

6

5

4



I will mention this in the documentation. I guess you could also work with one pipe if you syncronize access to it with 'semaphore'.



Lutz

Lutz

#3
>>>

So what does "int-in" means? Your examples do not mention this...?

>>>



is a doc error, will be corrected



Lutz

pjot

#4
Well, this works perfectly OK!! I never would have thought of the double pipe myself - smart idea!! What would the newLisp community be doing without you?



Below a GTK-server demo program, which I will put on my site as well:

# Define communication function
(define (gtk str)
(write-line str myout)
(if (!= str "gtk_exit(0)") (set 'tmp (read-line myin)))
tmp)

# Setup gtk-server
(map set '(myin gtkout) (pipe))
(map set '(gtkin myout) (pipe))
(process "gtk-server stdin" gtkin gtkout)

# Connect to the GTK-server
(gtk "gtk_init(NULL, NULL)")
(set 'win (gtk "gtk_window_new(0)"))
(gtk (append "gtk_window_set_title (" win ", This is a title)"))
(gtk (append "gtk_window_set_default_size (" win ", 100, 100)"))
(gtk (append "gtk_window_set_position (" win ", 1 )"))
(set 'table (gtk "gtk_table_new(30, 30, 1 )"))
(gtk (append "gtk_container_add (" win "," table ")"))
(set 'button1 (gtk "gtk_button_new_with_label (Exit)"))
(gtk (append "gtk_table_attach_defaults(" table ", " button1 ", 17, 28, 20, 25)"))
(set 'button2 (gtk "gtk_button_new_with_label (Print text)"))
(gtk (append "gtk_table_attach_defaults (" table ", " button2 ", 2, 13, 20, 25)"))
(set 'entry (gtk "gtk_entry_new()"))
(gtk (append "gtk_table_attach_defaults (" table ", " entry ", 2, 28, 5, 15)"))
(gtk (append "gtk_widget_show_all(" win ")"))

# Mainloop starts here
(set 'event1 0)
(set 'event2 0)
(while (and (= (integer event1) 0) (= (integer event2) 0))
(gtk "gtk_main_iteration()")
(set 'tmp (gtk (append "gtk_server_callback(" button2 ")")))
(if (> (integer tmp) 0)
(begin
(set 'tmp (gtk (append "gtk_entry_get_text(" entry ")")))
(println (append "This is the contents: " tmp))))
(set 'event1 (gtk (append "gtk_server_callback(" button1 ")")))
(set 'event2 (gtk (append "gtk_server_callback(" win ")")))
)
(gtk "gtk_exit(0)")
(exit)

The big advantage of this communication is, that it is extremely fast, and does not consume any sockets or pipes e.g. system resources. I consider this the preferred interface for the GTK-server.



It also may be nice to know that newLisp by far is the langauge which supports most communications interfaces right now: 7 out of 8. The next language is GNU Prolog with 5 out of 8. (The last interface option would be 2-way pipes on Windows - but I can live without it... ;-) )



Again thank you very much. The redirecting of stdin/stdout also comes handy in many other situations. I've used it a lot with KSH myself, you can do a lot of nice tricks with this functionality. Thanks!!

pjot

#5
I will look into the semaphores also...

pjot

#6
Hi Lutz,



The pipes in your new version work ok in Windows!



Now newLisp is the first language to support all communication interfaces with the GTK-server. I will mention newLisp as the recommended interpreted language on the GTK-server website.



Thank you very much for your good work!



It also may be interesting to know that the GTK-server has reached version 1.2 with big enhancements on the callback mechanism. The last limitation ("one-signal-per-widget") is history.





Cheers



Peter