+#endif
+}
+
+static gpointer thread_attach(gsize *tid)
+{
+ struct _WapiHandle_thread thread_handle = {0}, *thread_handle_p;
+ gpointer handle;
+ gboolean ok;
+ int ret;
+ int thr_ret;
+ int i, unrefs = 0;
+ gpointer ta_ret = NULL;
+
+ mono_once (&thread_hash_once, thread_hash_init);
+ mono_once (&thread_ops_once, thread_ops_init);
+
+ thread_handle.state = THREAD_STATE_START;
+ thread_handle.owner_pid = getpid ();
+ thread_handle.owned_mutexes = g_ptr_array_new ();
+
+ handle = _wapi_handle_new (WAPI_HANDLE_THREAD, &thread_handle);
+ if (handle == _WAPI_HANDLE_INVALID) {
+ g_warning ("%s: error creating thread handle", __func__);
+
+ SetLastError (ERROR_GEN_FAILURE);
+ return (NULL);
+ }
+
+ pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
+ handle);
+ thr_ret = _wapi_handle_lock_handle (handle);
+ g_assert (thr_ret == 0);
+
+ ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
+ (gpointer *)&thread_handle_p);
+ if (ok == FALSE) {
+ g_warning ("%s: error looking up thread handle %p", __func__,
+ handle);
+
+ SetLastError (ERROR_GEN_FAILURE);
+ goto cleanup;
+ }
+
+ /* Hold a reference while the thread is active, because we use
+ * the handle to store thread exit information
+ */
+ _wapi_handle_ref (handle);
+
+ /* Lock around the thread create, so that the new thread cant
+ * race us to look up the thread handle in GetCurrentThread()
+ */
+ pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
+ (void *)&thread_hash_mutex);
+ thr_ret = mono_mutex_lock(&thread_hash_mutex);
+ g_assert (thr_ret == 0);
+
+ ret = _wapi_timed_thread_attach (&thread_handle_p->thread, thread_exit,
+ handle);
+ if (ret != 0) {
+#ifdef DEBUG
+ g_message ("%s: Thread attach error: %s", __func__,
+ strerror(ret));
+#endif
+
+ /* Two, because of the reference we took above */
+ unrefs = 2;
+
+ goto thread_hash_cleanup;
+ }
+ ta_ret = handle;
+
+ g_hash_table_insert (thread_hash,
+ (gpointer)(thread_handle_p->thread->id),
+ handle);
+
+#ifdef DEBUG
+ g_message("%s: Attached thread handle %p thread %p ID %ld", __func__,
+ handle, thread_handle_p->thread,
+ thread_handle_p->thread->id);
+#endif
+
+ if (tid != NULL) {
+#ifdef PTHREAD_POINTER_ID
+ /* Don't use GPOINTER_TO_UINT here, it can't cope with
+ * sizeof(void *) > sizeof(uint) when a cast to uint
+ * would overflow
+ */
+ *tid = (gsize)(thread_handle_p->thread->id);
+#else
+ *tid = thread_handle_p->thread->id;
+#endif
+ }
+
+thread_hash_cleanup:
+ thr_ret = mono_mutex_unlock (&thread_hash_mutex);
+ g_assert (thr_ret == 0);
+ pthread_cleanup_pop (0);
+
+cleanup:
+ thr_ret = _wapi_handle_unlock_handle (handle);
+ g_assert (thr_ret == 0);
+ pthread_cleanup_pop (0);
+
+ /* Must not call _wapi_handle_unref() with the handle already
+ * locked
+ */
+ for (i = 0; i < unrefs; i++) {
+ _wapi_handle_unref (handle);
+ }
+
+ return(ta_ret);