diff --git a/gthread/gthread-nspr.c b/gthread/gthread-nspr.c new file mode 100644 index 000000000..77672e5f0 --- /dev/null +++ b/gthread/gthread-nspr.c @@ -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 +#include +#include + +#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 +};