Blame gl/tests/windows-thread.c

Packit Service 991b93
/* Creating and controlling threads (native Windows implementation).
Packit Service 991b93
   Copyright (C) 2005-2020 Free Software Foundation, Inc.
Packit Service 991b93
Packit Service 991b93
   This program is free software; you can redistribute it and/or modify
Packit Service 991b93
   it under the terms of the GNU General Public License as published by
Packit Service 991b93
   the Free Software Foundation; either version 3, or (at your option)
Packit Service 991b93
   any later version.
Packit Service 991b93
Packit Service 991b93
   This program is distributed in the hope that it will be useful,
Packit Service 991b93
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 991b93
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 991b93
   GNU General Public License for more details.
Packit Service 991b93
Packit Service 991b93
   You should have received a copy of the GNU General Public License
Packit Service 991b93
   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
Packit Service 991b93
Packit Service 991b93
/* Written by Bruno Haible <bruno@clisp.org>, 2005.
Packit Service 991b93
   Based on GCC's gthr-win32.h.  */
Packit Service 991b93
Packit Service 991b93
#include <config.h>
Packit Service 991b93
Packit Service 991b93
/* Specification.  */
Packit Service 991b93
#include "windows-thread.h"
Packit Service 991b93
Packit Service 991b93
#include <errno.h>
Packit Service 991b93
#include <process.h>
Packit Service 991b93
#include <stdlib.h>
Packit Service 991b93
Packit Service 991b93
#include "windows-once.h"
Packit Service 991b93
#include "windows-tls.h"
Packit Service 991b93
Packit Service 991b93
/* The Thread-Local Storage (TLS) key that allows to access each thread's
Packit Service 991b93
   'struct glwthread_thread_struct *' pointer.  */
Packit Service 991b93
static DWORD self_key = (DWORD)-1;
Packit Service 991b93
Packit Service 991b93
/* Initializes self_key.  This function must only be called once.  */
Packit Service 991b93
static void
Packit Service 991b93
do_init_self_key (void)
Packit Service 991b93
{
Packit Service 991b93
  self_key = TlsAlloc ();
Packit Service 991b93
  /* If this fails, we're hosed.  */
Packit Service 991b93
  if (self_key == (DWORD)-1)
Packit Service 991b93
    abort ();
Packit Service 991b93
}
Packit Service 991b93
Packit Service 991b93
/* Initializes self_key.  */
Packit Service 991b93
static void
Packit Service 991b93
init_self_key (void)
Packit Service 991b93
{
Packit Service 991b93
  static glwthread_once_t once = GLWTHREAD_ONCE_INIT;
Packit Service 991b93
  glwthread_once (&once, do_init_self_key);
Packit Service 991b93
}
Packit Service 991b93
Packit Service 991b93
/* This structure contains information about a thread.
Packit Service 991b93
   It is stored in TLS under key self_key.  */
Packit Service 991b93
struct glwthread_thread_struct
Packit Service 991b93
{
Packit Service 991b93
  /* Fields for managing the handle.  */
Packit Service 991b93
  HANDLE volatile handle;
Packit Service 991b93
  CRITICAL_SECTION handle_lock;
Packit Service 991b93
  /* Fields for managing the exit value.  */
Packit Service 991b93
  BOOL volatile detached;
Packit Service 991b93
  void * volatile result;
Packit Service 991b93
  /* Fields for managing the thread start.  */
Packit Service 991b93
  void * (*func) (void *);
Packit Service 991b93
  void *arg;
Packit Service 991b93
};
Packit Service 991b93
Packit Service 991b93
/* Return a real HANDLE object for the current thread.  */
Packit Service 991b93
static HANDLE
Packit Service 991b93
get_current_thread_handle (void)
Packit Service 991b93
{
Packit Service 991b93
  HANDLE this_handle;
Packit Service 991b93
Packit Service 991b93
  /* GetCurrentThread() returns a pseudo-handle, i.e. only a symbolic
Packit Service 991b93
     identifier, not a real handle.  */
Packit Service 991b93
  if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
Packit Service 991b93
                        GetCurrentProcess (), &this_handle,
Packit Service 991b93
                        0, FALSE, DUPLICATE_SAME_ACCESS))
Packit Service 991b93
    abort ();
Packit Service 991b93
  return this_handle;
Packit Service 991b93
}
Packit Service 991b93
Packit Service 991b93
glwthread_thread_t
Packit Service 991b93
glwthread_thread_self (void)
Packit Service 991b93
{
Packit Service 991b93
  glwthread_thread_t thread;
Packit Service 991b93
Packit Service 991b93
  if (self_key == (DWORD)-1)
Packit Service 991b93
    init_self_key ();
Packit Service 991b93
  thread = TlsGetValue (self_key);
Packit Service 991b93
  if (thread == NULL)
Packit Service 991b93
    {
Packit Service 991b93
      /* This happens only in threads that have not been created through
Packit Service 991b93
         glthread_create(), such as the main thread.  */
Packit Service 991b93
      for (;;)
Packit Service 991b93
        {
Packit Service 991b93
          thread =
Packit Service 991b93
            (struct glwthread_thread_struct *)
Packit Service 991b93
            malloc (sizeof (struct glwthread_thread_struct));
Packit Service 991b93
          if (thread != NULL)
Packit Service 991b93
            break;
Packit Service 991b93
          /* Memory allocation failed.  There is not much we can do.  Have to
Packit Service 991b93
             busy-loop, waiting for the availability of memory.  */
Packit Service 991b93
          Sleep (1);
Packit Service 991b93
        }
Packit Service 991b93
Packit Service 991b93
      thread->handle = get_current_thread_handle ();
Packit Service 991b93
      InitializeCriticalSection (&thread->handle_lock);
Packit Service 991b93
      thread->detached = FALSE; /* This can lead to a memory leak.  */
Packit Service 991b93
      thread->result = NULL; /* just to be deterministic */
Packit Service 991b93
      TlsSetValue (self_key, thread);
Packit Service 991b93
    }
Packit Service 991b93
  return thread;
Packit Service 991b93
}
Packit Service 991b93
Packit Service 991b93
/* The main function of a freshly creating thread.  It's a wrapper around
Packit Service 991b93
   the FUNC and ARG arguments passed to glthread_create_func.  */
Packit Service 991b93
static unsigned int WINAPI
Packit Service 991b93
wrapper_func (void *varg)
Packit Service 991b93
{
Packit Service 991b93
  struct glwthread_thread_struct *thread =
Packit Service 991b93
    (struct glwthread_thread_struct *) varg;
Packit Service 991b93
Packit Service 991b93
  EnterCriticalSection (&thread->handle_lock);
Packit Service 991b93
  /* Create a new handle for the thread only if the parent thread did not yet
Packit Service 991b93
     fill in the handle.  */
Packit Service 991b93
  if (thread->handle == NULL)
Packit Service 991b93
    thread->handle = get_current_thread_handle ();
Packit Service 991b93
  LeaveCriticalSection (&thread->handle_lock);
Packit Service 991b93
Packit Service 991b93
  if (self_key == (DWORD)-1)
Packit Service 991b93
    init_self_key ();
Packit Service 991b93
  TlsSetValue (self_key, thread);
Packit Service 991b93
Packit Service 991b93
  /* Run the thread.  Store the exit value if the thread was not terminated
Packit Service 991b93
     otherwise.  */
Packit Service 991b93
  thread->result = thread->func (thread->arg);
Packit Service 991b93
Packit Service 991b93
  /* Process the TLS destructors.  */
Packit Service 991b93
  glwthread_tls_process_destructors ();
Packit Service 991b93
Packit Service 991b93
  if (thread->detached)
Packit Service 991b93
    {
Packit Service 991b93
      /* Clean up the thread, like thrd_join would do.  */
Packit Service 991b93
      DeleteCriticalSection (&thread->handle_lock);
Packit Service 991b93
      CloseHandle (thread->handle);
Packit Service 991b93
      free (thread);
Packit Service 991b93
    }
Packit Service 991b93
Packit Service 991b93
  return 0;
Packit Service 991b93
}
Packit Service 991b93
Packit Service 991b93
int
Packit Service 991b93
glwthread_thread_create (glwthread_thread_t *threadp, unsigned int attr,
Packit Service 991b93
                         void * (*func) (void *), void *arg)
Packit Service 991b93
{
Packit Service 991b93
  struct glwthread_thread_struct *thread =
Packit Service 991b93
    (struct glwthread_thread_struct *)
Packit Service 991b93
    malloc (sizeof (struct glwthread_thread_struct));
Packit Service 991b93
  if (thread == NULL)
Packit Service 991b93
    return ENOMEM;
Packit Service 991b93
  thread->handle = NULL;
Packit Service 991b93
  InitializeCriticalSection (&thread->handle_lock);
Packit Service 991b93
  thread->detached = (attr & GLWTHREAD_ATTR_DETACHED ? TRUE : FALSE);
Packit Service 991b93
  thread->result = NULL; /* just to be deterministic */
Packit Service 991b93
  thread->func = func;
Packit Service 991b93
  thread->arg = arg;
Packit Service 991b93
Packit Service 991b93
  {
Packit Service 991b93
    unsigned int thread_id;
Packit Service 991b93
    HANDLE thread_handle;
Packit Service 991b93
Packit Service 991b93
    thread_handle = (HANDLE)
Packit Service 991b93
      _beginthreadex (NULL, 100000, wrapper_func, thread, 0, &thread_id);
Packit Service 991b93
      /* calls CreateThread with the same arguments */
Packit Service 991b93
    if (thread_handle == NULL)
Packit Service 991b93
      {
Packit Service 991b93
        DeleteCriticalSection (&thread->handle_lock);
Packit Service 991b93
        free (thread);
Packit Service 991b93
        return EAGAIN;
Packit Service 991b93
      }
Packit Service 991b93
Packit Service 991b93
    EnterCriticalSection (&thread->handle_lock);
Packit Service 991b93
    if (thread->handle == NULL)
Packit Service 991b93
      thread->handle = thread_handle;
Packit Service 991b93
    else
Packit Service 991b93
      /* thread->handle was already set by the thread itself.  */
Packit Service 991b93
      CloseHandle (thread_handle);
Packit Service 991b93
    LeaveCriticalSection (&thread->handle_lock);
Packit Service 991b93
Packit Service 991b93
    *threadp = thread;
Packit Service 991b93
    return 0;
Packit Service 991b93
  }
Packit Service 991b93
}
Packit Service 991b93
Packit Service 991b93
int
Packit Service 991b93
glwthread_thread_join (glwthread_thread_t thread, void **retvalp)
Packit Service 991b93
{
Packit Service 991b93
  if (thread == NULL)
Packit Service 991b93
    return EINVAL;
Packit Service 991b93
Packit Service 991b93
  if (thread == glwthread_thread_self ())
Packit Service 991b93
    return EDEADLK;
Packit Service 991b93
Packit Service 991b93
  if (thread->detached)
Packit Service 991b93
    return EINVAL;
Packit Service 991b93
Packit Service 991b93
  if (WaitForSingleObject (thread->handle, INFINITE) == WAIT_FAILED)
Packit Service 991b93
    return EINVAL;
Packit Service 991b93
Packit Service 991b93
  if (retvalp != NULL)
Packit Service 991b93
    *retvalp = thread->result;
Packit Service 991b93
Packit Service 991b93
  DeleteCriticalSection (&thread->handle_lock);
Packit Service 991b93
  CloseHandle (thread->handle);
Packit Service 991b93
  free (thread);
Packit Service 991b93
Packit Service 991b93
  return 0;
Packit Service 991b93
}
Packit Service 991b93
Packit Service 991b93
int
Packit Service 991b93
glwthread_thread_detach (glwthread_thread_t thread)
Packit Service 991b93
{
Packit Service 991b93
  if (thread == NULL)
Packit Service 991b93
    return EINVAL;
Packit Service 991b93
Packit Service 991b93
  if (thread->detached)
Packit Service 991b93
    return EINVAL;
Packit Service 991b93
Packit Service 991b93
  thread->detached = TRUE;
Packit Service 991b93
  return 0;
Packit Service 991b93
}
Packit Service 991b93
Packit Service 991b93
int
Packit Service 991b93
glwthread_thread_exit (void *retval)
Packit Service 991b93
{
Packit Service 991b93
  glwthread_thread_t thread = glwthread_thread_self ();
Packit Service 991b93
  thread->result = retval;
Packit Service 991b93
  glwthread_tls_process_destructors ();
Packit Service 991b93
  _endthreadex (0); /* calls ExitThread (0) */
Packit Service 991b93
  abort ();
Packit Service 991b93
}