/*
    begintex.c -  MSC extented version of _beginthread()

    Copyright (C) 1997
	Rainer Schnitker, Heeper Str. 283, 33607 Bielefeld
	email: rainer@mathematik.uni-bielefeld.de

    All rights reserved
*/

#include <emx/syscalls.h>
#include <emx/thread.h>
#include <mscompat.h>

#define WIN32_LEAN_AND_MEAN
#include <wingnuc.h>
#include <windows.h>
#include <winerror.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#ifndef __MT__
#error Must define __MT__ for multithread library.
#endif

extern int __thread_init();
extern struct _thread __thread_1;
extern unsigned long __ThreadIndex;

typedef void (*cdecl_thread_func) (void *);
typedef unsigned long __stdcall (*stdcall_thread_func) (void *);

static DWORD WINAPI thread_start (void * param)
{
    struct _thread *tp = (struct _thread *) param;
    stdcall_thread_func tf;
    DWORD retval;

    TlsSetValue(__ThreadIndex, tp);   /* set thread local storage */

    tf = (stdcall_thread_func) tp->_th_start;

    retval = (*tf) (tp->_th_arg);

    _endthread();

    return retval;
}

unsigned long _beginthreadex(
    void *      security,
    unsigned    stack_size,
    unsigned __stdcall (*start) (void *),
    void *      arg_list,
    unsigned    init_flag,
    unsigned *  tid)
{
    struct _thread *tp;
    HANDLE hThread;

    if (!__thread_init()) {
	errno = ENOSYS;
        return FALSE;
    }

    tp = (struct _thread *) HeapAlloc(GetProcessHeap(),
		    HEAP_ZERO_MEMORY, sizeof(struct _thread));

    if (!tp) {
	errno = ENOMEM;
        return FALSE;
    }

    tp->_th_rand = 1;
    tp->_th_start = (cdecl_thread_func) start;
    tp->_th_arg = arg_list;

    hThread = CreateThread (security, stack_size, thread_start, (void *) tp,
                CREATE_SUSPENDED, (LPDWORD) &tid);

    if (hThread == 0) {
	errno = EINVAL;
        return FALSE;
    }

    if (__newthread (*tid) != 0) {       /* system call */
	TerminateThread(hThread, 0);
        return FALSE;
    }

    if (init_flag == CREATE_SUSPENDED && ResumeThread(hThread) == FALSE) {
	errno = ESRCH;
        return FALSE;
    }
    return (unsigned long) hThread;
}

void _endthreadex (unsigned retval)
{
    struct _thread *tp;

    if (!__thread_init())
	return;

    tp = _thread ();

    if (tp != & __thread_1) {               /* not main thread */
	HeapFree(GetProcessHeap(), 0, tp);
	__endthread (_gettid());	    /* system call */
        ExitThread(retval);
    }
    ExitProcess(retval);
}
