static void *
_thread_boot (void *arg)
{
  thread_t *thr = (thread_t *) arg;
  int rc;

  rc = pthread_setspecific (_key_current, thr);
  CKRET (rc);

  /* Store the context so we can easily restart a dead thread */
  setjmp (thr->thr_init_context);

  thr->thr_status = RUNNING;
  _thread_init_attributes (thr);
  thr->thr_stack_base = (void *) &arg;

  rc = (*thr->thr_initial_function) (thr->thr_initial_argument);

  /* thread died, put it on the dead queue */
  thread_exit (rc);

  /* We should never come here */
  GPF_T;

failed:
  return (void *) 1L;
}
thread_t *
thread_create (
    thread_init_func initial_function,
    unsigned long stack_size,
    void *init_arg)
{
  thread_t *thr;

  assert (_main_thread != NULL);

  if (stack_size == 0)
    stack_size = THREAD_STACK_SIZE;

#if (SIZEOF_VOID_P == 8)
  stack_size *= 2;
#endif
#if defined (__x86_64 ) && defined (SOLARIS)
  /*GK: the LDAP on that platform requires that */
  stack_size *= 2;
#endif

  /* Any free threads with the right stack size? */
  for (thr = (thread_t *) _deadq.thq_head.thr_next;
       thr != (thread_t *) &_deadq.thq_head;
       thr = (thread_t *) thr->thr_hdr.thr_next)
    {
      if (thr->thr_stack_size >= stack_size)
	break;
    }

  if (thr == (thread_t *) &_deadq.thq_head)
    {
      /* No free fiber, create a new one */
      thr = thread_allocate ();
      _fiber_for_thread (thr, stack_size);
      _thread_num_total++;
    }
  else
    {
      /* Set new context for the thread */
      memcpy (thr->thr_context, thr->thr_init_context, sizeof (jmp_buf));
    }

  thr->thr_initial_function = initial_function;
  thr->thr_initial_argument = init_arg;
  thread_set_priority (thr, NORMAL_PRIORITY);
  _thread_init_attributes (thr);
  _fiber_status (thr, RUNNABLE);

  return thr;
}
/*
 *  The main thread must call this function to convert itself into a thread.
 */
thread_t *
thread_initial (unsigned long stack_size)
{
  if (_main_thread)
    return _main_thread;
  else
    {
      NEW_VARZ (thread_t, thr);
      _main_thread = thr;
      thr->thr_status = RUNNING;
      thr->thr_sem = semaphore_allocate (0);
      thr->thr_schedule_sem = semaphore_allocate (0);
      _thread_init_attributes (thr);
      thread_set_priority (thr, NORMAL_PRIORITY);
      return thr;
    }
}
/*
 *  The main thread must call this function to convert itself into a fiber.
 */
thread_t *
thread_initial (unsigned long stack_size)
{
  static unsigned int marker = THREAD_STACK_MARKER;

  if (_current_fiber)
    return _current_fiber;
  else
    {
      NEW_VARZ (thread_t, thr);

      assert (_current_fiber == NULL);
      _main_thread = _current_fiber = thr;

      _sched_init ();

      if (stack_size == 0)
	stack_size = MAIN_STACK_SIZE;

#if (SIZEOF_VOID_P == 8)
      stack_size *= 2;
#endif
#if defined (__x86_64 ) && defined (SOLARIS)
  /*GK: the LDAP on that platform requires that */
  stack_size *= 2;
#endif

      thr->thr_stack_marker = ▮
      thr->thr_sem = semaphore_allocate (0);
      thr->thr_schedule_sem = semaphore_allocate (0);
      thread_set_priority (thr, NORMAL_PRIORITY);
      _thread_init_attributes (thr);
      _fiber_for_thread (thr, stack_size);

      _fiber_status (thr, RUNNING);

      return thr;
    }
}
thread_t *
thread_attach (void)
{
  thread_t *thr;
  int rc;

  thr = thread_alloc ();
  thr->thr_stack_size = (unsigned long) -1;
  thr->thr_attached = 1;
  if (thr->thr_cv == NULL)
    goto failed;

  *((pthread_t *) thr->thr_handle) = pthread_self ();

  rc = pthread_setspecific (_key_current, thr);
  CKRET (rc);

  /* Store the context so we can easily restart a dead thread */
  setjmp (thr->thr_init_context);

  thr->thr_status = RUNNING;
  _thread_init_attributes (thr);
  thr->thr_stack_base = 0;

  return thr;

failed:
  if (thr->thr_sem)
    semaphore_free (thr->thr_sem);
  if (thr->thr_schedule_sem)
    semaphore_free (thr->thr_schedule_sem);
  if (thr->thr_handle)
    dk_free (thr->thr_handle, sizeof (pthread_t));
  dk_free (thr, sizeof (thread_t));
  return NULL;
}
/*
 *  The main thread must call this function to convert itself into a thread.
 */
thread_t *
thread_initial (unsigned long stack_size)
{
  int rc;
  thread_t *thr = NULL;

  if (_main_thread)
    return _main_thread;

  /*
   *  Initialize pthread key
   */
#ifndef OLD_PTHREADS
  rc = pthread_key_create (&_key_current, NULL);
#else
  rc = pthread_keycreate (&_key_current, NULL);
#endif
  CKRET (rc);

  /*
   *  Start off with a value of NULL
   */
  rc = pthread_setspecific (_key_current, NULL);
  CKRET (rc);

  /*
   *  Initialize default thread/mutex attributes
   */
#ifndef OLD_PTHREADS
  /* attribute for thread creation */
  rc = pthread_attr_init (&_thread_attr);
  CKRET (rc);

  /* attribute for mutex creation */
  rc = pthread_mutexattr_init (&_mutex_attr);
  CKRET (rc);
#else
  rc = pthread_attr_create (&_thread_attr);
  CKRET (rc);

  rc = pthread_mutexattr_create (&_mutex_attr);
  CKRET (rc);
#endif

#if defined (PTHREAD_PROCESS_PRIVATE) && !defined(oldlinux) && !defined(__FreeBSD__)
  rc = pthread_mutexattr_setpshared (&_mutex_attr, PTHREAD_PROCESS_PRIVATE);
  CKRET (rc);
#endif

#if defined (MUTEX_FAST_NP) && !defined (_AIX)
  rc = pthread_mutexattr_setkind_np (&_mutex_attr, MUTEX_FAST_NP);
  CKRET (rc);
#endif

#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
  rc = pthread_mutexattr_settype (&_mutex_attr, PTHREAD_MUTEX_ADAPTIVE_NP);
  CKRET (rc);
#endif

  /*
   *  Allocate a thread structure
   */
  thr = (thread_t *) dk_alloc (sizeof (thread_t));
  memset (thr, 0, sizeof (thread_t));

  assert (_main_thread == NULL);
  _main_thread = thr;

  _sched_init ();

  if (stack_size == 0)
    stack_size = MAIN_STACK_SIZE;

#if (SIZEOF_VOID_P == 8)
  stack_size *= 2;
#endif
#if defined (__x86_64 ) && defined (SOLARIS)
  /*GK: the LDAP on that platform requires that */
  stack_size *= 2;
#endif


  stack_size = ((stack_size / 8192) + 1) * 8192;

  thr->thr_stack_size = stack_size;
  thr->thr_status = RUNNING;
  thr->thr_cv = _alloc_cv ();
  thr->thr_sem = semaphore_allocate (0);
  thr->thr_schedule_sem = semaphore_allocate (0);
  if (thr->thr_cv == NULL)
    goto failed;
  _thread_init_attributes (thr);
  thread_set_priority (thr, NORMAL_PRIORITY);

  rc = pthread_setspecific (_key_current, thr);
  CKRET (rc);

  return thr;

failed:
  if (thr)
    {
      _thread_free_attributes (thr);
      dk_free (thr, sizeof (thread_t));
    }
  return NULL;
}