New files from last commit of thread-safety stuff.

This commit is contained in:
Owen Taylor
1998-12-09 00:19:06 +00:00
parent 7bb4602aa1
commit 7a79b53f61
7 changed files with 571 additions and 0 deletions

144
gmutex.c Normal file
View File

@@ -0,0 +1,144 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* gmutex.c:
* Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
/*
* MT safe
*/
#include "glib.h"
typedef struct _GStaticPrivateNode GStaticPrivateNode;
struct _GStaticPrivateNode {
gpointer data;
GDestroyNotify destroy;
};
static void g_static_private_free_data (gpointer data);
/* Global variables */
gboolean g_thread_use_default_impl = TRUE;
gboolean g_thread_supported = FALSE;
GThreadFunctions g_thread_functions_for_glib_use; /* is NULLified as default */
/* Local data */
static GMutex *g_mutex_protect_static_mutex_allocation = NULL;
static GMutex *g_thread_specific_mutex = NULL;
static GPrivate *g_thread_specific_private = NULL;
/* This must be called only once, before any threads are created.
* It will only be called from g_thread_init() in -lgthread.
*/
void
g_mutex_init (void)
{
g_mutex_protect_static_mutex_allocation = g_mutex_new();
g_thread_specific_mutex = g_mutex_new();
g_thread_specific_private = g_private_new (g_static_private_free_data);
}
GMutex *
g_static_mutex_get_mutex_impl (GMutex** mutex)
{
if (!g_thread_supported)
return NULL;
g_assert (g_mutex_protect_static_mutex_allocation);
g_mutex_lock (g_mutex_protect_static_mutex_allocation);
if (!(*mutex))
*mutex = g_mutex_new();
g_mutex_unlock (g_mutex_protect_static_mutex_allocation);
return *mutex;
}
gpointer
g_static_private_get (GStaticPrivate *private)
{
GArray *array;
array = g_private_get (g_thread_specific_private);
if (!array)
return NULL;
if (!private->index)
return NULL;
else if (private->index <= array->len)
return g_array_index (array, GStaticPrivateNode, (private->index - 1)).data;
else
return NULL;
}
void
g_static_private_set (GStaticPrivate *private,
gpointer data,
GDestroyNotify notify)
{
GArray *array;
static guint next_index = 0;
array = g_private_get (g_thread_specific_private);
if (!array)
{
array = g_array_new (FALSE, FALSE, sizeof(GStaticPrivateNode));
g_private_set (g_thread_specific_private, array);
}
if (!private->index)
{
g_mutex_lock (g_thread_specific_mutex);
if (!private->index)
private->index = ++next_index;
g_mutex_unlock (g_thread_specific_mutex);
}
if (private->index > array->len)
g_array_set_size (array, private->index);
g_array_index (array, GStaticPrivateNode, (private->index - 1)).data = data;
g_array_index (array, GStaticPrivateNode, (private->index - 1)).destroy = notify;
}
static void
g_static_private_free_data (gpointer data)
{
if (data)
{
GArray* array = data;
guint i;
for (i = 0; i < array->len; i++ )
{
GStaticPrivateNode *node = &g_array_index (array, GStaticPrivateNode, i);
if (node->data && node->destroy)
node->destroy (node->data);
}
}
}

21
gthread/Makefile.am Normal file
View File

@@ -0,0 +1,21 @@
## Process this file with automake to produce Makefile.in
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/gthread -DG_LOG_DOMAIN=g_log_domain_gthread
EXTRA_DIST = \
gthread-posix.c
libglib = $(top_builddir)/libglib.la # -lglib
lib_LTLIBRARIES = libgthread.la
libgthread_la_SOURCES = gthread.c
libgthread_la_LDFLAGS = \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
-release $(LT_RELEASE)
libgthread_la_LIBADD = \
@G_THREAD_LIBS@
noinst_PROGRAMS = testgthread
testgthread_LDADD = ../libglib.la libgthread.la

2
gthread/gthread-none.c Normal file
View File

@@ -0,0 +1,2 @@
static GThreadFunctions
g_mutex_functions_for_glib_use_default; /* is NULLified */

152
gthread/gthread-posix.c Normal file
View File

@@ -0,0 +1,152 @@
#include <pthread.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/time.h>
#define posix_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 posix_check_for_error( what ) G_STMT_START{ \
int error = (what); \
if( error ) { posix_print_error( what, error ); } \
}G_STMT_END
static GMutex*
g_mutex_new_posix_impl (void)
{
/* we can not use g_new and friends, as they might use mutexes by
themself */
GMutex* result = malloc(sizeof(pthread_mutex_t));
posix_check_for_error( pthread_mutex_init( (pthread_mutex_t*)result,
NULL ) );
return result;
}
static void
g_mutex_free_posix_impl (GMutex* mutex)
{
posix_check_for_error( pthread_mutex_destroy((pthread_mutex_t*)mutex) );
free (mutex);
}
/* pthread_mutex_lock, pthread_mutex_unlock can be taken directly, as
signature and semantic are right, but without error check then!!!!,
we might want to change this therfore. */
static gboolean
g_mutex_try_lock_posix_impl (GMutex* mutex)
{
int result;
result = pthread_mutex_trylock((pthread_mutex_t*)mutex);
if( result == EBUSY )
{
return FALSE;
}
posix_check_for_error( result );
return TRUE;
}
static GCond*
g_cond_new_posix_impl (void)
{
GCond* result = (GCond*) g_new0 (pthread_cond_t, 1);
posix_check_for_error( pthread_cond_init( (pthread_cond_t*)result, NULL ) );
return result;
}
/* pthread_cond_signal, pthread_cond_broadcast and pthread_cond_wait
can be taken directly, as signature and semantic are right, but
without error check then!!!!, we might want to change this
therfore. */
#define G_MICROSEC 1000000
#define G_NANOSEC 1000000000
static gboolean
g_cond_timed_wait_posix_impl (GCond* cond,
GMutex* entered_mutex,
GTimeVal* abs_time)
{
int result;
struct timespec end_time;
gboolean timed_out;
g_return_val_if_fail (cond != NULL, FALSE);
g_return_val_if_fail (entered_mutex != NULL, FALSE);
if (!abs_time)
{
g_cond_wait(cond, entered_mutex);
return TRUE;
}
end_time.tv_sec = abs_time->tv_sec;
end_time.tv_nsec = abs_time->tv_usec * (G_NANOSEC / G_MICROSEC);
g_assert (end_time.tv_nsec < G_NANOSEC);
result = pthread_cond_timedwait ((pthread_cond_t*)cond,
(pthread_mutex_t*)entered_mutex,
&end_time);
timed_out = ( result == ETIMEDOUT );
if (!timed_out)
posix_check_for_error (result);
return !timed_out;
}
static void
g_cond_free_posix_impl(GCond* cond)
{
posix_check_for_error (pthread_cond_destroy((pthread_cond_t*)cond));
g_free (cond);
}
static GPrivate*
g_private_new_posix_impl(GDestroyNotify destructor)
{
/* we can not use g_new and friends, as they might use mutexes by
themself */
GPrivate* result = malloc( sizeof(pthread_key_t) );
/* FIXME: we shouldn't use g_log here actually */
posix_check_for_error( pthread_key_create( (pthread_key_t*)result,
destructor) );
return result;
}
void
g_private_set_posix_impl(GPrivate* private, gpointer value)
{
g_return_if_fail (private != NULL);
/* FIXME: we shouldn't use g_log here actually */
posix_check_for_error( pthread_setspecific(*(pthread_key_t*)private,
value) );
}
gpointer
g_private_get_posix_impl(GPrivate* private)
{
g_return_val_if_fail (private != NULL, NULL);
/* FIXME: we shouldn't use g_log here actually */
return pthread_getspecific(*(pthread_key_t*)private );
}
static GThreadFunctions
g_thread_functions_for_glib_use_default = {
g_mutex_new_posix_impl,
(void(*)(GMutex*))pthread_mutex_lock,
g_mutex_try_lock_posix_impl,
(void(*)(GMutex*))pthread_mutex_unlock,
g_mutex_free_posix_impl,
g_cond_new_posix_impl,
(void(*)(GCond*))pthread_cond_signal,
(void(*)(GCond*))pthread_cond_broadcast,
(void(*)(GCond*,GMutex*))pthread_cond_wait,
g_cond_timed_wait_posix_impl,
g_cond_free_posix_impl,
g_private_new_posix_impl,
g_private_get_posix_impl,
g_private_set_posix_impl
};

147
gthread/gthread-solaris.c Normal file
View File

@@ -0,0 +1,147 @@
#include <thread.h>
#include <errno.h>
#include <stdlib.h>
#define solaris_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 solaris_check_for_error( what ) G_STMT_START{ \
int error = (what); \
if( error ) { solaris_print_error( what, error ); } \
}G_STMT_END
static GMutex*
g_mutex_new_solaris_impl()
{
/* we can not use g_new and friends, as they might use mutexes by
themself */
GMutex* result = malloc(sizeof(mutex_t));
solaris_check_for_error( mutex_init( (mutex_t*) result, USYNC_PROCESS, 0));
return result;
}
static void
g_mutex_free_solaris_impl(GMutex* mutex)
{
solaris_check_for_error( mutex_destroy((mutex_t*)mutex) );
free (mutex);
}
/* mutex_lock, mutex_unlock can be taken directly, as
signature and semantic are right, but without error check then!!!!,
we might want to change this therfore. */
static gboolean
g_mutex_try_lock_solaris_impl(GMutex* mutex)
{
int result;
result = mutex_trylock((mutex_t*)mutex);
if( result == EBUSY )
{
return FALSE;
}
solaris_check_for_error( result );
return TRUE;
}
static GCond*
g_cond_new_solaris_impl()
{
GCond* result = (GCond*) g_new0 (cond_t, 1);
solaris_check_for_error( cond_init( (cond_t*)result, USYNC_THREAD, 0 ) );
return result;
}
/* cond_signal, cond_broadcast and cond_wait
can be taken directly, as signature and semantic are right, but
without error check then!!!!, we might want to change this
therfore. */
#define G_MICROSEC 1000000
#define G_NANOSEC 1000000000
static gboolean
g_cond_timed_wait_solaris_impl(GCond* cond, GMutex* entered_mutex,
GTimeVal *abs_time)
{
int result;
timestruc_t end_time;
gboolean timed_out;
g_assert( cond );
g_assert( entered_mutex );
if( !abs_time )
{
g_cond_wait(cond, entered_mutex);
return TRUE;
}
end_time.tv_sec = abs_time->tv_sec;
end_time.tv_nsec = abs_time->tv_usec * ( G_NANOSEC / G_MICROSEC );
g_assert( end_time.tv_nsec < G_NANOSEC );
result = cond_timedwait( (cond_t*)cond, (mutex_t*)entered_mutex, &end_time );
timed_out = ( result == ETIME );
if( !timed_out ) solaris_check_for_error( result );
return !timed_out;
}
static void
g_cond_free_solaris_impl(GCond* cond)
{
solaris_check_for_error( cond_destroy((cond_t*)cond) );
g_free (cond);
}
static GPrivate*
g_private_new_solaris_impl(GDestroyNotify destructor)
{
/* we can not use g_new and friends, as they might use mutexes by
themself */
GPrivate* result = malloc( sizeof(thread_key_t) );
/* FIXME: we shouldn't use g_log here either actually */
solaris_check_for_error( thr_keycreate( (thread_key_t*)result, destructor) );
return result;
}
void
g_private_set_solaris_impl(GPrivate* private, gpointer value)
{
g_assert( private );
/* FIXME: we shouldn't use g_log here actually */
solaris_check_for_error( thr_setspecific( *(thread_key_t*)private, value) );
}
gpointer
g_private_get_solaris_impl(GPrivate* private)
{
gpointer result;
g_assert( private );
/* FIXME: we shouldn't use g_log here actually */
solaris_check_for_error( thr_getspecific( *(thread_key_t*)private,
&result) );
return result;
}
static GThreadFunctions
g_thread_functions_for_glib_use_default = {
g_mutex_new_solaris_impl,
(void(*)(GMutex*))mutex_lock,
g_mutex_try_lock_solaris_impl,
(void(*)(GMutex*))mutex_unlock,
g_mutex_free_solaris_impl,
g_cond_new_solaris_impl,
(void(*)(GCond*))cond_signal,
(void(*)(GCond*))cond_broadcast,
(void(*)(GCond*,GMutex*))cond_wait,
g_cond_timed_wait_solaris_impl,
g_cond_free_solaris_impl,
g_private_new_solaris_impl,
g_private_get_solaris_impl,
g_private_set_solaris_impl
};

60
gthread/gthread.c Normal file
View File

@@ -0,0 +1,60 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <glib.h>
static const char *g_log_domain_gthread = "GThread";
static gboolean thread_system_already_initialized = FALSE;
#include G_THREAD_SOURCE
gboolean
g_thread_try_init(GThreadFunctions* init)
{
if (thread_system_already_initialized)
return FALSE;
thread_system_already_initialized = TRUE;
if (init == NULL)
{
g_thread_use_default_impl = TRUE;
init = &g_thread_functions_for_glib_use_default;
}
g_thread_functions_for_glib_use = *init;
g_thread_supported =
init->mutex_new &&
init->mutex_lock &&
init->mutex_try_lock &&
init->mutex_unlock &&
init->mutex_free &&
init->cond_new &&
init->cond_signal &&
init->cond_broadcast &&
init->cond_wait &&
init->cond_timed_wait &&
init->cond_free &&
init->private_new &&
init->private_get &&
init->private_get;
/* if somebody is calling g_thread_init(), it means that he at least wants
to have mutex support, so check this */
if (!g_thread_supported)
g_error( "Mutex functions missing." );
return TRUE;
}
void
g_thread_init(GThreadFunctions* init)
{
/* Make sure, this function is only called once. */
if (!g_thread_try_init (init))
g_error( "the glib thread system may only be initialized once." );
}

45
gthread/testgthread.c Normal file
View File

@@ -0,0 +1,45 @@
#define main testglib_main
#include <testglib.c>
#undef main
void
test_mutexes()
{
GMutex* mutex;
GCond* cond;
GStaticMutex static_mutex = G_STATIC_MUTEX_INIT;
G_LOCK_DEFINE(test_me);
mutex = g_mutex_new();
cond = g_cond_new();
g_mutex_lock(mutex);
g_mutex_unlock(mutex);
g_static_mutex_lock(static_mutex);
g_static_mutex_unlock(static_mutex);
g_cond_signal(cond);
g_cond_broadcast(cond);
g_lock(test_me);
g_unlock(test_me);
g_cond_free(cond);
g_mutex_free(mutex);
}
int
main()
{
test_mutexes();
g_thread_init( NULL );
test_mutexes();
/* later we might want to start n copies of that */
testglib_main(0,NULL);
return 0;
}