+/*
+ * err_shelve_state returns the current thread local error state
+ * and freezes the error module until err_unshelve_state is called.
+ */
+int err_shelve_state(void **state)
+{
+ int saveerrno = get_last_sys_error();
+
+ /*
+ * Note, at present our only caller is OPENSSL_init_crypto(), indirectly
+ * via ossl_init_load_crypto_nodelete(), by which point the requested
+ * "base" initialization has already been performed, so the below call is a
+ * NOOP, that re-enters OPENSSL_init_crypto() only to quickly return.
+ *
+ * If are no other valid callers of this function, the call below can be
+ * removed, avoiding the re-entry into OPENSSL_init_crypto(). If there are
+ * potential uses that are not from inside OPENSSL_init_crypto(), then this
+ * call is needed, but some care is required to make sure that the re-entry
+ * remains a NOOP.
+ */
+ if (!OPENSSL_init_crypto(OPENSSL_INIT_BASE_ONLY, NULL))
+ return 0;
+
+ if (!RUN_ONCE(&err_init, err_do_init))
+ return 0;
+
+ *state = CRYPTO_THREAD_get_local(&err_thread_local);
+ if (!CRYPTO_THREAD_set_local(&err_thread_local, (ERR_STATE*)-1))
+ return 0;
+
+ set_sys_error(saveerrno);
+ return 1;
+}
+
+/*
+ * err_unshelve_state restores the error state that was returned
+ * by err_shelve_state previously.
+ */
+void err_unshelve_state(void* state)
+{
+ if (state != (void*)-1)
+ CRYPTO_THREAD_set_local(&err_thread_local, (ERR_STATE*)state);
+}
+