[erlang-questions] Using select in a Port

jm jeffm@REDACTED
Sat Oct 20 09:00:13 CEST 2007


Changed the read_cmd and the main function based on your advise to make 
it store the current offset and to continue reading where it had left 
off. After starting the port and calling a benign function upto few 
times the read returns 0, ie the debug prints,

module:list().
read_cmd start curpos = 0
read_cmd curpos = 2
read_cmd len = 10 desired=10
read_cmd returned message
list
     note_read
              note_read return
call_port: {ok,[]}
{ok,[]}                      %%%% <-- correct result sent and recieved.
3> read_cmd start curpos = 0
read_cmd returned 0: Success(0)


it appears somthing is causing erlang to close stdin to the port, but 
I'm scratching my head as to why as no error is logged by the node. All 
message sent from my module to the erlang node are sent using the ei 
library and write_cmd as shown in the previous email.

Jeff.

/*
  * inputs
  *    buf     a pointer the buffer to place the message in
  *    size    size of buf
  *    curpos  current offset into buf. Should be set to 0 before
  *            initial call
  *
  * returns  < 0 on read() error
  *         == 0 on read() returning 0
  *            1 when there is more to read
  *            2 when the message is complete
  */
int read_cmd(char *buf, int *size, int *curpos)
{
   int len;
   int count;
   int desired;

   fprintf(stderr, "read_cmd start curpos = %d\r\n", *curpos);
   if (*curpos < 2) {
     /* read header */
     count = read(0, buf + *curpos, 2 - *curpos);

     if (count <= 0)
       return(count); /* Error or fd is closed */

     *curpos += count;
     if (*curpos < 2)
       return(1);
   }
   fprintf(stderr, "read_cmd curpos = %d\r\n", *curpos);
   /* calculate the total message length and
    * the desired amount to read taking into account
    * the ammount already read
    */
   len = (buf[0] << 8) | buf[1];
   desired = len - *curpos + 2;
   fprintf(stderr, "read_cmd len = %d desired=%d\r\n", len, desired);

   /* check buffer size and realloc if necessary */
   if (len > *size) {
     buf = (char *) realloc(buf, len);
     if (buf == NULL)
       return -1;
     *size = len;
   }

   /* read message body */
   count = read(0, buf + *curpos, desired);
   if (count <= 0)
     return(0);

   *curpos += count;
   return(2);
}

/****** main ******/

int main() {
....
  while ((retval = select(maxfd + 1, &readfds, NULL, NULL, NULL)) >= 0) {
     if FD_ISSET(0, &readfds) {
       memset(inbuf, 0, BUFFER_SIZE);
       index = 0;
       result = read_cmd(inbuf, &size, &cmdpos);
       if (result == 0) {
         fprintf(stderr, "read_cmd returned 0: %s(%d)\r\n", 
strerror(errno), errno);
         exit(1);
       } else if (result < 0) {
         fprintf(stderr, "read_cmd returned < 0: %s(%d)\r\n", 
strerror(errno), errno);
         exit(1);
       } else if (result == 1) {
         fprintf(stderr, "read_cmd need to read more");
       } else {
         fprintf(stderr, "read_cmd returned message\r\n");
         /* must add two(2) to inbuf pointer to skip message length 
header */
         if (ei_decode_version(inbuf+2, &index, &version) ||
             ei_decode_tuple_header(inbuf+2, &index, &arity) ||
             ei_decode_atom(inbuf+2, &index, command)) {
           fprintf(stderr, "ei_decode failure...\r\n");
           fprintf(stderr, "buf=(%p) %s\r\n", inbuf, inbuf);
           fprintf(stderr, "index=%d\r\n", index);
           exit(4);
         }
         process_command(command, inbuf+2, &index, nlist);
         /* reset position of inbuf */
         cmdpos = 0;
       }
     }
     fprintf(stderr, "note_read\n");
     /* check other file descriptors */
     note_read(nlist, &readfds);

     maxfd = setup_select(nlist, &readfds);
   }
....
}


Per Hedeland wrote:
> jm <jeffm@REDACTED> wrote:
>> What I think is the relevent bits of code is below. It appears that 
>> select() is returning saying that something is waiting to be read on 
>> stdin,
> 
> select() (or poll()) never says that - it says "If you try to read()
> from (e.g.) stdin, it won't block even if the file descriptor is in
> blocking mode".
> 
>> int read_cmd(byte *buf, int *size)
>> {
>>   int len;
>>
>>   if (read_exact(buf, 2) != 2) {
>>     fprintf(stderr, "read_cmd return(-1)\r\n");
>>     return(-1);
>>   }
> 
> This is plain broken - the return value must be checked properly:
> 
>    > 0 but less than you wanted: No error, just that all the data hasn't
>    arrived yet - save what you got and try again for the rest the next
>    time select/poll triggers.
> 
>    0: end-of-file - not an error (the other end of a socket or pipe was
>    closed, or someone hit ^D on a tty), but you don't want to read from
>    this descriptor ever again - select/poll will keep reporting the fd
>    as "ready".
> 
>    < 0: Error - depending on the context of your program you may need to
>    check for errno EINTR or EAGAIN, which could be non-fatal in which
>    case you just ignore the whole thing. Otherwise fatal, and the same
>    processing as for EOF typically applies. (This is pretty rare and
>    most likely a bug in your program, e.g. trying to read from a closed
>    descriptor).
> 
> Of course your problem could be something else too...
> 
> --Per Hedeland




More information about the erlang-questions mailing list