Commit 2d4687d0 authored by Magne Mahre's avatar Magne Mahre

Bug#48929 Error in Accept() if using many file descriptors

In POSIX systems, the file descriptor set used in the select(2)
system call is represented by a bit vector of size FD_SETSIZE.
When select(2) is used on file/socket descriptors with a value
that is beyond this size, unpredictable errors may occur.

In this case, the error happens when there are a large number
of tables that need repair.  These tables are opened before
the sockets for incoming connections are acquired, resulting
in these sockets getting descriptor id which is higher than
FD_SETSIZE.

Replacing the call to select(2) with poll(2) fixes the problem,
as poll takes an array of the wanted descriptors, instead of
a bit vector.  

MS Windows has a different implementation of 'select', and is not
affected by this bug.  


configure.in:
  Added a test for the <poll.h> file
sql/mysqld.cc:
  Restructured some of the code to reduce the number of
  #ifdef's.  Removed some HP/UX 10-specific code.
parent 87c6bf3f
...@@ -839,7 +839,7 @@ AC_HEADER_DIRENT ...@@ -839,7 +839,7 @@ AC_HEADER_DIRENT
AC_HEADER_STDC AC_HEADER_STDC
AC_HEADER_SYS_WAIT AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS(fcntl.h fenv.h float.h floatingpoint.h ieeefp.h limits.h \ AC_CHECK_HEADERS(fcntl.h fenv.h float.h floatingpoint.h ieeefp.h limits.h \
memory.h pwd.h select.h \ memory.h pwd.h select.h poll.h \
stdlib.h stddef.h \ stdlib.h stddef.h \
strings.h string.h synch.h sys/mman.h sys/socket.h netinet/in.h arpa/inet.h \ strings.h string.h synch.h sys/mman.h sys/socket.h netinet/in.h arpa/inet.h \
sys/timeb.h sys/types.h sys/un.h sys/vadvise.h sys/wait.h term.h \ sys/timeb.h sys/types.h sys/un.h sys/vadvise.h sys/wait.h term.h \
......
...@@ -52,6 +52,10 @@ ...@@ -52,6 +52,10 @@
#include "sp_rcontext.h" #include "sp_rcontext.h"
#include "sp_cache.h" #include "sp_cache.h"
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#define mysqld_charset &my_charset_latin1 #define mysqld_charset &my_charset_latin1
/* stack traces are only supported on linux intel */ /* stack traces are only supported on linux intel */
...@@ -5343,26 +5347,47 @@ void handle_connections_sockets() ...@@ -5343,26 +5347,47 @@ void handle_connections_sockets()
{ {
my_socket sock,new_sock; my_socket sock,new_sock;
uint error_count=0; uint error_count=0;
uint max_used_connection= (uint) (max(ip_sock,unix_sock)+1);
fd_set readFDs,clientFDs;
THD *thd; THD *thd;
struct sockaddr_storage cAddr; struct sockaddr_storage cAddr;
int ip_flags=0,socket_flags=0,flags; int ip_flags=0,socket_flags=0,flags,retval;
st_vio *vio_tmp; st_vio *vio_tmp;
#ifdef HAVE_POLL
int socket_count= 0;
struct pollfd fds[2]; // for ip_sock and unix_sock
#else
fd_set readFDs,clientFDs;
uint max_used_connection= (uint) (max(ip_sock,unix_sock)+1);
#endif
DBUG_ENTER("handle_connections_sockets"); DBUG_ENTER("handle_connections_sockets");
LINT_INIT(new_sock); LINT_INIT(new_sock);
#ifndef HAVE_POLL
FD_ZERO(&clientFDs); FD_ZERO(&clientFDs);
#endif
if (ip_sock != INVALID_SOCKET) if (ip_sock != INVALID_SOCKET)
{ {
#ifdef HAVE_POLL
fds[socket_count].fd= ip_sock;
fds[socket_count].events= POLLIN;
socket_count++;
#else
FD_SET(ip_sock,&clientFDs); FD_SET(ip_sock,&clientFDs);
#endif
#ifdef HAVE_FCNTL #ifdef HAVE_FCNTL
ip_flags = fcntl(ip_sock, F_GETFL, 0); ip_flags = fcntl(ip_sock, F_GETFL, 0);
#endif #endif
} }
#ifdef HAVE_SYS_UN_H #ifdef HAVE_SYS_UN_H
#ifdef HAVE_POLL
fds[socket_count].fd= unix_sock;
fds[socket_count].events= POLLIN;
socket_count++;
#else
FD_SET(unix_sock,&clientFDs); FD_SET(unix_sock,&clientFDs);
#endif
#ifdef HAVE_FCNTL #ifdef HAVE_FCNTL
socket_flags=fcntl(unix_sock, F_GETFL, 0); socket_flags=fcntl(unix_sock, F_GETFL, 0);
#endif #endif
...@@ -5372,12 +5397,15 @@ void handle_connections_sockets() ...@@ -5372,12 +5397,15 @@ void handle_connections_sockets()
MAYBE_BROKEN_SYSCALL; MAYBE_BROKEN_SYSCALL;
while (!abort_loop) while (!abort_loop)
{ {
readFDs=clientFDs; #ifdef HAVE_POLL
#ifdef HPUX10 retval= poll(fds, socket_count, -1);
if (select(max_used_connection,(int*) &readFDs,0,0,0) < 0)
continue;
#else #else
if (select((int) max_used_connection,&readFDs,0,0,0) < 0) readFDs=clientFDs;
retval= select((int) max_used_connection,&readFDs,0,0,0);
#endif
if (retval < 0)
{ {
if (socket_errno != SOCKET_EINTR) if (socket_errno != SOCKET_EINTR)
{ {
...@@ -5387,7 +5415,7 @@ void handle_connections_sockets() ...@@ -5387,7 +5415,7 @@ void handle_connections_sockets()
MAYBE_BROKEN_SYSCALL MAYBE_BROKEN_SYSCALL
continue; continue;
} }
#endif /* HPUX10 */
if (abort_loop) if (abort_loop)
{ {
MAYBE_BROKEN_SYSCALL; MAYBE_BROKEN_SYSCALL;
...@@ -5395,6 +5423,21 @@ void handle_connections_sockets() ...@@ -5395,6 +5423,21 @@ void handle_connections_sockets()
} }
/* Is this a new connection request ? */ /* Is this a new connection request ? */
#ifdef HAVE_POLL
for (int i= 0; i < socket_count; ++i)
{
if (fds[i].revents & POLLIN)
{
sock= fds[i].fd;
#ifdef HAVE_FCNTL
flags= fcntl(sock, F_GETFL, 0);
#else
flags= 0;
#endif // HAVE_FCNTL
break;
}
}
#else // HAVE_POLL
#ifdef HAVE_SYS_UN_H #ifdef HAVE_SYS_UN_H
if (FD_ISSET(unix_sock,&readFDs)) if (FD_ISSET(unix_sock,&readFDs))
{ {
...@@ -5402,11 +5445,12 @@ void handle_connections_sockets() ...@@ -5402,11 +5445,12 @@ void handle_connections_sockets()
flags= socket_flags; flags= socket_flags;
} }
else else
#endif #endif // HAVE_SYS_UN_H
{ {
sock = ip_sock; sock = ip_sock;
flags= ip_flags; flags= ip_flags;
} }
#endif // HAVE_POLL
#if !defined(NO_FCNTL_NONBLOCK) #if !defined(NO_FCNTL_NONBLOCK)
if (!(test_flags & TEST_BLOCKING)) if (!(test_flags & TEST_BLOCKING))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment