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
|
// conflicts for some defines, at least on Windows
|
||||||
#include <kicad_curl/kicad_curl.h>
|
#include <kicad_curl/kicad_curl.h>
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
#include <ki_exception.h> // THROW_IO_ERROR
|
#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()
|
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 )
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock( s_lock );
|
|
||||||
|
|
||||||
if( !s_initialized )
|
|
||||||
{
|
{
|
||||||
if( curl_global_init( CURL_GLOBAL_ALL ) != CURLE_OK )
|
if( curl_global_init( CURL_GLOBAL_ALL ) != CURLE_OK )
|
||||||
{
|
{
|
||||||
THROW_IO_ERROR( "curl_global_init() failed." );
|
THROW_IO_ERROR( "curl_global_init() failed." );
|
||||||
}
|
}
|
||||||
|
|
||||||
s_initialized = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void KICAD_CURL::Cleanup()
|
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();
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -115,12 +115,6 @@ static int progressinfo( void* aProgress, double aDLtotal, double aDLnow, double
|
||||||
KICAD_CURL_EASY::KICAD_CURL_EASY() :
|
KICAD_CURL_EASY::KICAD_CURL_EASY() :
|
||||||
m_headers( nullptr )
|
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();
|
m_CURL = curl_easy_init();
|
||||||
|
|
||||||
if( !m_CURL )
|
if( !m_CURL )
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
#include <eda_draw_frame.h>
|
#include <eda_draw_frame.h>
|
||||||
#include <gestfich.h>
|
#include <gestfich.h>
|
||||||
#include <id.h>
|
#include <id.h>
|
||||||
|
#include <kicad_curl/kicad_curl.h>
|
||||||
#include <kiplatform/policy.h>
|
#include <kiplatform/policy.h>
|
||||||
#include <lockfile.h>
|
#include <lockfile.h>
|
||||||
#include <menus_helpers.h>
|
#include <menus_helpers.h>
|
||||||
|
@ -151,6 +152,8 @@ PGM_BASE::~PGM_BASE()
|
||||||
|
|
||||||
void PGM_BASE::Destroy()
|
void PGM_BASE::Destroy()
|
||||||
{
|
{
|
||||||
|
KICAD_CURL::Cleanup();
|
||||||
|
|
||||||
#ifdef KICAD_USE_SENTRY
|
#ifdef KICAD_USE_SENTRY
|
||||||
sentry_close();
|
sentry_close();
|
||||||
#endif
|
#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
|
// In particular, the user cache path is the most likely to be hit by startup code
|
||||||
PATHS::EnsureUserPathsExist();
|
PATHS::EnsureUserPathsExist();
|
||||||
|
|
||||||
|
KICAD_CURL::Init();
|
||||||
|
|
||||||
#ifdef KICAD_USE_SENTRY
|
#ifdef KICAD_USE_SENTRY
|
||||||
sentryInit();
|
sentryInit();
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -53,10 +53,6 @@
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
struct DYN_LOOKUP;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple wrapper class to call curl_global_init and curl_global_cleanup for KiCad.
|
* Simple wrapper class to call curl_global_init and curl_global_cleanup for KiCad.
|
||||||
*/
|
*/
|
||||||
|
@ -88,17 +84,6 @@ public:
|
||||||
{
|
{
|
||||||
return curl_version();
|
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_
|
#endif // KICAD_CURL_H_
|
||||||
|
|
Loading…
Reference in New Issue