@@ -812,23 +812,6 @@ static std::vector<X509*>& GetSystemStoreCACertificates() {
812812 return system_store_certs;
813813}
814814
815- static void LoadSystemCACertificates (void * data) {
816- GetSystemStoreCACertificates ();
817- }
818-
819- static uv_thread_t system_ca_thread;
820- static bool system_ca_thread_started = false ;
821- int LoadSystemCACertificatesOffThread () {
822- // This is only run once during the initialization of the process, so
823- // it is safe to use a static thread here.
824- int r =
825- uv_thread_create (&system_ca_thread, LoadSystemCACertificates, nullptr );
826- if (r == 0 ) {
827- system_ca_thread_started = true ;
828- }
829- return r;
830- }
831-
832815static std::vector<X509*> InitializeExtraCACertificates () {
833816 std::vector<X509*> extra_certs;
834817 unsigned long err = LoadCertsFromFile ( // NOLINT(runtime/int)
@@ -852,6 +835,53 @@ static std::vector<X509*>& GetExtraCACertificates() {
852835 return extra_certs;
853836}
854837
838+ static void LoadCACertificates (void * data) {
839+ per_process::Debug (DebugCategory::CRYPTO,
840+ " Started loading system root certificates off-thread\n " );
841+ GetSystemStoreCACertificates ();
842+ }
843+
844+ static std::atomic<bool > tried_cert_loading_off_thread = false ;
845+ static std::atomic<bool > cert_loading_thread_started = false ;
846+ static Mutex start_cert_loading_thread_mutex;
847+ static uv_thread_t cert_loading_thread;
848+
849+ void StartLoadingCertificatesOffThread (
850+ const FunctionCallbackInfo<Value>& args) {
851+ // Load the CA certificates eagerly off the main thread to avoid
852+ // blocking the main thread when the first TLS connection is made. We
853+ // don't need to wait for the thread to finish with code here, as
854+ // Get*CACertificates() functions has a function-local static and any
855+ // actual user of it will wait for that to complete initialization.
856+
857+ {
858+ Mutex::ScopedLock cli_lock (node::per_process::cli_options_mutex);
859+ if (!per_process::cli_options->use_system_ca ) {
860+ return ;
861+ }
862+ }
863+
864+ // Only try to start the thread once. If it ever fails, we won't try again.
865+ if (tried_cert_loading_off_thread.load ()) {
866+ return ;
867+ }
868+ {
869+ Mutex::ScopedLock lock (start_cert_loading_thread_mutex);
870+ // Re-check under the lock.
871+ if (tried_cert_loading_off_thread.load ()) {
872+ return ;
873+ }
874+ tried_cert_loading_off_thread.store (true );
875+ int r = uv_thread_create (&cert_loading_thread, LoadCACertificates, nullptr );
876+ cert_loading_thread_started.store (r == 0 );
877+ if (r != 0 ) {
878+ FPrintF (stderr,
879+ " Warning: Failed to load CA certificates off thread: %s\n " ,
880+ uv_strerror (r));
881+ }
882+ }
883+ }
884+
855885// Due to historical reasons the various options of CA certificates
856886// may invalid one another. The current rule is:
857887// 1. If the configure-time option --openssl-use-def-ca-store is NOT used
@@ -940,9 +970,12 @@ void CleanupCachedRootCertificates() {
940970 X509_free (cert);
941971 }
942972 }
943- if (system_ca_thread_started) {
944- uv_thread_join (&system_ca_thread);
945- system_ca_thread_started = false ;
973+
974+ // Serialize with starter to avoid the race window.
975+ Mutex::ScopedLock lock (start_cert_loading_thread_mutex);
976+ if (tried_cert_loading_off_thread.load () &&
977+ cert_loading_thread_started.load ()) {
978+ uv_thread_join (&cert_loading_thread);
946979 }
947980}
948981
@@ -1231,6 +1264,10 @@ void SecureContext::Initialize(Environment* env, Local<Object> target) {
12311264 SetMethod (context, target, " resetRootCertStore" , ResetRootCertStore);
12321265 SetMethodNoSideEffect (
12331266 context, target, " getUserRootCertificates" , GetUserRootCertificates);
1267+ SetMethod (context,
1268+ target,
1269+ " startLoadingCertificatesOffThread" ,
1270+ StartLoadingCertificatesOffThread);
12341271}
12351272
12361273void SecureContext::RegisterExternalReferences (
@@ -1275,6 +1312,7 @@ void SecureContext::RegisterExternalReferences(
12751312 registry->Register (GetExtraCACertificates);
12761313 registry->Register (ResetRootCertStore);
12771314 registry->Register (GetUserRootCertificates);
1315+ registry->Register (StartLoadingCertificatesOffThread);
12781316}
12791317
12801318SecureContext* SecureContext::Create (Environment* env) {
0 commit comments