summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMagne Mahre <magne.mahre@sun.com>2010-02-14 19:12:58 +0100
committerMagne Mahre <magne.mahre@sun.com>2010-02-14 19:12:58 +0100
commit2d4687d03b1a25b68de197837b6e51524d3a5b8a (patch)
tree9d5bb9f598d68ef5e7477a4d5672b2ed3210fac2
parent87c6bf3fc8edc185569702915c10b4241dba7293 (diff)
downloadmariadb-git-2d4687d03b1a25b68de197837b6e51524d3a5b8a.tar.gz
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.
-rw-r--r--configure.in2
-rw-r--r--sql/mysqld.cc64
2 files changed, 55 insertions, 11 deletions
diff --git a/configure.in b/configure.in
index 9361052e2d9..9776fc12fe6 100644
--- a/configure.in
+++ b/configure.in
@@ -839,7 +839,7 @@ AC_HEADER_DIRENT
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
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 \
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 \
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 983f1750a38..5a88ad1970a 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -52,6 +52,10 @@
#include "sp_rcontext.h"
#include "sp_cache.h"
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+
#define mysqld_charset &my_charset_latin1
/* stack traces are only supported on linux intel */
@@ -5343,26 +5347,47 @@ void handle_connections_sockets()
{
my_socket sock,new_sock;
uint error_count=0;
- uint max_used_connection= (uint) (max(ip_sock,unix_sock)+1);
- fd_set readFDs,clientFDs;
THD *thd;
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;
+#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");
LINT_INIT(new_sock);
+#ifndef HAVE_POLL
FD_ZERO(&clientFDs);
+#endif
+
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);
+#endif
#ifdef HAVE_FCNTL
ip_flags = fcntl(ip_sock, F_GETFL, 0);
#endif
}
#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);
+#endif
#ifdef HAVE_FCNTL
socket_flags=fcntl(unix_sock, F_GETFL, 0);
#endif
@@ -5372,12 +5397,15 @@ void handle_connections_sockets()
MAYBE_BROKEN_SYSCALL;
while (!abort_loop)
{
- readFDs=clientFDs;
-#ifdef HPUX10
- if (select(max_used_connection,(int*) &readFDs,0,0,0) < 0)
- continue;
+#ifdef HAVE_POLL
+ retval= poll(fds, socket_count, -1);
#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)
{
@@ -5387,7 +5415,7 @@ void handle_connections_sockets()
MAYBE_BROKEN_SYSCALL
continue;
}
-#endif /* HPUX10 */
+
if (abort_loop)
{
MAYBE_BROKEN_SYSCALL;
@@ -5395,6 +5423,21 @@ void handle_connections_sockets()
}
/* 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
if (FD_ISSET(unix_sock,&readFDs))
{
@@ -5402,11 +5445,12 @@ void handle_connections_sockets()
flags= socket_flags;
}
else
-#endif
+#endif // HAVE_SYS_UN_H
{
sock = ip_sock;
flags= ip_flags;
}
+#endif // HAVE_POLL
#if !defined(NO_FCNTL_NONBLOCK)
if (!(test_flags & TEST_BLOCKING))