remove wine's broken _beginthread() and _endthread() and implement them properly
[reactos.git] / reactos / lib / crt / process / thread.c
index d058d72..2b86729 100644 (file)
 #include <precomp.h>
 
-#if 0
+void _endthread(void);
+
+static DWORD WINAPI
+_beginthread_start(PVOID lpParameter)
+{
+    PTHREADDATA ThreadData = (PTHREADDATA)lpParameter;
+
+    if (SetThreadData(ThreadData))
+    {
+        /* FIXME - wrap start_address in SEH! */
+        ThreadData->start_address(ThreadData->arglist);
+
+        _endthread();
+    }
+    else
+    {
+        /* couldn't set the thread data, free it before terminating */
+        free(ThreadData);
+    }
+
+    ExitThread(0);
+}
+
+
 /*
- * @unimplemented
+ * @implemented
+ *
+ * FIXME: the return type should be uintptr_t
  */
 unsigned long _beginthread(
     void (__cdecl *start_address)(void*),
     unsigned stack_size,
     void* arglist)
 {
-    __set_errno ( ENOSYS );
-    return (unsigned long)-1;
+    HANDLE hThread;
+    PTHREADDATA ThreadData;
+
+    if (start_address == NULL) {
+        __set_errno(EINVAL);
+        return (unsigned long)-1;
+    }
+
+    /* allocate the thread data structure already here instead of allocating the
+       thread data structure in the thread itself. this way we can pass an error
+       code to the caller in case we don't have sufficient resources */
+    ThreadData = malloc(sizeof(THREADDATA));
+    if (ThreadData == NULL)
+    {
+        __set_errno(EAGAIN);
+        return (unsigned long)-1;
+    }
+
+    ThreadData->start_address = start_address;
+    ThreadData->arglist = arglist;
+
+    hThread = CreateThread(NULL,
+                           stack_size,
+                           _beginthread_start,
+                           ThreadData,
+                           CREATE_SUSPENDED,
+                           NULL);
+    if (hThread == NULL)
+    {
+        free(ThreadData);
+        __set_errno(EAGAIN);
+        return (unsigned long)-1;
+    }
+
+    ThreadData->hThread = hThread;
+
+    if (ResumeThread(hThread) == (DWORD)-1)
+    {
+        CloseHandle(hThread);
+
+        /* freeing the ThreadData _could_ cause a crash, but only in case someone
+           else resumed the thread and it got to free the context before we actually
+           get here, but that's _very_ unlikely! */
+        free(ThreadData);
+        __set_errno(EAGAIN);
+        return (unsigned long)-1;
+    }
+
+    return (unsigned long)hThread;
 }
-#endif
+
 /*
- * @unimplemented
+ * @implemented
  */
 void _endthread(void)
 {
-}
+    PTHREADDATA ThreadData = GetThreadData();
+
+    /* close the thread handle */
+    CloseHandle(ThreadData->hThread);
 
-/* EOF */
+    /* NOTE: the thread data will be freed in the thread detach routine that will
+             call FreeThreadData */
+
+    ExitThread(0);
+}