Commit 1040d2ce authored by Just van Rossum's avatar Just van Rossum

[ 731644] & [ 604210 ] Release the GIL around getaddrinfo(), yet protect

access with lock on those platforms that getaddrinfo() isn't (known to be)
thread-safe. Thanks to MvL for mentoring this patch.
parent a00050f2
...@@ -140,7 +140,22 @@ shutdown(how) -- shut down traffic in one or both directions\n\ ...@@ -140,7 +140,22 @@ shutdown(how) -- shut down traffic in one or both directions\n\
# define USE_GETHOSTBYNAME_LOCK # define USE_GETHOSTBYNAME_LOCK
#endif #endif
#ifdef USE_GETHOSTBYNAME_LOCK /* On systems on which getaddrinfo() is believed to not be thread-safe,
protect access with a lock. */
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
defined(__NetBSD__)
#define USE_GETADDRINFO_LOCK
#endif
#ifdef USE_GETADDRINFO_LOCK
#define ACQUIRE_GETADDRINFO_LOCK PyThread_acquire_lock(netdb_lock, 1);
#define RELEASE_GETADDRINFO_LOCK PyThread_release_lock(netdb_lock);
#else
#define ACQUIRE_GETADDRINFO_LOCK
#define RELEASE_GETADDRINFO_LOCK
#endif
#if defined(USE_GETHOSTBYNAME_LOCK) || defined(USE_GETADDRINFO_LOCK)
# include "pythread.h" # include "pythread.h"
#endif #endif
...@@ -619,9 +634,9 @@ new_sockobject(SOCKET_T fd, int family, int type, int proto) ...@@ -619,9 +634,9 @@ new_sockobject(SOCKET_T fd, int family, int type, int proto)
/* Lock to allow python interpreter to continue, but only allow one /* Lock to allow python interpreter to continue, but only allow one
thread to be in gethostbyname */ thread to be in gethostbyname or getaddrinfo */
#ifdef USE_GETHOSTBYNAME_LOCK #if defined(USE_GETHOSTBYNAME_LOCK) || defined(USE_GETADDRINFO_LOCK)
PyThread_type_lock gethostbyname_lock; PyThread_type_lock netdb_lock;
#endif #endif
...@@ -646,7 +661,15 @@ setipaddr(char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int af) ...@@ -646,7 +661,15 @@ setipaddr(char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int af)
hints.ai_family = af; hints.ai_family = af;
hints.ai_socktype = SOCK_DGRAM; /*dummy*/ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
hints.ai_flags = AI_PASSIVE; hints.ai_flags = AI_PASSIVE;
Py_BEGIN_ALLOW_THREADS
ACQUIRE_GETADDRINFO_LOCK
error = getaddrinfo(NULL, "0", &hints, &res); error = getaddrinfo(NULL, "0", &hints, &res);
Py_END_ALLOW_THREADS
/* We assume that those thread-unsafe getaddrinfo() versions
*are* safe regarding their return value, ie. that a
subsequent call to getaddrinfo() does not destroy the
outcome of the first call. */
RELEASE_GETADDRINFO_LOCK
if (error) { if (error) {
set_gaierror(error); set_gaierror(error);
return -1; return -1;
...@@ -710,6 +733,8 @@ setipaddr(char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int af) ...@@ -710,6 +733,8 @@ setipaddr(char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int af)
} }
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_family = af; hints.ai_family = af;
Py_BEGIN_ALLOW_THREADS
ACQUIRE_GETADDRINFO_LOCK
error = getaddrinfo(name, NULL, &hints, &res); error = getaddrinfo(name, NULL, &hints, &res);
#if defined(__digital__) && defined(__unix__) #if defined(__digital__) && defined(__unix__)
if (error == EAI_NONAME && af == AF_UNSPEC) { if (error == EAI_NONAME && af == AF_UNSPEC) {
...@@ -719,6 +744,8 @@ setipaddr(char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int af) ...@@ -719,6 +744,8 @@ setipaddr(char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int af)
error = getaddrinfo(name, NULL, &hints, &res); error = getaddrinfo(name, NULL, &hints, &res);
} }
#endif #endif
Py_END_ALLOW_THREADS
RELEASE_GETADDRINFO_LOCK /* see comment in setipaddr() */
if (error) { if (error) {
set_gaierror(error); set_gaierror(error);
return -1; return -1;
...@@ -2410,7 +2437,7 @@ socket_gethostbyname_ex(PyObject *self, PyObject *args) ...@@ -2410,7 +2437,7 @@ socket_gethostbyname_ex(PyObject *self, PyObject *args)
#endif #endif
#else /* not HAVE_GETHOSTBYNAME_R */ #else /* not HAVE_GETHOSTBYNAME_R */
#ifdef USE_GETHOSTBYNAME_LOCK #ifdef USE_GETHOSTBYNAME_LOCK
PyThread_acquire_lock(gethostbyname_lock, 1); PyThread_acquire_lock(netdb_lock, 1);
#endif #endif
h = gethostbyname(name); h = gethostbyname(name);
#endif /* HAVE_GETHOSTBYNAME_R */ #endif /* HAVE_GETHOSTBYNAME_R */
...@@ -2423,7 +2450,7 @@ socket_gethostbyname_ex(PyObject *self, PyObject *args) ...@@ -2423,7 +2450,7 @@ socket_gethostbyname_ex(PyObject *self, PyObject *args)
ret = gethost_common(h, (struct sockaddr *)&addr, sizeof(addr), ret = gethost_common(h, (struct sockaddr *)&addr, sizeof(addr),
sa->sa_family); sa->sa_family);
#ifdef USE_GETHOSTBYNAME_LOCK #ifdef USE_GETHOSTBYNAME_LOCK
PyThread_release_lock(gethostbyname_lock); PyThread_release_lock(netdb_lock);
#endif #endif
return ret; return ret;
} }
...@@ -2506,14 +2533,14 @@ socket_gethostbyaddr(PyObject *self, PyObject *args) ...@@ -2506,14 +2533,14 @@ socket_gethostbyaddr(PyObject *self, PyObject *args)
#endif #endif
#else /* not HAVE_GETHOSTBYNAME_R */ #else /* not HAVE_GETHOSTBYNAME_R */
#ifdef USE_GETHOSTBYNAME_LOCK #ifdef USE_GETHOSTBYNAME_LOCK
PyThread_acquire_lock(gethostbyname_lock, 1); PyThread_acquire_lock(netdb_lock, 1);
#endif #endif
h = gethostbyaddr(ap, al, af); h = gethostbyaddr(ap, al, af);
#endif /* HAVE_GETHOSTBYNAME_R */ #endif /* HAVE_GETHOSTBYNAME_R */
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
ret = gethost_common(h, (struct sockaddr *)&addr, sizeof(addr), af); ret = gethost_common(h, (struct sockaddr *)&addr, sizeof(addr), af);
#ifdef USE_GETHOSTBYNAME_LOCK #ifdef USE_GETHOSTBYNAME_LOCK
PyThread_release_lock(gethostbyname_lock); PyThread_release_lock(netdb_lock);
#endif #endif
return ret; return ret;
} }
...@@ -2966,7 +2993,11 @@ socket_getaddrinfo(PyObject *self, PyObject *args) ...@@ -2966,7 +2993,11 @@ socket_getaddrinfo(PyObject *self, PyObject *args)
hints.ai_socktype = socktype; hints.ai_socktype = socktype;
hints.ai_protocol = protocol; hints.ai_protocol = protocol;
hints.ai_flags = flags; hints.ai_flags = flags;
Py_BEGIN_ALLOW_THREADS
ACQUIRE_GETADDRINFO_LOCK
error = getaddrinfo(hptr, pptr, &hints, &res0); error = getaddrinfo(hptr, pptr, &hints, &res0);
Py_END_ALLOW_THREADS
RELEASE_GETADDRINFO_LOCK /* see comment in setipaddr() */
if (error) { if (error) {
set_gaierror(error); set_gaierror(error);
return NULL; return NULL;
...@@ -3035,7 +3066,11 @@ socket_getnameinfo(PyObject *self, PyObject *args) ...@@ -3035,7 +3066,11 @@ socket_getnameinfo(PyObject *self, PyObject *args)
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM; /* make numeric port happy */ hints.ai_socktype = SOCK_DGRAM; /* make numeric port happy */
Py_BEGIN_ALLOW_THREADS
ACQUIRE_GETADDRINFO_LOCK
error = getaddrinfo(hostp, pbuf, &hints, &res); error = getaddrinfo(hostp, pbuf, &hints, &res);
Py_END_ALLOW_THREADS
RELEASE_GETADDRINFO_LOCK /* see comment in setipaddr() */
if (error) { if (error) {
set_gaierror(error); set_gaierror(error);
goto fail; goto fail;
...@@ -3940,8 +3975,8 @@ init_socket(void) ...@@ -3940,8 +3975,8 @@ init_socket(void)
#endif #endif
/* Initialize gethostbyname lock */ /* Initialize gethostbyname lock */
#ifdef USE_GETHOSTBYNAME_LOCK #if defined(USE_GETHOSTBYNAME_LOCK) || defined(USE_GETADDRINFO_LOCK)
gethostbyname_lock = PyThread_allocate_lock(); netdb_lock = PyThread_allocate_lock();
#endif #endif
} }
......
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