/* beginth.c (emx+gcc) -- Copyright (c) 1992-1993 by Eberhard Mattes */

#if defined (__MT__)

#include <sys/emx.h>
#include <stdlib.h>
#include <errno.h>
#define INCL_DOSPROCESS
#define INCL_DOSERRORS
#define INCL_DOSEXCEPTIONS
#include <os2emx.h>

#define MAX_THREADS 1024

static struct _thread thread_1 =
{
  0,                            /* _th_errno */
  NULL,                         /* _th_arg */
  NULL,                         /* _th_start */
  NULL,                         /* _th_strtok_ptr (must be NULL) */
  {0},                          /* _th_asctime_buf */
  {0},                          /* _th_tmpnam_buf */
  {0},                          /* _th_gmtime_buf */
  1,                            /* _th_rand */
  NULL                          /* _th_store */
};

struct _thread *_thread_tab[MAX_THREADS+1] = {NULL, &thread_1};


static void start_thread (struct _thread *tp)
{
  EXCEPTIONREGISTRATIONRECORD reg;

  __initthread (&reg);
  tp->_th_rand = 1;             /* Initialize rand() */
  tp->_th_store = NULL;         /* Initialize pointer for _threadstore() */
  tp->_th_start (tp->_th_arg);
  _endthread();
}


int _beginthread (void (*start)(void *arg), void *stack, unsigned stack_size,
                  void *arg_list)
{
  ULONG rc;
  TID tid;
  struct _thread *tp;

  rc = DosAllocMem ((PPVOID)&tp, sizeof (struct _thread),
                    PAG_COMMIT|PAG_READ|PAG_WRITE);
  if (rc != 0)
    {
      errno = ENOMEM;
      return (-1);
    }
  tp->_th_start = start;
  tp->_th_arg = arg_list;
  rc = DosCreateThread (&tid, (PFNTHREAD)start_thread, (ULONG)tp,
                        3, stack_size);
  if (rc != 0)
    {
      if (rc == ERROR_NOT_ENOUGH_MEMORY)
        errno = ENOMEM;
      else if (rc == ERROR_MAX_THRDS_REACHED)
        errno = EAGAIN;
      else
        errno = EINVAL;
      return (-1);
    }
  if (tid > MAX_THREADS)
    {
      DosKillThread (tid);
      errno = EAGAIN;
      return (-1);
    }
  if (__newthread (tid) != 0)
    {
      DosKillThread (tid);
      return (-1);
    }
  _thread_tab[tid] = tp;
  rc = DosResumeThread (tid);
  if (rc != 0)
    {
      errno = ESRCH;
      return (-1);
    }
  return (tid);
}


void _endthread (void)
{
  struct _thread *tp;
  int tid;

  tid = _tid ();
  tp = _thread ();
  if (tp != &thread_1)
    DosFreeMem (tp);
  _thread_tab[tid] = NULL;
  __endthread (tid);
  for (;;)
    DosExit ((tid == 1 ? EXIT_PROCESS : EXIT_THREAD), 0);
}

#endif
