Author: brane
Date: Mon Jun 23 10:06:34 2025
New Revision: 1926660
URL: http://svn.apache.org/viewvc?rev=1926660&view=rev
Log:
Add a serialized-one-time-init helper function and use it in the OpenSSL
initialization code. We'll need it in other places, too, so it makes sense
to abstract the spinlock.
* serf_private.h
(struct serf__init_once_context,
SERF__INIT_ONCE_NONE,
SERF__DECLARE_STATIC_INIT_ONCE_CONTEXT,
serf__init_once_func_t,
serf__init_once): New declarations.
* src/init_once.c: New; implements one-time initialization logic.
* buckets/ssl_buckets.c
(apr_atomic_cas32): Remove conditional macro wrapper.
(enum ssl_init_e): Remove unused enum.
(do_init_libraries): Rename from init_ssl_libraries. Remove all the
spinlock logic. Return an error if the mutex could not be creasted,
resolving a FIXME comment.
(init_ssl_libraries): New; calls serf__init_once with do_init_libraries
as the initialization function.
(ssl_need_client_cert, serf_ssl_load_cert_file): Fail if library init fails.
* CMakeLists.txt (SOURCES): Add src/init_once.c.
Added:
serf/trunk/src/init_once.c (with props)
Modified:
serf/trunk/CMakeLists.txt
serf/trunk/buckets/ssl_buckets.c
serf/trunk/serf_private.h
Modified: serf/trunk/CMakeLists.txt
URL:
http://svn.apache.org/viewvc/serf/trunk/CMakeLists.txt?rev=1926660&r1=1926659&r2=1926660&view=diff
==============================================================================
--- serf/trunk/CMakeLists.txt (original)
+++ serf/trunk/CMakeLists.txt Mon Jun 23 10:06:34 2025
@@ -131,6 +131,7 @@ list(APPEND SOURCES
"src/context.c"
"src/deprecated.c"
"src/incoming.c"
+ "src/init_once.c"
"src/logging.c"
"src/outgoing.c"
"src/outgoing_request.c"
Modified: serf/trunk/buckets/ssl_buckets.c
URL:
http://svn.apache.org/viewvc/serf/trunk/buckets/ssl_buckets.c?rev=1926660&r1=1926659&r2=1926660&view=diff
==============================================================================
--- serf/trunk/buckets/ssl_buckets.c (original)
+++ serf/trunk/buckets/ssl_buckets.c Mon Jun 23 10:06:34 2025
@@ -1467,90 +1467,66 @@ static apr_status_t cleanup_ssl(void *da
#endif
-#if !APR_VERSION_AT_LEAST(1,0,0)
-#define apr_atomic_cas32(mem, with, cmp) apr_atomic_cas(mem, with, cmp)
-#endif
-enum ssl_init_e
+static apr_status_t do_init_libraries(void* baton)
{
- INIT_UNINITIALIZED = 0,
- INIT_BUSY = 1,
- INIT_DONE = 2
-};
-
-static volatile apr_uint32_t have_init_ssl = INIT_UNINITIALIZED;
-
-static void init_ssl_libraries(void)
-{
- apr_uint32_t val;
-
- val = apr_atomic_cas32(&have_init_ssl, INIT_BUSY, INIT_UNINITIALIZED);
-
- if (!val) {
#if APR_HAS_THREADS && defined(SERF_HAVE_SSL_LOCKING_CALLBACKS)
- int i, numlocks;
+ int i, numlocks;
#endif
#ifdef SERF_LOGGING_ENABLED
- /* Warn when compile-time and run-time version of OpenSSL differ in
- major/minor version number. */
+ /* Warn when compile-time and run-time version of OpenSSL differ in
+ major/minor version number. */
#ifdef SERF_HAVE_OPENSSL_VERSION_NUM
- unsigned long libver = OpenSSL_version_num();
+ unsigned long libver = OpenSSL_version_num();
#else
- long libver = SSLeay();
+ long libver = SSLeay();
#endif
- if ((libver ^ OPENSSL_VERSION_NUMBER) & 0xFFF00000) {
- serf__log(LOGLVL_WARNING, LOGCOMP_SSL, __FILE__, NULL,
- "Warning: OpenSSL library version mismatch, compile-"
- "time was %lx, runtime is %lx.\n",
- OPENSSL_VERSION_NUMBER, libver);
- }
+ if ((libver ^ OPENSSL_VERSION_NUMBER) & 0xFFF00000) {
+ serf__log(LOGLVL_WARNING, LOGCOMP_SSL, __FILE__, NULL,
+ "Warning: OpenSSL library version mismatch, compile-"
+ "time was %lx, runtime is %lx.\n",
+ OPENSSL_VERSION_NUMBER, libver);
+ }
#endif
#ifdef SERF_HAVE_OPENSSL_SSL_LIBRARY_INIT
- ERR_load_crypto_strings();
- SSL_load_error_strings();
- SSL_library_init();
- OpenSSL_add_all_algorithms();
+ ERR_load_crypto_strings();
+ SSL_load_error_strings();
+ SSL_library_init();
+ OpenSSL_add_all_algorithms();
#endif
#if APR_HAS_THREADS && defined(SERF_HAVE_SSL_LOCKING_CALLBACKS)
- numlocks = CRYPTO_num_locks();
- apr_pool_create(&ssl_pool, NULL);
- ssl_locks = apr_palloc(ssl_pool, sizeof(apr_thread_mutex_t*)*numlocks);
- for (i = 0; i < numlocks; i++) {
- apr_status_t rv;
+ numlocks = CRYPTO_num_locks();
+ apr_pool_create(&ssl_pool, NULL);
+ ssl_locks = apr_palloc(ssl_pool, sizeof(apr_thread_mutex_t*)*numlocks);
+ for (i = 0; i < numlocks; i++) {
+ apr_status_t status;
- /* Intraprocess locks don't /need/ a filename... */
- rv = apr_thread_mutex_create(&ssl_locks[i],
+ /* Intraprocess locks don't /need/ a filename... */
+ status = apr_thread_mutex_create(&ssl_locks[i],
APR_THREAD_MUTEX_DEFAULT, ssl_pool);
- if (rv != APR_SUCCESS) {
- /* FIXME: error out here */
- }
- }
- CRYPTO_set_locking_callback(ssl_lock);
- CRYPTO_set_id_callback(ssl_id);
- CRYPTO_set_dynlock_create_callback(ssl_dyn_create);
- CRYPTO_set_dynlock_lock_callback(ssl_dyn_lock);
- CRYPTO_set_dynlock_destroy_callback(ssl_dyn_destroy);
+ if (status != APR_SUCCESS)
+ return status;
+ }
+ CRYPTO_set_locking_callback(ssl_lock);
+ CRYPTO_set_id_callback(ssl_id);
+ CRYPTO_set_dynlock_create_callback(ssl_dyn_create);
+ CRYPTO_set_dynlock_lock_callback(ssl_dyn_lock);
+ CRYPTO_set_dynlock_destroy_callback(ssl_dyn_destroy);
- apr_pool_cleanup_register(ssl_pool, NULL, cleanup_ssl, cleanup_ssl);
+ apr_pool_cleanup_register(ssl_pool, NULL, cleanup_ssl, cleanup_ssl);
#endif
- apr_atomic_cas32(&have_init_ssl, INIT_DONE, INIT_BUSY);
- }
- else
- {
- /* Make sure we don't continue before the initialization in another
- thread has completed */
- while (val != INIT_DONE) {
- apr_sleep(APR_USEC_PER_SEC / 1000);
-
- val = apr_atomic_cas32(&have_init_ssl,
- INIT_UNINITIALIZED,
- INIT_UNINITIALIZED);
- }
- }
+
+ return APR_SUCCESS;
+}
+
+static apr_status_t init_ssl_libraries(void)
+{
+ SERF__DECLARE_STATIC_INIT_ONCE_CONTEXT(init_ctx);
+ return serf__init_once(&init_ctx, do_init_libraries, NULL);
}
static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey)
@@ -1774,7 +1750,8 @@ static serf_ssl_context_t *ssl_init_cont
{
serf_ssl_context_t *ssl_ctx;
- init_ssl_libraries();
+ if (init_ssl_libraries())
+ return NULL;
ssl_ctx = serf_bucket_mem_alloc(allocator, sizeof(*ssl_ctx));
@@ -2023,11 +2000,13 @@ apr_status_t serf_ssl_load_cert_file(
status = apr_file_open(&cert_file, file_path, APR_READ, APR_OS_DEFAULT,
pool);
+ if (!status) {
+ status = init_ssl_libraries();
+ }
if (status) {
return status;
}
- init_ssl_libraries();
biom = bio_meth_file_new();
bio = BIO_new(biom);
Modified: serf/trunk/serf_private.h
URL:
http://svn.apache.org/viewvc/serf/trunk/serf_private.h?rev=1926660&r1=1926659&r2=1926660&view=diff
==============================================================================
--- serf/trunk/serf_private.h (original)
+++ serf/trunk/serf_private.h Mon Jun 23 10:06:34 2025
@@ -167,6 +167,32 @@ typedef int serf__bool_t; /* Not _Bool *
#endif
#endif
+/*** One-time initialization. ***/
+
+/* Init-once context. */
+struct serf__init_once_context
+{
+ volatile apr_uint32_t state;
+ apr_status_t status;
+};
+
+#define SERF__INIT_ONCE_NONE 0
+#define SERF__DECLARE_STATIC_INIT_ONCE_CONTEXT(name) \
+ static struct serf__init_once_context name = { \
+ SERF__INIT_ONCE_NONE, APR_SUCCESS \
+ }
+
+/* The init-once callback function. */
+typedef apr_status_t (*serf__init_once_func_t)(void *baton);
+
+/* The function that performs on-time initialization.
+ If APR_HAS_THREADS, will use a spinlock to serialize the call to
+ the initialization function. */
+apr_status_t serf__init_once(struct serf__init_once_context *init_ctx,
+ serf__init_once_func_t init_func,
+ void *init_baton);
+
+
typedef struct serf__authn_scheme_t serf__authn_scheme_t;
typedef struct serf_io_baton_t {
Added: serf/trunk/src/init_once.c
URL:
http://svn.apache.org/viewvc/serf/trunk/src/init_once.c?rev=1926660&view=auto
==============================================================================
--- serf/trunk/src/init_once.c (added)
+++ serf/trunk/src/init_once.c Mon Jun 23 10:06:34 2025
@@ -0,0 +1,88 @@
+/* ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+#include <apr.h>
+#include <apr_version.h>
+#if APR_HAS_THREADS
+# include <apr_atomic.h>
+# include <apr_time.h>
+/* FIXME: Do we really want to support APR-0.9.x? */
+# if APR_MAJOR_VERSION < 1
+# define apr_atomic_cas32(m, v, c) apr_atomic_cas((m), (v), (c))
+# endif
+#endif
+
+#include "serf.h"
+#include "serf_private.h"
+
+
+enum init_once_state
+{
+ INIT_ONCE_NONE = SERF__INIT_ONCE_NONE,
+ INIT_ONCE_BUSY,
+ INIT_ONCE_DONE
+};
+
+static apr_uint32_t cas(volatile apr_uint32_t *mem,
+ apr_uint32_t val,
+ apr_uint32_t cmp)
+{
+#if APR_HAS_THREADS
+ return apr_atomic_cas32(mem, val, cmp);
+#else
+ const apr_uint32_t prev = *mem;
+ if (prev == cmp) {
+ *mem = val;
+ }
+ return prev;
+#endif
+}
+
+apr_status_t serf__init_once(struct serf__init_once_context *init_ctx,
+ serf__init_once_func_t init_func,
+ void *init_baton)
+{
+ apr_uint32_t state = cas(&init_ctx->state, INIT_ONCE_BUSY, INIT_ONCE_NONE);
+ for (;;)
+ {
+ switch (state)
+ {
+ case INIT_ONCE_DONE:
+ /* Already initialized. */
+ return init_ctx->status;
+
+ case INIT_ONCE_BUSY:
+ /* Spin while the initializer is working. */
+ apr_sleep(APR_USEC_PER_SEC / 500);
+ state = cas(&init_ctx->state, INIT_ONCE_NONE, INIT_ONCE_NONE);
+ continue;
+
+ case INIT_ONCE_NONE:
+ /* We're the single initializer, invoke the init code. */
+ init_ctx->status = init_func(init_baton);
+ cas(&init_ctx->state, INIT_ONCE_DONE, INIT_ONCE_BUSY);
+ return init_ctx->status;
+
+ default:
+ /* Not reached, can't happen. */
+ return APR_EGENERAL; /* FIXME: Just abort()? */
+ }
+ }
+}
Propchange: serf/trunk/src/init_once.c
------------------------------------------------------------------------------
svn:eol-style = native