+2002-06-08 Jeffrey Stedfast <fejj@ximian.com>
+
+ * mono-mutex.c (mono_once): New convenience function for my
+ previous fix.
+
+ * handles.c:
+ * error.c:
+ * critical-sections.c:
+ * threads.c:
+ * sockets.c:
+ * semaphores.c:
+ * processes.c:
+ * mutexes.c:
+ * io.c:
+ * events.c:
+ * atomic.c: Use mono_once() rather than pthread_once().
+
+2002-06-06 Jeffrey Stedfast <fejj@ximian.com>
+
+ * handles.c (_wapi_handle_new): pthread_once() is not atomic, so
+ if multiple threads all try to call _wapi_handle_new() before the
+ shared data has been initialized, it is possible that we could get
+ into a condition where shared_init() is being executed and later
+ threads will pass by pthread_once() due to the fact that it has
+ already been called and so therefor will attempt to use the shared
+ data before it has been completely initialized. If we instead use
+ a standard mutex locking mechanism around shared_init(), we can
+ avoid the situation entirely. By wrapping the mutex locking in a
+ check to see if we've already initialized the data, we can even
+ avoid wasting resources by having to lock/unlock the mutex in any
+ later calls (the only time we'd have to worry about
+ locking/unlocking is the initial race to call shared_init() at
+ startup).
Sat Jun 1 13:27:11 CEST 2002 Paolo Molaro <lupus@ximian.com>
#warning "Atomic functions are not atomic!"
static pthread_mutex_t spin;
-static pthread_once_t spin_once=PTHREAD_ONCE_INIT;
+static mono_once_t spin_once=MONO_ONCE_INIT;
static void spin_init(void)
{
{
gint32 old;
- pthread_once(&spin_once, spin_init);
+ mono_once(&spin_once, spin_init);
pthread_mutex_lock(&spin);
old= *dest;
{
gpointer old;
- pthread_once(&spin_once, spin_init);
+ mono_once(&spin_once, spin_init);
pthread_mutex_lock(&spin);
old= *dest;
{
gint32 ret;
- pthread_once(&spin_once, spin_init);
+ mono_once(&spin_once, spin_init);
pthread_mutex_lock(&spin);
*dest++;
{
gint32 ret;
- pthread_once(&spin_once, spin_init);
+ mono_once(&spin_once, spin_init);
pthread_mutex_lock(&spin);
*dest--;
{
gint32 ret;
- pthread_once(&spin_once, spin_init);
+ mono_once(&spin_once, spin_init);
pthread_mutex_lock(&spin);
ret=*dest;
{
gpointer ret;
- pthread_once(&spin_once, spin_init);
+ mono_once(&spin_once, spin_init);
pthread_mutex_lock(&spin);
ret=*dest;
{
gint32 ret;
- pthread_once(&spin_once, spin_init);
+ mono_once(&spin_once, spin_init);
pthread_mutex_lock(&spin);
ret= *dest;
* here but I'd need a mutex around the critical section structure
* anyway. So I may as well just use a pthread mutex.
*/
-static pthread_once_t attr_key_once=PTHREAD_ONCE_INIT;
+static mono_once_t attr_key_once=MONO_ONCE_INIT;
static mono_mutexattr_t attr;
static void attr_init(void)
*/
void InitializeCriticalSection(WapiCriticalSection *section)
{
- pthread_once(&attr_key_once, attr_init);
+ mono_once(&attr_key_once, attr_init);
mono_mutex_init(§ion->mutex, &attr);
}
#include "mono/io-layer/wapi.h"
static pthread_key_t error_key;
-static pthread_once_t error_key_once=PTHREAD_ONCE_INIT;
+static mono_once_t error_key_once=MONO_ONCE_INIT;
static void error_init(void)
{
guint32 err;
void *errptr;
- pthread_once(&error_key_once, error_init);
+ mono_once(&error_key_once, error_init);
errptr=pthread_getspecific(error_key);
err=GPOINTER_TO_UINT(errptr);
void SetLastError(guint32 code)
{
/* Set the thread-local error code */
- pthread_once(&error_key_once, error_init);
+ mono_once(&error_key_once, error_init);
pthread_setspecific(error_key, GUINT_TO_POINTER(code));
}
NULL, /* is_owned */
};
-static pthread_once_t event_ops_once=PTHREAD_ONCE_INIT;
+static mono_once_t event_ops_once=MONO_ONCE_INIT;
static void event_ops_init (void)
{
gpointer handle;
gboolean ok;
- pthread_once (&event_ops_once, event_ops_init);
+ mono_once (&event_ops_once, event_ops_init);
handle=_wapi_handle_new (WAPI_HANDLE_EVENT);
if(handle==_WAPI_HANDLE_INVALID) {
#undef DEBUG
-static pthread_once_t shared_data_once=PTHREAD_ONCE_INIT;
static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
static gboolean shared=FALSE;
static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
gpointer _wapi_handle_new (WapiHandleType type)
{
+ static mono_once_t shared_init_once = MONO_ONCE_INIT;
static pthread_mutex_t scan_mutex=PTHREAD_MUTEX_INITIALIZER;
guint32 idx;
gpointer handle;
#if HAVE_BOEHM_GC
gboolean tried_collect=FALSE;
#endif
-
- pthread_once (&shared_data_once, shared_init);
+
+ mono_once (&shared_init_once, shared_init);
again:
if(shared==TRUE) {
};
-static pthread_once_t io_ops_once=PTHREAD_ONCE_INIT;
+static mono_once_t io_ops_once=MONO_ONCE_INIT;
static void io_ops_init (void)
{
gchar *filename;
int ret;
- pthread_once (&io_ops_once, io_ops_init);
+ mono_once (&io_ops_once, io_ops_init);
if(name==NULL) {
#ifdef DEBUG
const guchar *name;
int flags, fd;
- pthread_once (&io_ops_once, io_ops_init);
+ mono_once (&io_ops_once, io_ops_init);
switch(stdhandle) {
case STD_INPUT_HANDLE:
#endif /* HAVE_PTHREAD_MUTEX_TIMEDLOCK */
+int
+mono_once (mono_once_t *once, void (*once_init) (void))
+{
+ if (!once->complete) {
+ pthread_mutex_lock (&once->mutex);
+ if (!once->complete) {
+ once_init ();
+ once->complete = TRUE;
+ }
+ pthread_mutex_unlock (&once->mutex);
+ }
+
+ return 0;
+}
+
#ifdef USE_MONO_MUTEX
#ifdef __cplusplus
extern "C" {
+#pragma }
#endif /* __cplusplus */
+#include <glib.h>
#include <pthread.h>
#include <time.h>
#endif /* HAVE_PTHREAD_MUTEX_TIMEDLOCK */
+typedef struct {
+ pthread_mutex_t mutex;
+ gboolean complete;
+} mono_once_t;
+
+#define MONO_ONCE_INIT { PTHREAD_MUTEX_INITIALIZER, FALSE }
+
+int mono_once (mono_once_t *once, void (*once_init) (void));
+
+
#ifdef USE_MONO_MUTEX
#define MONO_THREAD_NONE ((pthread_t)~0)
mutex_is_owned, /* is_owned */
};
-static pthread_once_t mutex_ops_once=PTHREAD_ONCE_INIT;
+static mono_once_t mutex_ops_once=MONO_ONCE_INIT;
static void mutex_ops_init (void)
{
gpointer handle;
gboolean ok;
- pthread_once (&mutex_ops_once, mutex_ops_init);
+ mono_once (&mutex_ops_once, mutex_ops_init);
handle=_wapi_handle_new (WAPI_HANDLE_MUTEX);
if(handle==_WAPI_HANDLE_INVALID) {
NULL, /* is_owned */
};
-static pthread_once_t process_ops_once=PTHREAD_ONCE_INIT;
+static mono_once_t process_ops_once=MONO_ONCE_INIT;
static void process_ops_init (void)
{
WapiStartupInfo *startup G_GNUC_UNUSED,
WapiProcessInformation *process_info G_GNUC_UNUSED)
{
- pthread_once (&process_ops_once, process_ops_init);
+ mono_once (&process_ops_once, process_ops_init);
return(FALSE);
}
NULL, /* is_owned */
};
-static pthread_once_t sem_ops_once=PTHREAD_ONCE_INIT;
+static mono_once_t sem_ops_once=MONO_ONCE_INIT;
static void sem_ops_init (void)
{
gpointer handle;
gboolean ok;
- pthread_once (&sem_ops_once, sem_ops_init);
+ mono_once (&sem_ops_once, sem_ops_init);
if(max<=0) {
#ifdef DEBUG
static guint32 startup_count=0;
static GPtrArray *sockets=NULL;
static pthread_key_t error_key;
-static pthread_once_t error_key_once=PTHREAD_ONCE_INIT;
+static mono_once_t error_key_once=MONO_ONCE_INIT;
static void socket_close_private (gpointer handle);
NULL, /* is_owned */
};
-static pthread_once_t socket_ops_once=PTHREAD_ONCE_INIT;
+static mono_once_t socket_ops_once=MONO_ONCE_INIT;
static void socket_ops_init (void)
{
void WSASetLastError(int error)
{
- pthread_once(&error_key_once, error_init);
+ mono_once(&error_key_once, error_init);
pthread_setspecific(error_key, GINT_TO_POINTER(error));
}
int err;
void *errptr;
- pthread_once(&error_key_once, error_init);
+ mono_once(&error_key_once, error_init);
errptr=pthread_getspecific(error_key);
err=GPOINTER_TO_INT(errptr);
return(INVALID_SOCKET);
}
- pthread_once (&socket_ops_once, socket_ops_init);
+ mono_once (&socket_ops_once, socket_ops_init);
handle=_wapi_handle_new (WAPI_HANDLE_SOCKET);
if(handle==_WAPI_HANDLE_INVALID) {
/* Hash threads with tids. I thought of using TLS for this, but that
* would have to set the data in the new thread, which is more hassle
*/
-static pthread_once_t thread_hash_once = PTHREAD_ONCE_INIT;
+static mono_once_t thread_hash_once = MONO_ONCE_INIT;
static mono_mutex_t thread_hash_mutex = MONO_MUTEX_INITIALIZER;
static GHashTable *thread_hash=NULL;
NULL, /* is_owned */
};
-static pthread_once_t thread_ops_once=PTHREAD_ONCE_INIT;
+static mono_once_t thread_ops_once=MONO_ONCE_INIT;
static void thread_ops_init (void)
{
gboolean ok;
int ret;
- pthread_once(&thread_hash_once, thread_hash_init);
- pthread_once (&thread_ops_once, thread_ops_init);
+ mono_once(&thread_hash_once, thread_hash_init);
+ mono_once (&thread_ops_once, thread_ops_init);
if(start==NULL) {
return(NULL);
*/
static pthread_key_t timed_thread_key;
-static pthread_once_t timed_thread_once = PTHREAD_ONCE_INIT;
+static mono_once_t timed_thread_once = MONO_ONCE_INIT;
static void timed_thread_init(void)
{
{
TimedThread *thread = (TimedThread *)args;
- pthread_once(&timed_thread_once, timed_thread_init);
+ mono_once(&timed_thread_once, timed_thread_init);
pthread_setspecific(timed_thread_key, (void *)thread);
pthread_detach(thread->id);
_wapi_timed_thread_exit(thread->start_routine(thread->arg));