[erlang-questions] Using select in a Port

jm jeffm@REDACTED
Fri Oct 19 06:14:43 CEST 2007


In writing a simple port I've hit a problem with using select(). Select 
is used so that the program can read from both stdin and another file 
descriptor. The program runs fine while receiving commands on stdin. It 
continues to run fine when the second file descriptor opens. It only 
fails after something arrives on the second file descriptor is processed 
and the results sent to the erlang node in then loops printing the debug 
output, to stderr,

read_cmd return(-1)
buf empty. retval = 1
note_read
          note_read end while for fd = 3
note_read return
read_cmd return(-1)
buf empty. retval = 1
note_read
          note_read end while for fd = 3

and so on.


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, read_cmd() then fails to read the two byte header and returns -1. 
Simply put what's the fix? Have I missed something to do with select()? 
The read_cmd() and read_exact() are take from "Programming Erlang" and 
http://www.trapexit.org/How_to_use_ei_to_marshal_binary_terms_in_port_programs
and should be correct.

Any help appreciated.

Jeff.


/**************** code extract ***************/
int main() {
.....
  maxfd = setup_select(nlist, &readfds);

   while ((retval = select(maxfd + 1, &readfds, NULL, NULL, NULL)) >= 0) {
     if FD_ISSET(0, &readfds) {
       memset(buf, 0, BUFFER_SIZE);
       read_cmd(buf, &size);
       index = 0;

       if (*buf != '\0') {
         if (ei_decode_version(buf, &index, &version) ||
             ei_decode_tuple_header(buf, &index, &arity) ||
             ei_decode_atom(buf, &index, command)) {
           fprintf(stderr, "ei_decode failure...\r\n");
           fprintf(stderr, "buf=(%p) %s\r\n", buf, buf);
           fprintf(stderr, "index=%d\r\n", index);
           exit(4);
         }
         process_command(command, buf, &index, nlist);
       } else {
         fprintf(stderr, "buf empty. retval = %d\r\n", retval);
       }
     }
     fprintf(stderr, "note_read\n");
     /* check other file descriptors */
     note_read(nlist, &readfds);

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

/***************** setup_select *********************/
int setup_select(note_t *nlist, fd_set *readfds) {
   int topfd, maxfd = 0;

   /* pselect initialisation */
   FD_ZERO(readfds);
   FD_SET(0, readfds);

   topfd = note_setup_select(nlist, readfds);
   if (topfd > maxfd)
     maxfd = topfd;

   return maxfd;
}

/***************** read_cmd *************/
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);
   }
   len = (buf[0] << 8) | buf[1];

   fprintf(stderr, "read_cmd len = %d\r\n", len);
   if (len > *size) {
     buf = (byte *) realloc(buf, len);
     if (buf == NULL)
       return -1;
     *size = len;
   }
   return read_exact(buf, len);
}

/************* read_exact ***************/
int read_exact(byte *buf, int len) {
   int i, got = 0;

   do {
     if ((i = read(0, buf+got, len-got)) <= 0)
       return(i);
     got += i;
   } while (got<len);

   return(len);
}



More information about the erlang-questions mailing list