bug-gawk
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [bug-gawk] Adding an API hook to enable a select extension


From: Andrew J. Schorr
Subject: Re: [bug-gawk] Adding an API hook to enable a select extension
Date: Fri, 31 May 2013 14:15:42 -0400
User-agent: Mutt/1.5.21 (2010-09-15)

Hi Eli,

On Fri, May 31, 2013 at 08:51:04PM +0300, Eli Zaretskii wrote:
> It will, if getline would return a special code for "no data ready".
> Then you just try reading, and that's it.  No need for an explicit
> 'select' call.

I'm afraid I don't understand your point.  Suppose you have a program that is
reading from 2 TCP sockets.  It does not know when data may arrive on either
socket.  It wants to do something very simple: when data arrives from either
socket, just read it and print it.

If I understand your suggestion correctly, your version of the program might
look like this:

@load "time"

BEGIN {
   server["/inet4/tcp/0/127.0.0.1/12345"] = ""
   server["/inet4/tcp/0/127.0.0.1/23456"] = ""
   for (i in server)
      PROCINFO[i, "READ_TIMEOUT"] = 0
   while (length(server) > 0) {
      for (i in server) {
         if ((rc = (i |& getline x)) > 0)
            printf "Server %s says: %s\n", i, x
         else if (rc != TIMEOUT) {
            printf "Error reading from %s: %s\n", i, ERRNO
            close(i)
            delete server[i]
         }
      }
      sleep(1)
   }
}

If we omit the "sleep" function call, this will spin in a tight loop.  But with
the "sleep" call, there will be latency for receiving data.  And there are many
unnecessary system calls here, since we keep reading file descriptors
regardless of whether data is available.  We are burning CPU for no reason.

With select, it looks like this:

BEGIN {
   server["/inet4/tcp/0/127.0.0.1/12345"] = ""
   server["/inet4/tcp/0/127.0.0.1/23456"] = ""
   delete writefds
   delete exceptfds
   while (length(server) > 0) {
      delete readfds
      for (i in server)
         readfds[i] = ""
      # note: we omit the 4th argument to select to indicate that it
      # should block (i.e. there is no timeout)
      if (select(readfds, writefds, exceptfds) < 0)
         # probably caught an interrupt
         printf "Error: select failed: %s\n", ERRNO > "/dev/stderr"
      else {
         for (i in readfds) {
            if ((i |& getline x) > 0)
               printf "Server %s says: %s\n", i, x
            else {
               printf "Error reading from %s: %s\n", i, ERRNO
               close(i)
               delete server[i]
            }
         }
      }
   }
}

Those 2 programs are basically the same, except that the 2nd one is
much more efficient and does not suffer the latency problems of the
first one.

Both programs can be improved by setting the sockets to be non-blocking
to ensure that there is no risk of blocking.  To do this properly requires
some enhancement of getline to handle EAGAIN/EWOULDBLOCK properly.
This would help solve the original poster's problem.  If we make any change
to core gawk, I think it should be to solve that issue.  I think that
is a worthwhile change.

> You are confusing a feature and its implementation.  The feature is an
> ability to call readline and have it return some indication that
> there's nothing to read.  The implementation is to use 'select' (or
> whatever).

I really don't think that's what I want.  Please see the above and explain
to me why I'm confused.

Thanks,
Andy



reply via email to

[Prev in Thread] Current Thread [Next in Thread]