Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows support for registration of C threads from callbacks #450

Merged
merged 1 commit into from
Sep 27, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 62 additions & 3 deletions src/ctypes-foreign-threaded/foreign_threaded_stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,76 @@
#include <caml/mlvalues.h>
#include <caml/threads.h>

extern int (*ctypes_thread_register)(void);

#ifdef _WIN32
#include <caml/fail.h>
#include <windows.h>

/* The OCaml runtime stores the pointers to the information that must
be cleaned up in thread local storage. Therefore
caml_c_thread_unregister must be called from the thread itself.
.CRT$XLA to .CRT$XLZ is an array of callback pointers that are
called by the OS when the DLL is loaded and on thread attachment /
detachment (they were introduced for the current task: set up and
clean thread local storage).

Note: Only Windows Vista and later execute the TLS callbacks for
dynamically loaded DLLs (-> Windows XP restrictions: no toplevel
support, bytecode executables must be compiled with '-custom').
*/

/* ctypes_tls_callback will be called for all threads. The OCaml
runtime use the same TLS $index for its own threads and threads
registered with caml_c_thread_register. TlsSetValue($index,NULL) is
only called during caml_c_thread_unregister, but not for threads
created by OCaml. Therefore an additional TLS index is allocated to
ensure, that caml_c_thread_unregister is not called for these
threads.
*/
static DWORD tls_index;
#define CTYPES_TLS_MAGIC_VALUE ((void*)0x78)

static void NTAPI
ctypes_tls_callback(void* a, DWORD reason, PVOID b)
{
(void)a; (void)b;
if ( reason == DLL_THREAD_DETACH ) {
void * x = TlsGetValue(tls_index);
if ( x == CTYPES_TLS_MAGIC_VALUE ) {
TlsSetValue(tls_index, NULL);
caml_c_thread_unregister();
}
}
}

PIMAGE_TLS_CALLBACK __crt_ctypes_tls_callback__ __attribute__ \
((section(".CRT$XLB"))) = ctypes_tls_callback;

static int ctypes_thread_actually_register(void)
{
int rv = caml_c_thread_register();
if ( rv != 0 ) {
/* errors ignored (like in the case of pthread_key_create).
I can't raise an exception here and I can't store the information
anywhere */
TlsSetValue(tls_index, CTYPES_TLS_MAGIC_VALUE);
}
return rv;
}

value ctypes_setup_thread_registration(value _)
{
/* Don't override the hook on systems without pthreads. */
tls_index = TlsAlloc();
if ( tls_index == TLS_OUT_OF_INDEXES ) {
caml_failwith("ctypes_thread_registration: TlsAlloc failed");
}
ctypes_thread_register = ctypes_thread_actually_register;
return Val_unit;
}
#else
#include <pthread.h>

extern int (*ctypes_thread_register)(void);

static pthread_key_t cleanup_key;

static void ctypes_thread_unregister(void* _)
Expand Down