Index: src/nonsfi/linux/linux_pthread_private.c |
diff --git a/src/nonsfi/linux/linux_pthread_private.c b/src/nonsfi/linux/linux_pthread_private.c |
index 0cf3cd03d0c10076cf393720abfdd0bdbf0ab83b..ed3eaa0d6ba76714b9e185514331f4cc3ee5781f 100644 |
--- a/src/nonsfi/linux/linux_pthread_private.c |
+++ b/src/nonsfi/linux/linux_pthread_private.c |
@@ -4,8 +4,10 @@ |
* found in the LICENSE file. |
*/ |
+#include <assert.h> |
#include <errno.h> |
+#include "native_client/src/nonsfi/linux/linux_pthread_private.h" |
#include "native_client/src/nonsfi/linux/linux_syscall_defines.h" |
#include "native_client/src/nonsfi/linux/linux_syscall_structs.h" |
#include "native_client/src/nonsfi/linux/linux_syscall_wrappers.h" |
@@ -79,6 +81,94 @@ static int nacl_irt_thread_nice(const int nice) { |
return 0; |
} |
+static struct nc_combined_tdb *get_irt_tdb(void *thread_ptr) { |
+ struct nc_combined_tdb *tdb = (void *) ((uintptr_t) thread_ptr + |
+ __nacl_tp_tdb_offset(sizeof(*tdb))); |
+ return tdb; |
+} |
+ |
+/* |
+ * This is the real first entry point for new threads. |
+ * Based on code from src/untrusted/irt/irt_thread.c |
+ */ |
+static void irt_start_thread() { |
+ struct nc_combined_tdb *tdb = get_irt_tdb(__nacl_read_tp()); |
+ |
+ /* |
+ * Fetch the user's start routine. |
+ */ |
+ void *(*user_start)(void *) = tdb->tdb.start_func; |
+ |
+ /* |
+ * Now do per-thread initialization for the IRT-private C library state. |
+ */ |
+ __newlib_thread_init(); |
+ |
+ /* |
+ * Finally, run the user code. |
+ */ |
+ (*user_start)(tdb->tdb.state); |
+ |
+ /* |
+ * That should never return. Crash hard if it does. |
+ */ |
+ __builtin_trap(); |
+} |
+ |
+/* |
+ * Creates a thread and initializes the IRT-private TLS area. |
+ * Based on code from src/untrusted/irt/irt_thread.c |
+ */ |
+int nacl_user_thread_create(void *(*start_func)(void *), void *stack, |
+ void *thread_ptr) { |
+ struct nc_combined_tdb *tdb; |
+ |
+ /* |
+ * Before we start the thread, allocate the IRT-private TLS area for it. |
+ */ |
+ size_t combined_size = __nacl_tls_combined_size(sizeof(*tdb)); |
+ void *combined_area = malloc(combined_size); |
+ if (combined_area == NULL) |
+ return EAGAIN; |
+ |
+ /* |
+ * Note that __nacl_tls_initialize_memory() is not reversible, |
+ * because it takes a pointer that need not be aligned and can |
+ * return a pointer that is aligned. In order to |
+ * free(combined_area) later, we must save the value of |
+ * combined_area. |
+ */ |
+ void *irt_tp = __nacl_tls_initialize_memory(combined_area, sizeof(*tdb)); |
+ tdb = get_irt_tdb(irt_tp); |
+ __nc_initialize_unjoinable_thread(tdb); |
+ tdb->tdb.irt_thread_data = combined_area; |
+ tdb->tdb.start_func = start_func; |
+ tdb->tdb.state = thread_ptr; |
+ |
+ return nacl_irt_thread_create(irt_start_thread, stack, irt_tp); |
+} |
+ |
+/* |
+ * Destroys a thread created by nacl_user_thread_create. |
+ * Based on code from src/untrusted/irt/irt_thread.c |
+ */ |
+void nacl_user_thread_exit(int32_t *stack_flag) { |
+ struct nc_combined_tdb *tdb = get_irt_tdb(__nacl_read_tp()); |
+ |
+ __nc_tsd_exit(); |
+ |
+ /* |
+ * Sanity check: Check that this function was not called on a thread |
+ * created by the IRT's internal pthread_create(). For such |
+ * threads, irt_thread_data == NULL. |
+ */ |
+ assert(tdb->tdb.irt_thread_data != NULL); |
+ |
+ free(tdb->tdb.irt_thread_data); |
+ |
+ nacl_irt_thread_exit(stack_flag); |
+} |
+ |
void __nc_initialize_interfaces(void) { |
const struct nacl_irt_thread init = { |
nacl_irt_thread_create, |