mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-08-01 15:03:39 +02:00
This commit merges the glib-threads branch into the main
branch. See the ChangeLog for details of the changes. In brief overview: - The set of threading functions can be set - A default implementation is provided in -lgthread - All static data structures are locked using these functions if g_thread_init() is called.
This commit is contained in:
8
gthread/.cvsignore
Normal file
8
gthread/.cvsignore
Normal file
@@ -0,0 +1,8 @@
|
||||
Makefile.in
|
||||
Makefile
|
||||
.deps
|
||||
*.lo
|
||||
*.o
|
||||
.libs
|
||||
*.la
|
||||
testgthread
|
21
gthread/Makefile.am
Normal file
21
gthread/Makefile.am
Normal 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
|
28
gthread/gthread-none.c
Normal file
28
gthread/gthread-none.c
Normal file
@@ -0,0 +1,28 @@
|
||||
/* GLIB - Library of useful routines for C programming
|
||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* gthread.c: fallback thread system implementation
|
||||
* 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
|
||||
*/
|
||||
|
||||
static GThreadFunctions
|
||||
g_mutex_functions_for_glib_use_default; /* is NULLified */
|
218
gthread/gthread-nspr.c
Normal file
218
gthread/gthread-nspr.c
Normal file
@@ -0,0 +1,218 @@
|
||||
/* GLIB - Library of useful routines for C programming
|
||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* gthread.c: nspr thread system implementation
|
||||
* 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 <prpdce.h>
|
||||
#include <prthread.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef G_DISABLE_ASSERT
|
||||
|
||||
#define STDERR_ASSERT(expr)
|
||||
|
||||
#else /* G_DISABLE_ASSERT */
|
||||
|
||||
#define STDERR_ASSERT(expr) G_STMT_START{ \
|
||||
if (!(expr)) \
|
||||
g_log (G_LOG_DOMAIN, \
|
||||
G_LOG_LEVEL_ERROR, \
|
||||
"file %s: line %d: assertion failed: (%s)", \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
#expr); }G_STMT_END
|
||||
|
||||
#endif /* G_DISABLE_ASSERT */
|
||||
|
||||
/* NOTE: the functions g_mutex_lock and g_mutex_unlock may not use
|
||||
functions from gmem.c and gmessages.c; */
|
||||
|
||||
static gboolean
|
||||
g_mutex_trylock_nspr_impl (GMutex * mutex)
|
||||
{
|
||||
PRStatus status = PRP_TryLock ((PRLock *) mutex);
|
||||
if (status == PR_SUCCESS)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
g_cond_wait_nspr_impl (GCond * cond,
|
||||
GMutex * entered_mutex)
|
||||
{
|
||||
PRStatus status = PRP_NakedWait ((PRCondVar *) cond,
|
||||
(PRLock *) entered_mutex,
|
||||
PR_INTERVAL_NO_TIMEOUT);
|
||||
g_assert (status == PR_SUCCESS);
|
||||
}
|
||||
|
||||
#define G_MICROSEC 1000000
|
||||
|
||||
static gboolean
|
||||
g_cond_timed_wait_nspr_impl (GCond * cond,
|
||||
GMutex * entered_mutex,
|
||||
GTimeVal * abs_time)
|
||||
{
|
||||
PRStatus status;
|
||||
PRIntervalTime interval;
|
||||
GTimeVal current_time;
|
||||
glong microsecs;
|
||||
|
||||
g_return_val_if_fail (cond != NULL, FALSE);
|
||||
g_return_val_if_fail (entered_mutex != NULL, FALSE);
|
||||
|
||||
g_get_current_time (¤t_time);
|
||||
|
||||
if (abs_time->tv_sec < current_time.tv_sec ||
|
||||
(abs_time->tv_sec == current_time.tv_sec &&
|
||||
abs_time->tv_usec < current_time.tv_usec))
|
||||
return FALSE;
|
||||
|
||||
interval = PR_SecondsToInterval (abs_time->tv_sec - current_time.tv_sec);
|
||||
microsecs = abs_time->tv_usec - current_time.tv_usec;
|
||||
if (microsecs < 0)
|
||||
interval -= PR_MicrosecondsToInterval (-microsecs);
|
||||
else
|
||||
interval += PR_MicrosecondsToInterval (microsecs);
|
||||
|
||||
status = PRP_NakedWait ((PRCondVar *) cond, (PRLock *) entered_mutex,
|
||||
interval);
|
||||
|
||||
g_assert (status == PR_SUCCESS);
|
||||
|
||||
g_get_current_time (¤t_time);
|
||||
|
||||
if (abs_time->tv_sec < current_time.tv_sec ||
|
||||
(abs_time->tv_sec == current_time.tv_sec &&
|
||||
abs_time->tv_usec < current_time.tv_usec))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct _GPrivateNSPRData GPrivateNSPRData;
|
||||
struct _GPrivateNSPRData
|
||||
{
|
||||
gpointer data;
|
||||
GDestroyNotify destructor;
|
||||
};
|
||||
|
||||
typedef struct _GPrivateNSPR GPrivateNSPR;
|
||||
struct _GPrivateNSPR
|
||||
{
|
||||
PRUintn private;
|
||||
GDestroyNotify destructor;
|
||||
};
|
||||
|
||||
static GPrivateNSPRData *
|
||||
g_private_nspr_data_constructor (GDestroyNotify destructor, gpointer data)
|
||||
{
|
||||
/* we can not use g_new and friends, as they might use private data by
|
||||
themself */
|
||||
GPrivateNSPRData *private = malloc (sizeof (GPrivateNSPRData));
|
||||
g_assert (private);
|
||||
private->data = data;
|
||||
private->destructor = destructor;
|
||||
|
||||
return private;
|
||||
}
|
||||
|
||||
static void
|
||||
g_private_nspr_data_destructor (gpointer data)
|
||||
{
|
||||
GPrivateNSPRData *private = data;
|
||||
if (private->destructor && private->data)
|
||||
(*private->destructor) (private->data);
|
||||
free (private);
|
||||
}
|
||||
|
||||
static GPrivate *
|
||||
g_private_new_nspr_impl (GDestroyNotify destructor)
|
||||
{
|
||||
GPrivateNSPR *result = g_new (GPrivateNSPR, 1);
|
||||
PRStatus status = PR_NewThreadPrivateIndex (&result->private,
|
||||
g_private_nspr_data_destructor);
|
||||
g_assert (status == PR_SUCCESS);
|
||||
|
||||
result->destructor = destructor;
|
||||
return (GPrivate *) result;
|
||||
}
|
||||
|
||||
/* NOTE: the functions g_private_get and g_private_set may not use
|
||||
functions from gmem.c and gmessages.c */
|
||||
|
||||
static GPrivateNSPRData *
|
||||
g_private_nspr_data_get (GPrivateNSPR * private)
|
||||
{
|
||||
GPrivateNSPRData *data;
|
||||
|
||||
STDERR_ASSERT (private);
|
||||
|
||||
data = PR_GetThreadPrivate (private->private);
|
||||
if (!data)
|
||||
{
|
||||
data = g_private_nspr_data_constructor (private->destructor, NULL);
|
||||
STDERR_ASSERT (PR_SetThreadPrivate (private->private, data)
|
||||
== PR_SUCCESS);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void
|
||||
g_private_set_nspr_impl (GPrivate * private, gpointer value)
|
||||
{
|
||||
if (!private)
|
||||
return;
|
||||
|
||||
g_private_nspr_data_get ((GPrivateNSPR *) private)->data = value;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
g_private_get_nspr_impl (GPrivate * private)
|
||||
{
|
||||
if (!private)
|
||||
return NULL;
|
||||
|
||||
return g_private_nspr_data_get ((GPrivateNSPR *) private)->data;
|
||||
}
|
||||
|
||||
static GThreadFunctions g_thread_functions_for_glib_use_default =
|
||||
{
|
||||
(GMutex * (*)())PR_NewLock,
|
||||
(void (*)(GMutex *)) PR_Lock,
|
||||
g_mutex_trylock_nspr_impl,
|
||||
(void (*)(GMutex *)) PR_Unlock,
|
||||
(void (*)(GMutex *)) PR_DestroyLock,
|
||||
(GCond * (*)())PRP_NewNakedCondVar,
|
||||
(void (*)(GCond *)) PRP_NakedNotify,
|
||||
(void (*)(GCond *)) PRP_NakedBroadcast,
|
||||
g_cond_wait_nspr_impl,
|
||||
g_cond_timed_wait_nspr_impl,
|
||||
(void (*)(GCond *)) PRP_DestroyNakedCondVar,
|
||||
g_private_new_nspr_impl,
|
||||
g_private_get_nspr_impl,
|
||||
g_private_set_nspr_impl
|
||||
};
|
176
gthread/gthread-posix.c
Normal file
176
gthread/gthread-posix.c
Normal file
@@ -0,0 +1,176 @@
|
||||
/* GLIB - Library of useful routines for C programming
|
||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* gthread.c: posix thread system implementation
|
||||
* 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 <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)
|
||||
{
|
||||
GMutex *result = (GMutex *) g_new (pthread_mutex_t, 1);
|
||||
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);
|
||||
}
|
||||
|
||||
/* NOTE: the functions g_mutex_lock and g_mutex_unlock may not use
|
||||
functions from gmem.c and gmessages.c; */
|
||||
|
||||
/* 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 therefore. */
|
||||
|
||||
static gboolean
|
||||
g_mutex_trylock_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_new (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)
|
||||
{
|
||||
GPrivate *result = (GPrivate *) g_new (pthread_key_t, 1);
|
||||
posix_check_for_error (pthread_key_create ((pthread_key_t *) result,
|
||||
destructor));
|
||||
return 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_posix_impl (GPrivate * private, gpointer value)
|
||||
{
|
||||
if (!private)
|
||||
return;
|
||||
|
||||
pthread_setspecific (*(pthread_key_t *) private, value);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
g_private_get_posix_impl (GPrivate * private)
|
||||
{
|
||||
if (!private)
|
||||
return NULL;
|
||||
|
||||
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_trylock_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
|
||||
};
|
177
gthread/gthread-solaris.c
Normal file
177
gthread/gthread-solaris.c
Normal file
@@ -0,0 +1,177 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <thread.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.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 (void)
|
||||
{
|
||||
GMutex *result = (GMutex *) g_new (mutex_t, 1);
|
||||
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);
|
||||
}
|
||||
|
||||
/* NOTE: the functions g_mutex_lock and g_mutex_unlock may not use
|
||||
functions from gmem.c and gmessages.c; */
|
||||
|
||||
/* 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 therefore. */
|
||||
|
||||
static gboolean
|
||||
g_mutex_trylock_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_new (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_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 = 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)
|
||||
{
|
||||
GPrivate *result = (GPrivate *) g_new (thread_key_t,1);
|
||||
solaris_check_for_error (thr_keycreate ((thread_key_t *) result,
|
||||
destructor));
|
||||
return 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_solaris_impl (GPrivate * private, gpointer value)
|
||||
{
|
||||
if (!private)
|
||||
return;
|
||||
|
||||
thr_setspecific (*(thread_key_t *) private, value);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
g_private_get_solaris_impl (GPrivate * private)
|
||||
{
|
||||
gpointer result;
|
||||
|
||||
if (!private)
|
||||
return NULL;
|
||||
|
||||
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_trylock_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
|
||||
};
|
101
gthread/gthread.c
Normal file
101
gthread/gthread.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/* GLIB - Library of useful routines for C programming
|
||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* gthread.c: thread related functions
|
||||
* 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
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
void g_mutex_init (void);
|
||||
void g_mem_init (void);
|
||||
void g_messages_init (void);
|
||||
|
||||
void
|
||||
g_thread_init(GThreadFunctions* init)
|
||||
{
|
||||
gboolean supported;
|
||||
|
||||
if (thread_system_already_initialized)
|
||||
g_error ("the glib thread system may only be initialized once.");
|
||||
|
||||
thread_system_already_initialized = TRUE;
|
||||
|
||||
if (init == NULL)
|
||||
init = &g_thread_functions_for_glib_use_default;
|
||||
else
|
||||
g_thread_use_default_impl = FALSE;
|
||||
|
||||
g_thread_functions_for_glib_use = *init;
|
||||
|
||||
/* It is important, that g_thread_supported is not set before the
|
||||
thread initialization functions of the different modules are
|
||||
called */
|
||||
|
||||
supported =
|
||||
init->mutex_new &&
|
||||
init->mutex_lock &&
|
||||
init->mutex_trylock &&
|
||||
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 wants to
|
||||
have thread support, so check this */
|
||||
|
||||
if (!supported)
|
||||
{
|
||||
if (g_thread_use_default_impl)
|
||||
g_error ("Threads are not supported on this platform.");
|
||||
else
|
||||
g_error ("The supplied thread function vector is invalid.");
|
||||
}
|
||||
|
||||
/* now call the thread initialization functions of the different
|
||||
glib modules. BTW: order does matter, g_mutex_init MUST be first */
|
||||
|
||||
g_mutex_init ();
|
||||
g_mem_init ();
|
||||
g_messages_init ();
|
||||
|
||||
/* now we can set g_thread_supported and thus enable all the thread
|
||||
functions */
|
||||
|
||||
g_thread_supported = TRUE;
|
||||
}
|
200
gthread/testgthread.c
Normal file
200
gthread/testgthread.c
Normal file
@@ -0,0 +1,200 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#define main testglib_main
|
||||
#include <testglib.c>
|
||||
#undef main
|
||||
|
||||
#define TEST_PRIVATE_THREADS 9
|
||||
#define TEST_PRIVATE_ROUNDS 5
|
||||
|
||||
void
|
||||
test_mutexes ()
|
||||
{
|
||||
GMutex *mutex = NULL;
|
||||
GCond *cond = NULL;
|
||||
GStaticMutex static_mutex = G_STATIC_MUTEX_INIT;
|
||||
G_LOCK_DEFINE (test_me);
|
||||
|
||||
if (g_thread_supported)
|
||||
{
|
||||
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);
|
||||
|
||||
if (g_thread_supported)
|
||||
{
|
||||
g_cond_free (cond);
|
||||
g_mutex_free (mutex);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(NSPR) /* we are using nspr threads */
|
||||
/* this option must be specified by hand during compile of
|
||||
testgthread. also note, that you have to link with whatever library
|
||||
nspr is building upon, it might otherwise (as on solaris) lead to
|
||||
run time failure, as the mutex functions are defined in libc, but
|
||||
as noops, that will make some nspr assertions fail. */
|
||||
#include <prthread.h>
|
||||
|
||||
gpointer
|
||||
new_thread (GHookFunc func, gpointer data)
|
||||
{
|
||||
PRThread *thread = PR_CreateThread (PR_SYSTEM_THREAD, func, data,
|
||||
PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
|
||||
PR_JOINABLE_THREAD, 0);
|
||||
return thread;
|
||||
}
|
||||
#define join_thread(thread) PR_JoinThread (thread)
|
||||
#define self_thread() PR_GetCurrentThread ()
|
||||
|
||||
#elif defined(DEFAULTMUTEX) /* we are using solaris threads */
|
||||
|
||||
gpointer
|
||||
new_thread (GHookFunc func, gpointer data)
|
||||
{
|
||||
thread_t thread;
|
||||
thr_create (NULL, 0, (void *(*)(void *)) func, data, THR_BOUND, &thread);
|
||||
return GUINT_TO_POINTER (thread);
|
||||
}
|
||||
#define join_thread(thread) \
|
||||
thr_join ((thread_t)GPOINTER_TO_UINT (thread), NULL, NULL)
|
||||
#define self_thread() GUINT_TO_POINTER (thr_self ())
|
||||
|
||||
#elif defined(PTHREAD_MUTEX_INITIALIZER) /* we are using posix threads */
|
||||
gpointer
|
||||
new_thread(GHookFunc func, gpointer data)
|
||||
{
|
||||
pthread_t thread;
|
||||
pthread_attr_t pthread_attr;
|
||||
pthread_attr_init (&pthread_attr);
|
||||
pthread_attr_setdetachstate (&pthread_attr, PTHREAD_CREATE_JOINABLE);
|
||||
pthread_create (&thread, &pthread_attr, (void *(*)(void *)) func, data);
|
||||
return GUINT_TO_POINTER (thread);
|
||||
}
|
||||
#define join_thread(thread) \
|
||||
pthread_join ((pthread_t)GPOINTER_TO_UINT (thread), NULL)
|
||||
#define self_thread() GUINT_TO_POINTER (pthread_self ())
|
||||
|
||||
#else /* we are not having a thread implementation, do nothing */
|
||||
|
||||
#define new_thread(func,data) (NULL)
|
||||
#define join_thread(thread) ((void)0)
|
||||
#define self_thread() NULL
|
||||
|
||||
#endif
|
||||
|
||||
#define G_MICROSEC 1000000
|
||||
|
||||
void
|
||||
wait_thread (double seconds)
|
||||
{
|
||||
GMutex *mutex;
|
||||
GCond *cond;
|
||||
GTimeVal current_time;
|
||||
|
||||
g_get_current_time (¤t_time);
|
||||
mutex = g_mutex_new ();
|
||||
cond = g_cond_new ();
|
||||
|
||||
current_time.tv_sec += (guint) seconds;
|
||||
seconds -= (guint) seconds;
|
||||
current_time.tv_usec += (guint) (seconds * G_MICROSEC);
|
||||
while (current_time.tv_usec >= G_MICROSEC)
|
||||
{
|
||||
current_time.tv_usec -= G_MICROSEC;
|
||||
current_time.tv_sec++;
|
||||
}
|
||||
|
||||
g_mutex_lock (mutex);
|
||||
g_cond_timed_wait (cond, mutex, ¤t_time);
|
||||
g_mutex_unlock (mutex);
|
||||
|
||||
g_mutex_free (mutex);
|
||||
g_cond_free (cond);
|
||||
}
|
||||
|
||||
gpointer
|
||||
private_constructor ()
|
||||
{
|
||||
gpointer *result = g_new (gpointer, 2);
|
||||
result[0] = 0;
|
||||
result[1] = self_thread ();
|
||||
g_print ("allocating data for the thread %p.\n", result[1]);
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
private_destructor (gpointer data)
|
||||
{
|
||||
gpointer *real = data;
|
||||
g_print ("freeing data for the thread %p.\n", real[1]);
|
||||
g_free (real);
|
||||
}
|
||||
|
||||
GStaticPrivate private;
|
||||
|
||||
void
|
||||
test_private_func (void *data)
|
||||
{
|
||||
guint i = 0;
|
||||
wait_thread (1);
|
||||
while (i < TEST_PRIVATE_ROUNDS)
|
||||
{
|
||||
guint random_value = rand () % 10000;
|
||||
guint *data = g_static_private_get (&private);
|
||||
if (!data)
|
||||
{
|
||||
data = private_constructor ();
|
||||
g_static_private_set (&private, data, private_destructor);
|
||||
}
|
||||
*data = random_value;
|
||||
wait_thread (.2);
|
||||
g_assert (*(guint *) g_static_private_get (&private) == random_value);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_private ()
|
||||
{
|
||||
int i;
|
||||
gpointer threads[TEST_PRIVATE_THREADS];
|
||||
for (i = 0; i < TEST_PRIVATE_THREADS; i++)
|
||||
{
|
||||
threads[i] = new_thread (test_private_func, (gpointer) i);
|
||||
}
|
||||
for (i = 0; i < TEST_PRIVATE_THREADS; i++)
|
||||
{
|
||||
join_thread (threads[i]);
|
||||
}
|
||||
g_print ("\n");
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
test_mutexes ();
|
||||
|
||||
g_thread_init (NULL);
|
||||
|
||||
test_mutexes ();
|
||||
|
||||
test_private ();
|
||||
|
||||
/* later we might want to start n copies of that */
|
||||
testglib_main (0, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user