多线程中使用curl致coredump问题
coredump时的调用栈:
#0 0x081eff2c in addbyter ()
#1 0x081f05b8 in dprintf_formatf ()
#2 0x081f15cf in curl_mvsnprintf ()
#3 0x081f0079 in curl_msnprintf ()
#4 0x081ef55c in Curl_failf ()
#5 0x081fa1a3 in Curl_resolv_timeout ()
#6 0xeb8fbdd4 in ?? ()
#7 0x00000000 in ?? ()
coredump的原因是因为curl的DNS解析超时控制是使用SIGALARM实现的。
这样导致发现SIGALARM会出现多线程修改同一个全局变量,由此产生了COREDUMP。
问题发生的前提是设置了CURLOPT_TIMEOUT或CURLOPT_CONNECTTIMEOUT,并且值不为0。
解决办法:
1) 设置CURLOPT_NOSIGNAL的值为1
2) 使用c-ares(configure时指定参数--enable-ares)
lib/curl_setup.h(异步模式使用c-ares控制DNS解析超时):
只有当configure时指定了--enable-ares才会定义USE_ARES。
#ifdef USE_ARES
# define CURLRES_ASYNCH
# define CURLRES_ARES
/* now undef the stock libc functions just to avoid them being used */
# undef HAVE_GETADDRINFO
# undef HAVE_GETHOSTBYNAME
#elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
# define CURLRES_ASYNCH
# define CURLRES_THREADED
#else
# define CURLRES_SYNCH
#endif
lib/hostip.c(同步模式使用ALARM控制DNS解析超时):
只有定义了CURLRES_SYNCH,才可能定义USE_ALARM_TIMEOUT。
#if defined(CURLRES_SYNCH) && \
defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP)
/* alarm-based timeouts can only be used with all the dependencies satisfied */
#define USE_ALARM_TIMEOUT
#endif
相关源代码:
lib/asyn-ares.c:
Curl_resolver_getaddrinfo
lib/hostasyn.c(基于c-ares的异步版本Curl_getaddrinfo):
Curl_resolver_getaddrinfo <-- Curl_getaddrinfo
从缓存中找(hostip.c):
fetch_addr <-- Curl_resolv
hostip.c:
Curl_ipv4_resolve_r <-- Curl_getaddrinfo <-- Curl_resolv
hostip.c:
curl_jmpenv <-- sigaction(SIGALRM, alarmfunc)/sigsetjmp(curl_jmpenv) <- Curl_resolv_timeout <-
url.c:
Curl_resolv_timeout(hostname) <-- resolve_server <-- create_conn <-- Curl_connect
multi.c:
Curl_connect <--
transfer.c
Curl_connect <-- Curl_reconnect_request
url.c:
Curl_reconnect_request <-- Curl_do
multi.c:
Curl_do <-- multi_runsingle <-- curl_multi_perform <-- multi_socket <-- curl_multi_socket
#0 0x081eff2c in addbyter ()
#1 0x081f05b8 in dprintf_formatf ()
#2 0x081f15cf in curl_mvsnprintf ()
#3 0x081f0079 in curl_msnprintf ()
#4 0x081ef55c in Curl_failf ()
#5 0x081fa1a3 in Curl_resolv_timeout ()
#6 0xeb8fbdd4 in ?? ()
#7 0x00000000 in ?? ()
coredump的原因是因为curl的DNS解析超时控制是使用SIGALARM实现的。
这样导致发现SIGALARM会出现多线程修改同一个全局变量,由此产生了COREDUMP。
问题发生的前提是设置了CURLOPT_TIMEOUT或CURLOPT_CONNECTTIMEOUT,并且值不为0。
解决办法:
1) 设置CURLOPT_NOSIGNAL的值为1
2) 使用c-ares(configure时指定参数--enable-ares)
lib/curl_setup.h(异步模式使用c-ares控制DNS解析超时):
只有当configure时指定了--enable-ares才会定义USE_ARES。
#ifdef USE_ARES
# define CURLRES_ASYNCH
# define CURLRES_ARES
/* now undef the stock libc functions just to avoid them being used */
# undef HAVE_GETADDRINFO
# undef HAVE_GETHOSTBYNAME
#elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
# define CURLRES_ASYNCH
# define CURLRES_THREADED
#else
# define CURLRES_SYNCH
#endif
lib/hostip.c(同步模式使用ALARM控制DNS解析超时):
只有定义了CURLRES_SYNCH,才可能定义USE_ALARM_TIMEOUT。
#if defined(CURLRES_SYNCH) && \
defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP)
/* alarm-based timeouts can only be used with all the dependencies satisfied */
#define USE_ALARM_TIMEOUT
#endif
相关源代码:
lib/asyn-ares.c:
Curl_resolver_getaddrinfo
lib/hostasyn.c(基于c-ares的异步版本Curl_getaddrinfo):
Curl_resolver_getaddrinfo <-- Curl_getaddrinfo
从缓存中找(hostip.c):
fetch_addr <-- Curl_resolv
hostip.c:
Curl_ipv4_resolve_r <-- Curl_getaddrinfo <-- Curl_resolv
hostip.c:
curl_jmpenv <-- sigaction(SIGALRM, alarmfunc)/sigsetjmp(curl_jmpenv) <- Curl_resolv_timeout <-
url.c:
Curl_resolv_timeout(hostname) <-- resolve_server <-- create_conn <-- Curl_connect
multi.c:
Curl_connect <--
transfer.c
Curl_connect <-- Curl_reconnect_request
url.c:
Curl_reconnect_request <-- Curl_do
multi.c:
Curl_do <-- multi_runsingle <-- curl_multi_perform <-- multi_socket <-- curl_multi_socket