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
strace.out
Description: Binary data
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/