Newbie questions about Pliant

Newbie questions about Pliant

Stream question

Questions about streams that aren't in pliant doc. pages
Message posted by szamo on 2002/05/25 03:54:40
My main question is how can i write a loop that checks if a tcpip stream
contains data to read, and handles the data if data is received, and executes
the remaining part of loop even if no data is received. I wrote a little code
(only the important lines are written here):

######################
gvar Stream s
gvar Address p
gvar Int nr
s open "tcp://hostname/client/1234" in+out
while not s:atend
  s read_available p nr
  if nr > 0
    console nr
  console "This should be displayed even if no data is received." eol
s close
######################

The problem with this code is that calling s:atend blocks the execution if no
data is received, thus the "This should be..." message isn't displayed
continuously, only when s:atend returns false (which means it could read data).
I have no idea how i can do it, and i wanted to try the configure method for
streams, but then i realized the pliant document doesn't say anything about it,
except the syntax. My idea was to configure the stream that way it doesn't
block program execution, however i really don't know how to solve it.
So my second question is what commands can be used in configure/query methods,
where can i read a document about it?
Message posted by maybe pom on 2002/05/25 07:06:06
To answer directly your question, you may:
1/ configure your Stream to timeout, (quite bad, actually)
2/ create a thread to handle it:
gvar Stream s
 gvar Address p
 gvar Int nr
 s open "tcp://hostname/client/1234" in+out
 thread
   while not s:atend
     s read_available p nr
     if nr > 0
       console nr
   s close
 # do anything else here

Message posted by maybe pom on 2002/05/25 07:16:04
to configure your TCP stream to timeout in a specified amount of time,
th syntax is:

s configure "timeout 10"
Message posted by maybe pom on 2002/05/25 07:22:14
Last remark:
instead of
s open "tcp://hostname/client/1234" in+out
you could write
s open "tcp://hostname/client/1234" in+out+safe

a "safe" open allows the connection to crash without error raising
Instead, in case of error, the file will be simply marked as crashed.
Any further attempt to write will be ignored, and attempts to read will
return as much zeros as requested. Test on the stream status may then be 
performed using "is_crashed" method.
Message posted by thomasb on 2002/05/25 20:07:43
Please note that configure timeout have no effect on tcp streams.
http://pliant.cx/pliant/language/stream/tcp.pli#method+configure
Message posted by maybe Hubert Tonneau on 2002/05/25 21:31:27
> Please note that configure timeout have no effect on tcp streams.

Your wrong: it sets the 'timeout' field as a result of the parsing line,
and the field will be used by the 'read' method.
Message posted by maybe szamo on 2002/05/28 15:40:20
Thanks for the help. My goal was to write a small telnet client, since i didn't
find it amongst pliant applications. The safe option of stream is really good to
have, it (and threads) helped coding the telnet function. The timeout works on
tcp stream, you can test it with this function. What i miss is that the
readline/read_available methods return without telling whether it failed to read
because stream is alive (can't check with is_open), or the stream is still alive
but timeouted. As i saw, there is no way to check if stream is alive. Only atend
method can say if the stream is at the end, but it means only there is no
avaialble data to read currently.
Assuming we would know if the stream is dead, my other question is how i could
terminate the keyboard_input function, which is waiting for input while the
stream has died in the meantime. I guess i shouldn't use the keyboard_input, and
should read only characters, thus i could check the stream status between
characters.
Anyway, here is my telnet function, it's very basic, but works. The hostname and
port must be set correctly in the tcp:// line, of course. Return argument of
telnet function isn't really used yet.

function telnet -> f
  arg Int f
  var Stream s                                   
  s open "tcp://hostname/client/portnr" safe+in+out
  s configure "timeout 0.01"
  thread
    while not s:is_crashed
      var Str str
      str := s readline
      if str:len > 0
        console str eol
  thread
    while not s:is_crashed
      var Str str
      str := keyboard_input ""
      s writeline str
  while not s:is_crashed
    sleep 1
  s close
  f := 0

export telnet
Message posted by maybe Hubert Tonneau on 2002/05/28 15:52:01
> As i saw, there is no way to check if stream is alive

Of course there is:
Assuming that your stream is 's', you can write things like:
if s=success
  ...
Message posted by maybe Hubert Tonneau on 2002/05/28 15:54:04
Another way to test if the stream is dead is (does exactly the same thing):

if s:is_crashed
  ...

And if you want to reuse it after a timeout occured, you can do:
s recover
Message posted by maybe Hubert Tonneau on 2002/05/28 16:05:40
> my other question is how i could terminate the keyboard_input function

The Pliant console interface is very primitive, and I have no plan to turn
it to a full featured one. HTTP is the high end interface, and the more
interactive applications are expected to benefit from improvements in the
DOM direction rather.

There is a 'os_socket_wait' function in /pliant/language/os/socket.pli
that you can use of some operating systems to test if a given handle has
datas available for reading, but knowing the keybord file handle is not
completely trivial in the current code. The Unix standard is that it is
handle 0, but it may not work on some OSes.
Message posted by maybe Szamo on 2002/05/30 00:49:29
What is DOM?

About checking if stream is alive: as you probably noticed, i used the
s:is_crashed expression (assuming s is the stream) in the code, but it can't
tell if the stream is alive. I looked into the code, and saw that
read_available calls atend, which tries to read bytes from the stream driver.
It can return for two reasons in my example, first if there is no data received
within timeout, second if the stream is not alive (I can clearly prove this
with displaying something in the reading thread, because when the stream is not
alive, it doesn't wait for timeout, so the displaying is much faster). The
is_crashed or success what you are talking about returns basically the crashed
flag, which is set only when the stream code notices error. Since reading
nothing from a stream is not an error, it's not crashed.
I hope i managed to describe the situation a bit better.

(I post my other question about console in a different note, so it will suit
the note title :).
Message posted by maybe Hubert Tonneau on 2002/05/30 08:12:20
Seems that you are perfectly right. I have to think more about it.
Message posted by maybe Szamo on 2002/07/07 22:06:19
Another problem (?) with flush sync. First here is the code i use (similar to
previous but uses flush sync.

module "/pliant/language/unsafe.pli"
module "/pliant/language/stream.pli"
module "/pliant/language/ui/ansi_terminal.pli"

function telnet hostname port-> f
  arg Str hostname port; arg Int f
  var Stream s
  var Str tcpip := "tcp://" + hostname + "/client/" + port
  s open tcpip in+out+safe
  s configure "timeout 0.1"
  thread
    part reading
      while not s:is_crashed
        s read_available (var Address p) (var Int nr)
        console "X" # for testing, to see this thread is running
        if nr > 0
          var Str l
          l set p nr false
          console l
        restart reading
  thread
    part writing
      while not s:is_crashed
        var Str k := keyboard_input ""
        if s:is_crashed
          console "Stream has closed, can't write!" eol
          leave writing
        s writeline k
        s flush sync # This 'crashes' the stream on linux, but not on windows
  while not s:is_crashed
    sleep 1
    console "Y" # for testing, to see this thread is running
  if s:is_crashed
    console "Stream crashed!" eol
  s close
  f := 0

export telnet

My question is that if using 's flush sync' is logical/required, or has sense,
and why it crashes the stream on linux, but not on windows? (I use debian, and
win98). If i comment the 's flush sync', it works well on linux (didn't try on
windows, but probably i had reason why i wrote it there, can't remember though).
Message posted by maybe Hubert Tonneau on 2002/07/08 23:16:07
It's not always safe to use the same stream both for reading and writing at
once. If you do it anyway, you must at least open the stream with 'noautopost'
flag:

  s open tcpip in+out+safe+noautopost

The reason is that when Pliant get's on a read command in a stream, it will
flush the output queue if some data is cached there (in order to avoid
infinit wait case where both ends of a pipe would wait for reading but none
would flush it's output cache).
The 'noautopost' flag will disable this feature.
Now, since there are no semaphores in the Pliant Stream machinery, if you have
two threads accessing the same stream at once, one reading and one writting,
then if the 'noautopost' flag is not set, then the reading thread will also
try to write first, so you end with two threads trying to write the same datas:
not good.