Ever had one of those weeks where *every* feature you try and use seems
not to want to work for you?  sigh :-{

  Well, unless I've done something really dumb, this simple testcase ought
to wait 1/4 of a second to receive a char from com1 and then exit.

  But it doesn't.  It locks up in some very serious way that prevents the
process from being killed with ctrl-c and in fact even prevents a debugger
from attaching to it.  However it's still possible to kill the process with
the task manager.

  When I try and debug it with vs.net, I get an error that says 'The process
appears to be deadlocked (or is not running any user-mode code).'  OTOH gdb
seems to manage to get attached to it ok.  Strange.  

  Also, running it under strace makes it responsive to ctrl-c again (but
doesn't otherwise change the behaviour).  It also shows that the select does
in fact timeout, but never seems to make it through the cleanup routines and
back to the main function.

  This problem may be related to either
http://sources.redhat.com/ml/cygwin/2003-06/msg00477.html
http://sources.redhat.com/ml/cygwin/2003-06/msg00493.html
which describe select failing to notice serial input, and/or
http://sources.redhat.com/ml/cygwin/2003-03/msg02097.html
which describes select returning spurious 'read ready' indications.  I
couldn't find any indication that either of these problems have been
addressed since they were discussed on the list.

  Anyway, I'm about to get down and build a debug version of the .dll and
see where I can get with this problem, and I'll report any progress I make.
I just need to figure out why every single testcase in 'make check' fails
with "child process exited abnormally".  It seems not to be finding the
newly-built .dll and so failing to execute any of them.

  If anyone feels like taking a look over the attached testcase just to
confirm that this is a real bug and not some silly mistake I've made in
opening and setting up the com port, and that the problem is reproducible
for them, that would be most helpful.

  Also if anyone has any useful information about what goes on during the
post-select cleanup stage, that might give me a clue or two as well.


  cheers,
     DaveK

Attachment: strace.out
Description: Binary data

Attachment: makefile
Description: Binary data



#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <termios.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/select.h>


/**  Reads the serial port, implementing a timeout.
 *
 * @param serialfd Fd returned earlier from serial_init (...)
 * @param buffer The destination address for received bytes.
 * @param buflen The maximum amount of space available in the buffer.
 * @param timeout_ms Timeout in milliseconds; zero to poll, -ve for infinite.
 *
 * @return -1 if error, 0 if timeout before any data rx'd, else num
 * bytes placed into buffer (up to max of buflen).
 *
 * @todo Perhaps implement win32 style serial handling
 */

int serial_read_with_timeout (int serialfd, void *buffer, int buflen, int timeout_ms)
{
struct timeval tmo, *tmoptr;
int rv;
fd_set readfds;

//fd_set dummy1, dummy2;
    //FD_ZERO (&dummy1); FD_ZERO (&dummy2);

    FD_ZERO (&readfds);
    FD_SET (serialfd, &readfds);
    tmo.tv_sec = timeout_ms / 1000;
    tmo.tv_usec = (timeout_ms - (1000 * tmo.tv_sec)) * 1000;
    tmoptr = (timeout_ms < 0) ? NULL : &tmo;
    printf ("b4sel %d, %p, 0, 0, %p { %ld, %ld }\n", 1+serialfd, &readfds, tmoptr, 
tmo.tv_sec, tmo.tv_usec);
    rv = select (1 + serialfd, &readfds, NULL, NULL, tmoptr);
    //rv = select (1 + serialfd, &readfds, &dummy1, &dummy2, tmoptr);
    printf ("afsel\n");
    // So what happened? rv is 0 => no fd set, -1 = error, else there must be readable 
data
    if (rv <= 0)
        return rv;
    // huzzah! there is some data to actually read....
    // we could always do int bytes; ioctl(fd, FIONREAD, &bytes);
    // at this point, but nonblocking means we should be ok anyway.......
    rv = read (serialfd, buffer, buflen);
    return rv;
}



int main (int argc, const char **argv)
{
int rv, fd;
char buff[8];
struct termios tio;


    fd = open ("/dev/com1", O_RDWR | O_BINARY | /* O_NONBLOCK | */ O_NOCTTY | O_NDELAY 
);
    if (fd < 0)
    {
        fprintf (stderr, "oops error opening com1 %d\n", errno);
        return -1;
    }
    // Dunno for sure if this just duplicates setting O_NONBLOCK
    fcntl(fd, F_SETFL, FNDELAY);
    // Set the serial port to the baud rate chosen and 8n1.
    rv = tcgetattr (fd, &tio);
    if (rv)
    {
        fprintf (stderr, "Can't get options - error %d\n", errno);
        close (fd);
        return -1;
    }
    // Not implemented.... cfmakeraw (&tio); ... equivalent is....
    tio.c_iflag &= 
~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXOFF|IXANY|INPCK|IUCLC);
    tio.c_oflag &= ~OPOST;
    tio.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN|ECHOE);
    tio.c_cflag &= ~(CSIZE|PARENB);
    tio.c_cflag |= CS8 | CLOCAL | CREAD;
    // Now modify the defaults with chosen settings.
    rv = cfsetospeed (&tio, B57600);
    if (!rv)
        rv = cfsetispeed (&tio, B57600);
    if  (rv)
        fprintf (stderr, "ERROR: Baud rate not recognized\n");
    tio.c_cflag = (tio.c_cflag & ~CSIZE) | CS8;
    tio.c_cflag = (tio.c_cflag & ~PARENB);
    tio.c_cflag = (tio.c_cflag & ~CSTOPB);
    // and implement those settings.
    rv = tcsetattr (fd, TCSANOW, &tio);
    if (rv)
    {
        fprintf (stderr, "Error %d setting options\n", errno);
        close (fd);
        return -1;
    }

    // so try reading it
    rv = serial_read_with_timeout (fd, buff, 1, 250);
    fprintf (stderr, "serial read: rv %d char $%02x\n", rv, (unsigned int)buff[0]);

    // we done now.
    rv = close (fd);
    fprintf (stderr, "close gives %d\n", fd);
    return 0;
}







--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/

Reply via email to