gthread-win32.c



Hi Sebastian et. al.,
your recent mail reminded me on something I forgot about a year ago.

At 14:07 10.05.01 +0200, Sebastian Wilhelmi wrote:
>Trying to remember the Be patches, I saw some time ago (BTW what happened to
>them), they seem to have no native static mutex, also Windows doesn't have it
>(at least on 9x IIRC), but we still have no native implementation there
>anyway.
>

Attached the first native gthread implementation for win32. It is mainly
plain mapping of one API to another, although in some cases I'm unsure
if it maps The Right Thing. Maybe I should have read a posix-thread-book :)

Anyway, the three runtime tests I'm aware of are passed with the following
result:

D:\devel\my-gtk\glib\tests>mainloop-test
Timeout run 2947 times
Timeout run 2952 times
Timeout run 2947 times
Timeout run 2950 times

GLib-CRITICAL **: file grand.c: line 224: assertion `end > begin' failed

D:\devel\my-gtk\glib\tests>thread-test
[there is no output]

D:\devel\my-gtk\glib\tests>threadpool-test
[again no output]

Does someone with more thread understanding than me have the time 
to take a look through the source and point out open issues ?

Thanks in advance,
	Hans
/* GLIB - Library of useful routines for C programming
 * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * gthread.c: solaris thread system implementation
 * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
 * Copyright 2000 Hans Breuer
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
 * file for a list of people on the GLib Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GLib at ftp://ftp.gtk.org/pub/gtk/. 
 */

/* 
 * MT safe
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <glib.h>
#define STRICT
#include <windows.h>

#define win32_print_error( name, num )				\
  g_error( "file %s: line %d (%s): error %s during %s",			\
           __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION,			\
           g_strerror((num)), #name )

#define win32_check_for_error( what ) G_STMT_START{			\
  int error = (what);							\
  if( error ) { win32_print_error( what, error ); }			\
  }G_STMT_END

gulong g_thread_min_stack_size = 0;

#define G_MUTEX_SIZE (sizeof (HANDLE))

#define PRIORITY_LOW_VALUE 0
#define PRIORITY_URGENT_VALUE 127

static GMutex *
g_mutex_new_win32_impl (void)
{
  HANDLE *result = g_new (HANDLE, 1);
  *result = CreateMutex (NULL, /* pointer to security attributes */
                         TRUE, /* ??? flag for initial ownership */ 
                         NULL); /* pointer to mutex-object name */
  win32_check_for_error (NULL != *result);
  return (GMutex *) result;
}

static void
g_mutex_free_win32_impl (GMutex * mutex)
{
  win32_check_for_error (
    CloseHandle (*(HANDLE*)mutex)
    );
  free (mutex);
}

/* NOTE: the functions g_mutex_lock and g_mutex_unlock may not use
   functions from gmem.c and gmessages.c; */

static void
g_mutex_lock_win32_impl (GMutex *mutex)
{
  win32_check_for_error (
    WAIT_FAILED != WaitForSingleObject (*(HANDLE*)mutex, INFINITE)
    );
}

static void
g_mutex_unlock_win32_impl (GMutex *mutex)
{
  win32_check_for_error (
    ReleaseMutex (*(HANDLE*)mutex)
    );
}

static gboolean
g_mutex_trylock_win32_impl (GMutex * mutex)
{
  DWORD result;
  result = WaitForSingleObject (*(HANDLE*)mutex, 0);
  if (result == WAIT_OBJECT_0)
    return TRUE;
  win32_check_for_error (WAIT_TIMEOUT != result);
  return FALSE;
}

static GCond *
g_cond_new_win32_impl (void)
{
  HANDLE *result = g_new (HANDLE, 1);
  *result = CreateEvent (NULL,  /* default security, can't inherit */
                         FALSE, /* auto-reset */
                         FALSE, /* initially nonsignaled */
                         NULL); /* no name */

  win32_check_for_error (NULL != *result);
  return (GCond *) result;
}

static void
g_cond_signal_win32_impl (GCond * cond)
{
  win32_check_for_error (SetEvent (*(HANDLE*)cond));
}

static void
g_cond_broadcast_win32_impl (GCond * cond)
{
  /* XXX : signal all waiters ? */
}

static void     
g_cond_wait_win32_impl (GCond *cond,
			     GMutex *mutex)
{
  /* XXX : what's the mutex for ? */
  win32_check_for_error (
    WaitForSingleObject (*(HANDLE*)cond, INFINITE));
}

#define G_NSEC_PER_SEC 1000000000

static gboolean
g_cond_timed_wait_win32_impl (GCond * cond, 
				GMutex * entered_mutex,
				GTimeVal * abs_time)
{
  int result;
  gboolean timed_out;

  g_return_val_if_fail (cond != NULL, FALSE);
  g_return_val_if_fail (entered_mutex != NULL, FALSE);

  /* XXX : what's the mutex for ? */
  if (!abs_time)
    {
      g_cond_wait (cond, entered_mutex);
      return TRUE;
    }

  result = WaitForSingleObject (*(HANDLE*)cond,
                                abs_time->tv_sec * 1000 + abs_time->tv_usec / 1000);
  timed_out = (result == WAIT_TIMEOUT);
  if (!timed_out)
    win32_check_for_error (result);
  return !timed_out;
}

static void
g_cond_free_win32_impl (GCond * cond)
{
  win32_check_for_error (CloseHandle (*(HANDLE*) cond));
  g_free (cond);
}

static GPrivate *
g_private_new_win32_impl (GDestroyNotify destructor)
{
  DWORD *result = g_new (DWORD,1);
  *result = TlsAlloc ();
  win32_check_for_error (0xFFFFFFFF != *result);
  return (GPrivate *) result;
}

/* NOTE: the functions g_private_get and g_private_set may not use
   functions from gmem.c and gmessages.c */

static void
g_private_set_win32_impl (GPrivate * private_key, gpointer value)
{
  if (!private_key)
    return;

  win32_check_for_error (
    TlsSetValue (*(DWORD*)private_key, value)
    );
}

static gpointer
g_private_get_win32_impl (GPrivate * private_key)
{
  if (!private_key)
    return NULL;

  return TlsGetValue (*(DWORD*)private_key);
}

static void
g_thread_set_priority_win32_impl (gpointer thread, GThreadPriority priority)
{
  win32_check_for_error (SetThreadPriority (*(HANDLE*)thread,  
					/* XXX: g_thread_priority_map [priority] */ priority));
}

/* map the thead func signature */
typedef struct _Win32ThreadCreateData Win32ThreadCreateData;
struct _Win32ThreadCreateData
{
  GThreadFunc func;
  gpointer data;
};

DWORD WINAPI
ThreadFunc (LPVOID pVoid)
{
  Win32ThreadCreateData *create_data = (Win32ThreadCreateData *)pVoid;

  create_data->func (create_data->data);

  g_free (pVoid);
  return 0;
}

static void
g_thread_create_win32_impl (GThreadFunc thread_func, 
			      gpointer arg, 
			      gulong stack_size,
			      gboolean joinable,
			      gboolean bound,
			      GThreadPriority priority,
			      gpointer thread,
			      GError **error)
{     
  HANDLE hThread;
  DWORD  dwThreadId;
  DWORD flags = (joinable ? 0 : CREATE_SUSPENDED); /* XXX: | (bound ? 0: THR_BOUND); */
  Win32ThreadCreateData *create_data = g_new(Win32ThreadCreateData, 1);
  create_data->func = thread_func;
  create_data->data = arg;
  
  g_return_if_fail (thread_func);
  g_return_if_fail (priority >= G_THREAD_PRIORITY_LOW);
  g_return_if_fail (priority <= G_THREAD_PRIORITY_URGENT);
  
  stack_size = MAX (g_thread_min_stack_size, stack_size);
  
  hThread = CreateThread (NULL, /* security attibs inherited */
                          stack_size,
                          &ThreadFunc,
                          create_data,
                          flags,  /* XXX : ??? */
                          &dwThreadId);

  if (NULL == hThread)
    {
      g_set_error (error, G_THREAD_ERROR, G_THREAD_ERROR_AGAIN, 
		   "Error creating thread: %d", GetLastError());
      return;
    }
  *(HANDLE*)thread = hThread;

  g_thread_set_priority_win32_impl (thread, priority);
}

static void 
g_thread_yield_win32_impl (void)
{
  Sleep(0);
}

static void
g_thread_join_win32_impl (gpointer thread)
{
  /* XXX: what is it ??? */
  win32_check_for_error (0xFFFFFFFF != ResumeThread (*(HANDLE*)thread));
}

static void 
g_thread_exit_win32_impl (void) 
{
  ExitThread (0);
}

static void
g_thread_self_win32_impl (gpointer thread)
{
  /*
   * XXX: not sure if this should return the unique thread identifier
   * from GetCurrentThreadId () instead
   */

  /*
   * a 'pseudo' handle, not the one returned by create_thread.
   * It could be the real handle, if we provide id->handle mapping
   * _or_ change GLIB_SIZEOF_SYSTEM_THREAD to store both in create_thread
   */
  *(HANDLE*)thread = GetCurrentThread();
}

static GThreadFunctions g_thread_functions_for_glib_use_default =
{
  g_mutex_new_win32_impl,           /* mutex */
  g_mutex_lock_win32_impl,
  g_mutex_trylock_win32_impl,
  g_mutex_unlock_win32_impl,
  g_mutex_free_win32_impl,
  g_cond_new_win32_impl,            /* condition */
  g_cond_signal_win32_impl,
  g_cond_broadcast_win32_impl,
  g_cond_wait_win32_impl,
  g_cond_timed_wait_win32_impl,
  g_cond_free_win32_impl,
  g_private_new_win32_impl,         /* private thread data */
  g_private_get_win32_impl,
  g_private_set_win32_impl,
  g_thread_create_win32_impl,       /* thread */
  g_thread_yield_win32_impl,
  g_thread_join_win32_impl,
  g_thread_exit_win32_impl,
  g_thread_set_priority_win32_impl,
  g_thread_self_win32_impl
};
-------- Hans "at" Breuer "dot" Org -----------
Tell me what you need, and I'll tell you how to 
get along without it.                -- Dilbert


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]