Hi Tomas,

> >> > Not necessarily. If we use the select() mechanism provided by '*Run'
> >> > and 'task', you can make input operations like 'listen', 'accept',
> >> > 'read', 'rd' etc. non-blocking.
> select() does not make thinks non-blocking as far as I am aware.  It
> just wakes up the process when something is going on.

Well, not non-blocking in the strict sense. But I think you can make
pretty sure that I/O won't block, i.e. behave as if non-blocking.

> I think that to be non-blocking, all I/O operations must be able to
> say how much data to read/write without blocking.

Yes, that's what happens. Any call to read() will never block, and
return the available amount of data. It is the application that must
make sure to collect the partial chunks of data (which would be the same
case if you use real non-blocking I/O).

> Does not (line) try to read until eol or eof?  That could block if the
> client is "naughty" or something happens (like delay while receiving

Correct. This may happen quite easily if the connection is cut off in
between. That's why I suggested to use 'alarm' to catch such cases and
return something useful. But in a non-forking system, even that is
unsatisfactory, as during the (necessarily not too small) timeout period
the whole system is blocked, not just that single client.

> > For the above communication between my own machines, I can guarantee
> > that no message received with the (rd) is longer than the system pipe
> > buffer size (at least 4096 bytes, larger on most systems). In that case
> > the (rd) will never block if select() said that data are available.
> How can you guarantee that? Simply by sending little data or some
> special protocol?

Yes. As 'pr' and 'rd' are used (the so-called PLIO protocol), the
involved parties are either other PicoLisp processes or custom
applications. In the described cases single executable expressions are
exchanged, typically far less than 100 bytes in size.

Keeping the PIPE_BUF limit in mind is extremely important when
communicating over pipes (sic!) with multiple writers, to guarantee
atomicity. For example, the PicoLisp kernel takes care of that during
'commit' (see, for example, "src/io.c:3317" and "src/io.c:3346").

> Also, that is a very special case.  I don't think you can make such
> assumptions with HTTP server where you don't have the clients under
> control.

Yes, true.

> > chunked transfers, or character by character to be absolutely sure) in a
> > single step in the 'task' body. select() will either return immediately
> ...
> How big is a reasonable chunk?  What if something happens (a delay)

I would expect a correctly implemented client to keep the chunk size
below the typical PIPE_BUF size (4096 bytes).

> with the client in the middle of sending the chunk?

Well, as before, you still need to either timeout, or assemble the
chunks is separate 'task's whenever the next part arrives. That's why I
suggested to go down to "character by character".

> Would not reading by character loose the magic of striving for
> supercalifragilisticexpialidoucious server?;-)

Yes, it might get clumsy, but only in the lowest layer which could
assemble the messages in the background and signal the higher layers
when a complete message is available.

> server in picolisp is of the first kind.  Once the server is serving a
> request, everything else (all the other requests) have to wait until
> it is finished with the current task.

Yes, at least it will get complicated to put such processing into
separate task's. And all responses will appear much less smooth. That's
why I still prefer the forking server ;-)

- Alex

Reply via email to