Init curl in InitPgm for thread safety
curl itself highly recommends not initializing curl from within a thread. Due to the PCM, this can happen in a thread these days. Pointed out by Érico Rolim in https://gitlab.com/kicad/code/kicad/-/merge_requests/855
This commit is contained in:
parent
299c88cfec
commit
8fd4909f86
|
@ -27,109 +27,21 @@
|
|||
// conflicts for some defines, at least on Windows
|
||||
#include <kicad_curl/kicad_curl.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <ki_exception.h> // THROW_IO_ERROR
|
||||
|
||||
|
||||
|
||||
// These are even more private than class members, and since there is only
|
||||
// one instance of KICAD_CURL ever, these statics are hidden here to simplify the
|
||||
// client (API) header file.
|
||||
static volatile bool s_initialized;
|
||||
|
||||
static std::mutex s_lock; // for s_initialized
|
||||
|
||||
/// At process termination, using atexit() keeps the CURL stuff out of the
|
||||
/// singletops and PGM_BASE.
|
||||
static void at_terminate()
|
||||
{
|
||||
KICAD_CURL::Cleanup();
|
||||
}
|
||||
|
||||
|
||||
void KICAD_CURL::Init()
|
||||
{
|
||||
// We test s_initialized twice in an effort to avoid
|
||||
// unnecessarily locking s_lock. This understands that the common case
|
||||
// will not need to lock.
|
||||
if( !s_initialized )
|
||||
if( curl_global_init( CURL_GLOBAL_ALL ) != CURLE_OK )
|
||||
{
|
||||
std::lock_guard<std::mutex> lock( s_lock );
|
||||
|
||||
if( !s_initialized )
|
||||
{
|
||||
if( curl_global_init( CURL_GLOBAL_ALL ) != CURLE_OK )
|
||||
{
|
||||
THROW_IO_ERROR( "curl_global_init() failed." );
|
||||
}
|
||||
|
||||
s_initialized = true;
|
||||
}
|
||||
THROW_IO_ERROR( "curl_global_init() failed." );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void KICAD_CURL::Cleanup()
|
||||
{
|
||||
/*
|
||||
|
||||
Calling lock_guard() from a static destructor will typically be bad, since the
|
||||
s_lock may already have been statically destroyed itself leading to a boost
|
||||
exception. (Remember C++ does not provide certain sequencing of static
|
||||
destructor invocation.)
|
||||
|
||||
To prevent this we test s_initialized twice, which ensures that the lock_guard
|
||||
is only instantiated on the first call, which should be from
|
||||
PGM_BASE::destroy() which is first called earlier than static destruction.
|
||||
Then when called again from the actual PGM_BASE::~PGM_BASE() function,
|
||||
lock_guard will not be instantiated because s_initialized will be false.
|
||||
|
||||
*/
|
||||
|
||||
if( s_initialized )
|
||||
{
|
||||
std::lock_guard<std::mutex> lock( s_lock );
|
||||
|
||||
if( s_initialized )
|
||||
{
|
||||
curl_global_cleanup();
|
||||
|
||||
atexit( &at_terminate );
|
||||
|
||||
s_initialized = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string KICAD_CURL::GetSimpleVersion()
|
||||
{
|
||||
if( !s_initialized )
|
||||
Init();
|
||||
|
||||
curl_version_info_data* info = curl_version_info( CURLVERSION_NOW );
|
||||
|
||||
std::string res;
|
||||
|
||||
if( info->version )
|
||||
{
|
||||
res += "libcurl version: " + std::string( info->version );
|
||||
}
|
||||
|
||||
res += " (";
|
||||
|
||||
if( info->features & CURL_VERSION_SSL )
|
||||
{
|
||||
res += "with SSL - ";
|
||||
res += std::string( info->ssl_version );
|
||||
}
|
||||
else
|
||||
{
|
||||
res += "without SSL";
|
||||
}
|
||||
res += ")";
|
||||
|
||||
return res;
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -115,12 +115,6 @@ static int progressinfo( void* aProgress, double aDLtotal, double aDLnow, double
|
|||
KICAD_CURL_EASY::KICAD_CURL_EASY() :
|
||||
m_headers( nullptr )
|
||||
{
|
||||
// Call KICAD_CURL::Init() from in here every time, but only the first time
|
||||
// will incur any overhead. This strategy ensures that libcurl is never loaded
|
||||
// unless it is needed.
|
||||
|
||||
KICAD_CURL::Init();
|
||||
|
||||
m_CURL = curl_easy_init();
|
||||
|
||||
if( !m_CURL )
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include <eda_draw_frame.h>
|
||||
#include <gestfich.h>
|
||||
#include <id.h>
|
||||
#include <kicad_curl/kicad_curl.h>
|
||||
#include <kiplatform/policy.h>
|
||||
#include <lockfile.h>
|
||||
#include <menus_helpers.h>
|
||||
|
@ -151,6 +152,8 @@ PGM_BASE::~PGM_BASE()
|
|||
|
||||
void PGM_BASE::Destroy()
|
||||
{
|
||||
KICAD_CURL::Cleanup();
|
||||
|
||||
#ifdef KICAD_USE_SENTRY
|
||||
sentry_close();
|
||||
#endif
|
||||
|
@ -409,6 +412,8 @@ bool PGM_BASE::InitPgm( bool aHeadless, bool aSkipPyInit, bool aIsUnitTest )
|
|||
// In particular, the user cache path is the most likely to be hit by startup code
|
||||
PATHS::EnsureUserPathsExist();
|
||||
|
||||
KICAD_CURL::Init();
|
||||
|
||||
#ifdef KICAD_USE_SENTRY
|
||||
sentryInit();
|
||||
#endif
|
||||
|
|
|
@ -53,10 +53,6 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
struct DYN_LOOKUP;
|
||||
|
||||
|
||||
/**
|
||||
* Simple wrapper class to call curl_global_init and curl_global_cleanup for KiCad.
|
||||
*/
|
||||
|
@ -88,17 +84,6 @@ public:
|
|||
{
|
||||
return curl_version();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Report back curl version only and SSL library support.
|
||||
*
|
||||
* @return Generated version string.
|
||||
*/
|
||||
static std::string GetSimpleVersion();
|
||||
|
||||
private:
|
||||
friend class KICAD_CURL_EASY;
|
||||
};
|
||||
|
||||
#endif // KICAD_CURL_H_
|
||||
|
|
Loading…
Reference in New Issue