taskpool.c \
timer.c \
tls.c \
+ trampoline.c \
+ trampoline_p.h \
tm.c \
utf8.c \
pthreads/condition.c \
#include "mem_p.h"
#include "tls_p.h"
+#include "trampoline_p.h"
/***
*** Functions
isc__initialize(void) {
isc__mem_initialize();
isc__tls_initialize();
+ isc__trampoline_initialize();
}
void
isc__shutdown(void) {
+ isc__trampoline_shutdown();
isc__tls_shutdown();
isc__mem_shutdown();
}
#include <isc/lang.h>
#include <isc/result.h>
+extern thread_local size_t isc_tid_v;
+
ISC_LANG_BEGINDECLS
typedef pthread_t isc_thread_t;
#include <isc/thread.h>
#include <isc/util.h>
+#include "trampoline_p.h"
+
#ifndef THREAD_MINSTACKSIZE
#define THREAD_MINSTACKSIZE (1024U * 1024)
#endif /* ifndef THREAD_MINSTACKSIZE */
isc_thread_create(isc_threadfunc_t func, isc_threadarg_t arg,
isc_thread_t *thread) {
pthread_attr_t attr;
+ isc__trampoline_t *trampoline_arg;
+
+ trampoline_arg = isc__trampoline_get(func, arg);
+
#if defined(HAVE_PTHREAD_ATTR_GETSTACKSIZE) && \
defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE)
size_t stacksize;
#endif /* if defined(HAVE_PTHREAD_ATTR_GETSTACKSIZE) && \
* defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE) */
- ret = pthread_create(thread, &attr, func, arg);
+ ret = pthread_create(thread, &attr, isc__trampoline_run,
+ trampoline_arg);
if (ret != 0) {
_FATAL(ret, "pthread_create()");
}
--- /dev/null
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include <isc/mem.h>
+#include <isc/mutex.h>
+#include <isc/once.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+
+#include "trampoline_p.h"
+
+#define ISC__TRAMPOLINE_UNUSED 0
+
+struct isc__trampoline {
+ int tid; /* const */
+ isc_thread_t self;
+ isc_threadfunc_t start;
+ isc_threadarg_t arg;
+};
+
+static isc_once_t isc__trampoline_initialize_once = ISC_ONCE_INIT;
+static isc_once_t isc__trampoline_shutdown_once = ISC_ONCE_INIT;
+static isc_mutex_t isc__trampoline_lock;
+static isc__trampoline_t **trampolines;
+thread_local size_t isc_tid_v = SIZE_MAX;
+static size_t isc__trampoline_min = 1;
+static size_t isc__trampoline_max = 65;
+
+/*
+ * We can't use isc_mem API here, because it's called too
+ * early and when the isc_mem_debugging flags are changed
+ * later and ISC_MEM_DEBUGSIZE or ISC_MEM_DEBUGCTX flags are
+ * added, neither isc_mem_put() nor isc_mem_free() can be used
+ * to free up the memory allocated here because the flags were
+ * not set when calling isc_mem_get() or isc_mem_allocate()
+ * here.
+ *
+ * Actually, since this is a single allocation at library load
+ * and deallocation at library unload, using the standard
+ * allocator without the tracking is fine for this purpose.
+ */
+static isc__trampoline_t *
+isc__trampoline_new(int tid, isc_threadfunc_t start, isc_threadarg_t arg) {
+ isc__trampoline_t *trampoline = calloc(1, sizeof(*trampoline));
+ RUNTIME_CHECK(trampoline != NULL);
+
+ *trampoline = (isc__trampoline_t){
+ .tid = tid,
+ .start = start,
+ .arg = arg,
+ .self = ISC__TRAMPOLINE_UNUSED,
+ };
+
+ return (trampoline);
+}
+
+static void
+trampoline_initialize(void) {
+ isc_mutex_init(&isc__trampoline_lock);
+
+ trampolines = calloc(isc__trampoline_max, sizeof(trampolines[0]));
+ RUNTIME_CHECK(trampolines != NULL);
+
+ /* Get the trampoline slot 0 for the main thread */
+ trampolines[0] = isc__trampoline_new(0, NULL, NULL);
+ trampolines[0]->self = isc_thread_self();
+ isc_tid_v = trampolines[0]->tid;
+
+ /* Initialize the other trampolines */
+ for (size_t i = 1; i < isc__trampoline_max; i++) {
+ trampolines[i] = NULL;
+ }
+ isc__trampoline_min = 1;
+}
+
+void
+isc__trampoline_initialize(void) {
+ isc_result_t result = isc_once_do(&isc__trampoline_initialize_once,
+ trampoline_initialize);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+}
+
+static void
+trampoline_shutdown(void) {
+ /*
+ * When the program using the library exits abruptly and the library
+ * gets unloaded, there might be some existing trampolines from unjoined
+ * threads. We intentionally ignore those and don't check whether all
+ * trampolines have been cleared before exiting.
+ */
+ free(trampolines[0]);
+ free(trampolines);
+ trampolines = NULL;
+ isc_mutex_destroy(&isc__trampoline_lock);
+}
+
+void
+isc__trampoline_shutdown(void) {
+ isc_result_t result = isc_once_do(&isc__trampoline_shutdown_once,
+ trampoline_shutdown);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+}
+
+isc__trampoline_t *
+isc__trampoline_get(isc_threadfunc_t start, isc_threadarg_t arg) {
+ isc__trampoline_t **tmp = NULL;
+ isc__trampoline_t *trampoline = NULL;
+ LOCK(&isc__trampoline_lock);
+again:
+ for (size_t i = isc__trampoline_min; i < isc__trampoline_max; i++) {
+ if (trampolines[i] == NULL) {
+ trampoline = isc__trampoline_new(i, start, arg);
+ trampolines[i] = trampoline;
+ isc__trampoline_min = i + 1;
+ goto done;
+ }
+ }
+ tmp = calloc(2 * isc__trampoline_max, sizeof(trampolines[0]));
+ RUNTIME_CHECK(tmp != NULL);
+ for (size_t i = 0; i < isc__trampoline_max; i++) {
+ tmp[i] = trampolines[i];
+ }
+ for (size_t i = isc__trampoline_max; i < 2 * isc__trampoline_max; i++) {
+ tmp[i] = NULL;
+ }
+ free(trampolines);
+ trampolines = tmp;
+ isc__trampoline_max = isc__trampoline_max * 2;
+ goto again;
+done:
+ INSIST(trampoline != NULL);
+ UNLOCK(&isc__trampoline_lock);
+
+ return (trampoline);
+}
+
+static void
+trampoline_put(isc__trampoline_t *trampoline) {
+ LOCK(&isc__trampoline_lock);
+ REQUIRE(trampoline->tid > 0 &&
+ (size_t)trampoline->tid < isc__trampoline_max);
+ REQUIRE(trampoline->self == isc_thread_self());
+ REQUIRE(trampolines[trampoline->tid] == trampoline);
+
+ trampolines[trampoline->tid] = NULL;
+
+ if (isc__trampoline_min > (size_t)trampoline->tid) {
+ isc__trampoline_min = trampoline->tid;
+ }
+
+ free(trampoline);
+
+ UNLOCK(&isc__trampoline_lock);
+ return;
+}
+
+isc_threadresult_t
+isc__trampoline_run(isc_threadarg_t arg) {
+ isc__trampoline_t *trampoline = (isc__trampoline_t *)arg;
+ isc_threadresult_t result;
+
+ REQUIRE(trampoline->tid > 0 &&
+ (size_t)trampoline->tid < isc__trampoline_max);
+ REQUIRE(trampoline->self == ISC__TRAMPOLINE_UNUSED);
+
+ /* Initialize the trampoline */
+ isc_tid_v = trampoline->tid;
+ trampoline->self = isc_thread_self();
+
+ /* Run the main function */
+ result = (trampoline->start)(trampoline->arg);
+
+ trampoline_put(trampoline);
+
+ return (result);
+}
--- /dev/null
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+#include <isc/thread.h>
+
+typedef struct isc__trampoline isc__trampoline_t;
+
+void
+isc__trampoline_initialize(void);
+/*%<
+ * Initialize the thread trampoline internal structures, must be called only
+ * once as a library constructor (see lib/isc/lib.c).
+ */
+
+void
+isc__trampoline_shutdown(void);
+/*%<
+ * Destroy the thread trampoline internal structures, must be called only
+ * once as a library destructor (see lib/isc/lib.c).
+ */
+
+isc__trampoline_t *
+isc__trampoline_get(isc_threadfunc_t start_routine, isc_threadarg_t arg);
+/*%<
+ * Get a free thread trampoline structure and initialize it with
+ * start_routine and arg passed to start_routine.
+ *
+ * Requires:
+ *\li 'start_routine' is a valid non-NULL thread start_routine
+ */
+
+isc_threadresult_t
+isc__trampoline_run(isc_threadarg_t arg);
+/*%<
+ * Run the thread trampoline, this will get passed to the actual
+ * pthread_create() (or Windows equivalent), initialize the isc_tid_v.
+ *
+ * Requires:
+ *\li 'arg' is a valid isc_trampoline_t
+ *
+ * Returns:
+ *\li return value from start_routine (see isc__trampoline_get())
+ */
#include "mem_p.h"
#include "tls_p.h"
+#include "trampoline_p.h"
/*
* Called when we enter the DLL
case DLL_PROCESS_ATTACH:
isc__mem_initialize();
isc__tls_initialize();
+ isc__trampoline_initialize();
break;
/*
* termination or a call to FreeLibrary.
*/
case DLL_PROCESS_DETACH:
+ isc__trampoline_shutdown();
isc__tls_shutdown();
isc__mem_shutdown();
break;
#include <isc/lang.h>
#include <isc/result.h>
+extern thread_local size_t isc_tid_v;
+
/*
* Inlines to help with wait return checking
*/
isc_tlsctx_createclient
isc_tlsctx_createserver
isc_tlsctx_free
+isc__trampoline_initialize
+isc__trampoline_shutdown
+isc__trampoline_get
+isc__trampoline_run
isc_tm_timegm
isc_tm_strptime
isc_url_parse
isc_dscp_check_value DATA
isc_hashctx DATA
isc_mem_debugging DATA
+isc_tid_v DATA
@IF PKCS11
pk11_verbose_init DATA
@END PKCS11
<ClInclude Include="..\openssl_shim.h">
<Filter>Win32 Header Files</Filter>
</ClInclude>
+ <ClInclude Include="..\trampoline_p.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
<ClInclude Include="errno2result.h">
<Filter>Win32 Header Files</Filter>
</ClInclude>
<ClCompile Include="..\tlsstream.c">
<Filter>Library Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\trampoline.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\tm.c">
<Filter>Library Source Files</Filter>
</ClCompile>
<ClInclude Include="..\entropy_private.h" />
<ClInclude Include="..\fsaccess_common_p.h" />
<ClInclude Include="..\openssl_shim.h" />
+ <ClInclude Include="..\trampoline_p.h" />
<ClInclude Include="syslog.h" />
<ClInclude Include="unistd.h" />
<ClInclude Include="..\..\versions.h" />
<ClCompile Include="..\task.c" />
<ClCompile Include="..\taskpool.c" />
<ClCompile Include="..\timer.c" />
+ <ClCompile Include="..\trampoline.c" />
<ClCompile Include="..\tls.c" />
<ClCompile Include="..\tm.c" />
<ClCompile Include="..\url.c" />
#include <process.h>
+#include <isc/mutex.h>
+#include <isc/once.h>
#include <isc/strerr.h>
#include <isc/thread.h>
#include <isc/util.h>
+#include "trampoline_p.h"
+
void
isc_thread_create(isc_threadfunc_t start, isc_threadarg_t arg,
isc_thread_t *threadp) {
isc_thread_t thread;
unsigned int id;
+ isc__trampoline_t *trampoline_arg;
+
+ trampoline_arg = isc__trampoline_get(start, arg);
- thread = (isc_thread_t)_beginthreadex(NULL, 0, start, arg, 0, &id);
+ thread = (isc_thread_t)_beginthreadex(NULL, 0, isc__trampoline_run,
+ trampoline_arg, 0, &id);
if (thread == NULL) {
char strbuf[ISC_STRERRORSIZE];
strerror_r(errno, strbuf, sizeof(strbuf));
./lib/isc/tls.c C 2021
./lib/isc/tls_p.h C 2021
./lib/isc/tm.c C 2014,2016,2018,2019,2020,2021
+./lib/isc/trampoline.c C 2021
+./lib/isc/trampoline_p.h C 2021
./lib/isc/unix/dir.c C 1999,2000,2001,2004,2005,2007,2008,2009,2011,2012,2016,2017,2018,2019,2020,2021
./lib/isc/unix/errno.c C 2016,2018,2019,2020,2021
./lib/isc/unix/errno2result.c C 2000,2001,2002,2004,2005,2007,2011,2012,2013,2016,2018,2019,2020,2021