Commit b35c3098 by Patrick Steinhardt

curl: explicitly initialize and cleanup global curl state

Our curl-based streams make use of the easy curl interface. This
interface automatically initializes and de-initializes the global curl
state by calling out to `curl_global_init` and `curl_global_cleanup`.
Thus, all global state will be repeatedly re-initialized when creating
multiple curl streams in succession. Despite being inefficient, this is
not thread-safe due to `curl_global_init` being not thread-safe itself.
Thus a multi-threaded programing handling multiple curl streams at the
same time is inherently racy.

Fix the issue by globally initializing and cleaning up curl's state.
parent 9e98f49d
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "stream.h" #include "stream.h"
#include "git2/transport.h" #include "git2/transport.h"
#include "buffer.h" #include "buffer.h"
#include "global.h"
#include "vector.h" #include "vector.h"
#include "proxy.h" #include "proxy.h"
...@@ -36,6 +37,18 @@ typedef struct { ...@@ -36,6 +37,18 @@ typedef struct {
git_cred *proxy_cred; git_cred *proxy_cred;
} curl_stream; } curl_stream;
int git_curl_stream_global_init(void)
{
if (curl_global_init(CURL_GLOBAL_ALL) != 0) {
giterr_set(GITERR_NET, "could not initialize curl");
return -1;
}
/* `curl_global_cleanup` is provided by libcurl */
git__on_shutdown(curl_global_cleanup);
return 0;
}
static int seterr_curl(curl_stream *s) static int seterr_curl(curl_stream *s)
{ {
giterr_set(GITERR_NET, "curl error: %s\n", s->curl_error); giterr_set(GITERR_NET, "curl error: %s\n", s->curl_error);
...@@ -351,6 +364,11 @@ int git_curl_stream_new(git_stream **out, const char *host, const char *port) ...@@ -351,6 +364,11 @@ int git_curl_stream_new(git_stream **out, const char *host, const char *port)
#include "stream.h" #include "stream.h"
int git_curl_stream_global_init(void)
{
return 0;
}
int git_curl_stream_new(git_stream **out, const char *host, const char *port) int git_curl_stream_new(git_stream **out, const char *host, const char *port)
{ {
GIT_UNUSED(out); GIT_UNUSED(out);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "git2/sys/stream.h" #include "git2/sys/stream.h"
extern int git_curl_stream_global_init(void);
extern int git_curl_stream_new(git_stream **out, const char *host, const char *port); extern int git_curl_stream_new(git_stream **out, const char *host, const char *port);
#endif #endif
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "sysdir.h" #include "sysdir.h"
#include "filter.h" #include "filter.h"
#include "merge_driver.h" #include "merge_driver.h"
#include "curl_stream.h"
#include "openssl_stream.h" #include "openssl_stream.h"
#include "thread-utils.h" #include "thread-utils.h"
#include "git2/global.h" #include "git2/global.h"
...@@ -22,7 +23,7 @@ ...@@ -22,7 +23,7 @@
git_mutex git__mwindow_mutex; git_mutex git__mwindow_mutex;
#define MAX_SHUTDOWN_CB 9 #define MAX_SHUTDOWN_CB 10
static git_global_shutdown_fn git__shutdown_callbacks[MAX_SHUTDOWN_CB]; static git_global_shutdown_fn git__shutdown_callbacks[MAX_SHUTDOWN_CB];
static git_atomic git__n_shutdown_callbacks; static git_atomic git__n_shutdown_callbacks;
...@@ -62,7 +63,8 @@ static int init_common(void) ...@@ -62,7 +63,8 @@ static int init_common(void)
(ret = git_filter_global_init()) == 0 && (ret = git_filter_global_init()) == 0 &&
(ret = git_merge_driver_global_init()) == 0 && (ret = git_merge_driver_global_init()) == 0 &&
(ret = git_transport_ssh_global_init()) == 0 && (ret = git_transport_ssh_global_init()) == 0 &&
(ret = git_openssl_stream_global_init()) == 0) (ret = git_openssl_stream_global_init()) == 0 &&
(ret = git_curl_stream_global_init()) == 0)
ret = git_mwindow_global_init(); ret = git_mwindow_global_init();
GIT_MEMORY_BARRIER; GIT_MEMORY_BARRIER;
......
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