Bug 20983 - unable to break a blocking read for serial I/O
Summary: unable to break a blocking read for serial I/O
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Red Hat Linux
Classification: Retired
Component: kernel
Version: 6.2
Hardware: i386
OS: Linux
medium
medium
Target Milestone: ---
Assignee: Arjan van de Ven
QA Contact: David Lawrence
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2000-11-16 22:04 UTC by Need Real Name
Modified: 2007-04-18 16:29 UTC (History)
0 users

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2002-12-15 03:45:39 UTC
Embargoed:


Attachments (Terms of Use)

Description Need Real Name 2000-11-16 22:04:16 UTC
In Redhat LINUX v6.2, using the standard serial I/O code found in 
"ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/Serial-Programming-HOWTO" it 
is not possible to break out of a blocking read.

To break out of the read, I tried to close the port (from a another 
thread) The close succeeds but the read call still blocks. I have also 
tried IOCTL with various parameters but the read never breaks.

I have even tried using a select statement to capture the break, but it 
blocks just like the read.

This seems like a definite problem. To duplicate the problem :

1) create a thread to perform a blocking read loop (see HOWTO article for 
details)
2) try to break out of the read with a close command on the same file 
descriptor used by the read loop. This has to be done is a separate thread.

Note that killing the process seems like the only way to break the read 
call.

Please notify me if you can confirm this bug. I have spent a great amount 
of time trying to get around this.

Comment 1 Need Real Name 2000-11-29 18:57:02 UTC
Is anyone looking into this?

Comment 2 Jeff Johnson 2000-11-29 19:26:25 UTC
I will be, although I suspect the answer is going to be programming error and/or
standards
conforming behavior.

If you attach a short test case that exhibits the behavior  that will expedite
resolution.

Comment 3 Need Real Name 2000-11-29 19:52:53 UTC
/*********

The following are the routines I use to talk to the port. The initPort and
readPort calls are made from the same thread, the ClosePort call is made from 
a different thread.

The calling threads for this code is in from java (via JNI methods). I am not 
sure how to make a new thread call in LINUX so I let java do this for me. You 
will able to call this code without the JNI headers if you make your own 
calling threads.
 1) here's what happens:
   Thread1 : call InitPort and ReadPort() // this will block on the read call
   Thread2 : call ClosePort() // the close succeeds but Thread 1 is still 
blocked
  2) here's the problem (restated)
            If new data arives on the serial port, the read in Thread1 will 
return from the system call and return. This return should occur when the port 
is closed. Terminating the program also breaks the read. There doesn't seem to 
any other way to break the read.

Thanks,
Gene 

**********/


//#include "PortReader.h"
#include "SerialIO_PortReaderThread.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <signal.h>
#include <sys/ioctl.h>

#define BAUDRATE B9600
#define MODEMDEVICE "/dev/ttyS0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1

volatile int STOP=FALSE; 

  int fd = -1;
  struct termios oldtio;


void ClosePort()
{
	int retval;
	printf("ClosePort(%d)\n", fd);
	// this does not terminate the pending read....
	if (fd >= 0)
	{
		tcflush(fd, TCIFLUSH);
		tcsetattr(fd,TCSANOW,&oldtio);
		retval = close (fd);
		fd = -1;
	}
}



void InitPort (jint nPort, jint nBaud)
{
	struct termios newtio;
	char szDevice[80];
	if (fd >= 0 )
	{
		ClosePort();
	}


	if (nPort < 0)
		nPort = SerialIO_PortReaderThread_COM1;
	
	if (nBaud == 0)
		nBaud = B9600; //?? has to change to use what in the C header 
files 
					  // this is an enum type see "man 
tcsetattr"

	sprintf(szDevice, "/dev/ttyS%d", nPort);
	printf("device %s, baud %d\n",szDevice,nBaud); 
	fd = open(szDevice, O_RDWR | O_NOCTTY ); 

	if (fd <0) 
	{
		perror(szDevice); 
		exit(-1);  // ??TODO: change this 
	}

	tcgetattr(fd,&oldtio); /* save current port settings */

	bzero(&newtio, sizeof(newtio));
	newtio.c_cflag = B9600 | CRTSCTS | CS8 | CLOCAL | CREAD;
	newtio.c_iflag = IGNPAR;
	newtio.c_oflag = 0;

	/* set input mode (non-canonical, no echo,...) */
	newtio.c_lflag = 0;

	newtio.c_cc[VTIME]    = 1;   /* inter-character timer unused */
	newtio.c_cc[VMIN]     = 1;   /*5 == blocking read until 5 chars 
received */

	tcflush(fd, TCIFLUSH);
	tcsetattr(fd,TCSANOW,&newtio);

}



int ReadPort (char Buffer[], int nSize)
{

	// turn blocking on
	// size = read()
	// turn blocking off
	// while (size > 0) {
	//		add data to buffer
	//	    sleep(1/2 sec)
	//		size = read() // non blocking read
	//  }

	char *pTemp = Buffer; 
	int flags = 0;
	int retval;
	
	if (fd < 0)
		return -1; // no file open


	retval = fcntl(fd, F_SETFL, ~O_NONBLOCK); // turn  block read on

	nSize = read(fd,Buffer,nSize);
	retval = fcntl(fd, F_SETFL, O_NONBLOCK); // turn block read off

	while ((nSize > 0) && ((pTemp+nSize)-Buffer) > 0)
	{
		printf("\nnSize %d\n", nSize);
		pTemp = pTemp + nSize;	// point to next empty spavce in buffer
		usleep(500);			// wait for more data to come 
in.
		nSize = read(fd,pTemp,2000); // read next set of data into 
buffer
	}
	*(pTemp) = 0; // null terminate the buffer
	nSize = pTemp-Buffer;
	printf("\nBuffer Read (%d) :%s:\n", nSize, Buffer);
	
	return nSize;
}







Comment 4 Tim Waugh 2001-09-11 11:53:22 UTC
> I have even tried using a select statement to capture the break, but it 
> blocks just like the read.

But select has a timeout parameter.

This doesn't seem like a bug, but UNIX semantics.

In any case, it's nothing to do with setserial.  Reassigning to kernel.


Comment 5 Alan Cox 2002-12-15 03:45:39 UTC
close in one thread isnt defined to terminate a read in another - thats
undefined semantics land. In Linux it doesnt



Note You need to log in before you can comment on or make changes to this bug.