Mailing-List: contact cygwin-help AT sourceware DOT cygnus DOT com; run by ezmlm List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT sources DOT redhat DOT com Delivered-To: mailing list cygwin AT sources DOT redhat DOT com Message-ID: <410A7080D2D2D11185F800A0C9663B823E8948@pulse-bdc.pulse.com> From: Ted Soo-Hoo To: "'cygwin AT sourceware DOT cygnus DOT com'" Subject: 1.1.4 select and poll false positive past 32 descriptors Date: Tue, 8 Aug 2000 17:21:49 -0400 MIME-Version: 1.0 X-Mailer: Internet Mail Service (5.5.2650.21) Content-Type: text/plain; charset="iso-8859-1" Hello, When invoked in a way that may pend they fail to update any result data past descriptors 0-31. This typically means you get false positive bits. NT 4.0 + cygwin1.dll 1.1.4 as built 2000-08-03. It looks from the sources like the intent was to support a large variable number of descriptors, not (as may have been once) a fixed maximum. If that's not so, the rest of this might not apply. Sample output of test program with 40 sockets plus three for the stdin, stdout, and stderr fds: Press Enter to run the test recv_fd_max = 42 read_fds before select that pends: f9 ff ff ff ff 07 00 00 read_fds after select that pends: 01 00 00 00 ff 07 00 00 read_fds before select that polls: f9 ff ff ff ff 07 00 00 read_fds after select that polls: 01 00 00 00 00 00 00 00 The pending select set the first read_fds word but didn't clear the second 32-bit word. If I use a no-time-timeout I get expected read_fds bits. Nothing is talking to the sockets so they're 0s. To return descriptors as ready for reading that are not really ready will hang programs that do reads based on select saying it's OK to do so. A workaround for the problem is to use both of these selects, one to pend and one to get bits. I've tested up to around 200 this way, using a larger FD_SETSIZE when compiling of course. The idea for polling comes from select.cc code which goes down a different path for that case. I also ran under strace and saw that a pended operation bases its returned size on a value n which is always small, e.g. 1 or 2 and not the expected value to copy out. That value should be based on the maximum file descriptor given by the user, but not work too hard beyond that. A possible fix would be to change the loop that does the counting to count n less conditionally. Just a thought. I don't understand all the code. By the way, an attempt to wait on a large poll array suffers a similar fate -- a scan for active elements finds the one with file descriptor 32 active when it shouldn't be. Probably a leftover POLLIN came back on all the high descriptors. Test program for select: #include #include #include #include #include #include #include #define SOCKET_MAX 40 main() { int count; int recv_fd, recv_fd_max; int status; struct sockaddr_in addr; struct protoent *proto_ptr; fd_set recv_fds; fd_set zero_fds; fd_set read_fds, write_fds, except_fds; struct timeval tv; recv_fd_max = 0; FD_ZERO(&recv_fds); FD_ZERO(&zero_fds); addr.sin_family = PF_INET; proto_ptr = getprotobyname("udp"); if (proto_ptr == 0) { printf("Could not find protocol number for udp\n"); exit(1); } addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_port = htons(0); for (count = 0; count < SOCKET_MAX; count++) { recv_fd = socket(AF_INET, SOCK_DGRAM, proto_ptr->p_proto); status = bind(recv_fd, (struct sockaddr *) &addr, sizeof(struct sockaddr)); if (status == -1) { perror("Could not bind"); exit(1); } FD_SET(recv_fd, &recv_fds); if (recv_fd > recv_fd_max) { recv_fd_max = recv_fd; } } FD_SET(0, &recv_fds); printf("Press Enter to run the test\n"); memcpy(&read_fds, &recv_fds, sizeof(fd_set)); memcpy(&write_fds, &zero_fds, sizeof(fd_set)); memcpy(&except_fds, &zero_fds, sizeof(fd_set)); printf("recv_fd_max = %d\n", recv_fd_max); print_fds("read_fds before select that pends:\n", &read_fds); status = select(recv_fd_max + 1, &read_fds, &write_fds, &except_fds, NULL); if (status == -1) { printf("Select failed\n"); exit(1); } print_fds("read_fds after select that pends:\n", &read_fds); memcpy(&read_fds, &recv_fds, sizeof(fd_set)); memcpy(&write_fds, &zero_fds, sizeof(fd_set)); memcpy(&except_fds, &zero_fds, sizeof(fd_set)); print_fds("read_fds before select that polls:\n", &read_fds); tv.tv_sec = 0; tv.tv_usec = 0; status = select(recv_fd_max + 1, &read_fds, &write_fds, &except_fds, &tv); if (status == -1) { printf("Select failed\n"); exit(1); } print_fds("read_fds after select that polls:\n", &read_fds); } print_fds(label, fds) char *label; fd_set *fds; { int count; printf("%s", label); for (count = 0; count < sizeof(fd_set); count++) { printf("%02x ", * ((unsigned char *) fds + count)); } printf("\n"); } Thank you! Regards, Ted -- Want to unsubscribe from this list? Send a message to cygwin-unsubscribe AT sourceware DOT cygnus DOT com