This is the mail archive of the cygwin@cygwin.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Bug in poll/select from console only [w/test case]


There appears to be a bug in the console reading machenery in the
2002-06-03 snapshot.  The problem is that if you're sitting at the
console and type a space bar, a process which is polling stdin will
start getting read-ready returns.  But if that process calls read() it
will block until the enter key is pressed.  The problem must be in
peek_console, which looks to be in more than one way the wrong tool for
the job:

	The bug I see is that it appears to assume that PeekConsoleInput
	implies that the file descriptor is ready to read.  But that is
	after the check that fails with my test case:  I do see the 'already
	ready' message from line 631.  The code behind that is convoluted
	enough that I'd have to look at the whold f*h*_console object before
	I felt comfortable messing with it.

	Just for what it's worth, however, when I have written similar code
	in the past, I have always had a single routine that sucked data
	into a buffer somewhere and parsed it enough to know if it was ready
	to return at least one line.   If there was a line already buffered,
	this routine would return immediately.  I called this routine in my
	get method and also in my peek method, so peek would read the
	underlying device.  It could be that grabbing a streambuffer object
	out of the iostreams library is just what the doctor ordered for
	this.

	Anyway, I'm sorry I don't have time to fix this, but my company is
	releasing a new version of it's product this week, and would be
	grumpy if their lead programmer was off playing in somebody elses
	source.  <G>  If it's still there next week I'll have a better look.

	Sadly, the following test case, due to the nature of the bug,
	requires a monkey to press the button, if you know a way to automate
	it, let me know.  Success is measured by seeing read() return
	immediately alter poll() does. Oh ... be sure to redirect either out
	or error to a file, or the double output will be really annoying.
--
  poll.1
--
Usage:
	g++ -opoll.exe poll.cxx 2>/dev/null
	./poll
	<space>

	and rejoice when you don't see the poll() return until you hit
	enter.

--
  poll.cxx
--

#include <sys/poll.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>

int start_time=time(0);
void write_str(const char*msg, int fd = 1) {
	//FIXME
	write(1, msg, strlen(msg));
	write(2, msg, strlen(msg));
}
void write_num(int val, int fd = 1) {
	char buffer[10];
	sprintf(buffer,"%d%c", val, 0);
	write_str(buffer,fd);
}
void nl(int fd = 1){
	write_str("\n");	
}
void write_err(const char *fn, int fd = 2) {
	write_str(fn, fd);
	write_str(":", fd);
	write_str(strerror(errno), fd);
}


void start(){
	char buffer[20];
	sprintf(buffer,"in:  %d\n%c", (time(0)-start_time) , 0);
	write_str(buffer);
	start_time = time(0);
};
void finish() {
	char buffer[20];
	sprintf(buffer,"out: %d\n%c", (time(0)-start_time) , 0);
	write_str(buffer);
	start_time = time(0);
}
int report(const char *fn, int res) {
	char buffer[20];
	sprintf(buffer,"%s: %d\n%c", fn,res , 0);
	write_str(buffer);
	if ( res < 0 ) {
		write_err(fn);
	}
	return res;
}
int main ( int, char** ) {
	pollfd sin;
	sin.events=POLLIN;
	sin.fd=0;
	for(;;){
		sin.revents=0;
		errno=0;
		nl();
		start();
		int res = report("poll", poll(&sin,1,1000));
		finish();
		int err = errno;
		if ( res < 0 )
			write_err("read");
		bool done = false;
		bool ready = false;
		switch(sin.revents){
			case POLLIN:
				write_str("POLLIN\n"); 
				ready=true;
			case 0: //fallthrough
				done = false ;
			break;
			case POLLOUT: write_str("POLLOUT\n"); break;
			case POLLERR: write_str("POLLERR\n"); break;
			case POLLHUP: write_str("POLLHUP\n"); break;
			case POLLNVAL: write_str("POLLNVAL\n"); break;
		}
		if ( done )
			break;
		if ( !ready )
			continue;
		char buf[1024];
		nl();
		start();
		res = report("read", read(0,buf, sizeof(buf)));
		finish();
		if ( res > 0 )
			continue;
		if ( res < 0 ) 
			write_err("read");
		exit(res<0);
		
	}
	write_str("done\n");
}



-- 
Got freedom?  Vote Libertarian:  http://www.lp.org

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Bug reporting:         http://cygwin.com/bugs.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]