2002-06-08 Jeffrey Stedfast <fejj@ximian.com>
authorJeffrey Stedfast <fejj@novell.com>
Sat, 8 Jun 2002 17:57:49 +0000 (17:57 -0000)
committerJeffrey Stedfast <fejj@novell.com>
Sat, 8 Jun 2002 17:57:49 +0000 (17:57 -0000)
* 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).

svn path=/trunk/mono/; revision=5177

15 files changed:
mono/io-layer/ChangeLog
mono/io-layer/atomic.c
mono/io-layer/critical-sections.c
mono/io-layer/error.c
mono/io-layer/events.c
mono/io-layer/handles.c
mono/io-layer/io.c
mono/io-layer/mono-mutex.c
mono/io-layer/mono-mutex.h
mono/io-layer/mutexes.c
mono/io-layer/processes.c
mono/io-layer/semaphores.c
mono/io-layer/sockets.c
mono/io-layer/threads.c
mono/io-layer/timed-thread.c

index 487eb0c1d6dd5890e40ee1c882c71636b8859333..71c89635535f58c315d270e4ded699ab773053ce 100644 (file)
@@ -1,3 +1,36 @@
+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>
 
index 9466c3d4941b60a1bdbabca08428af8f0c510c26..1bf0bf416ac50522480329ae998a10fb72ce1639 100644 (file)
@@ -18,7 +18,7 @@
 #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)
 {
@@ -31,7 +31,7 @@ gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch,
 {
        gint32 old;
        
-       pthread_once(&spin_once, spin_init);
+       mono_once(&spin_once, spin_init);
        pthread_mutex_lock(&spin);
        
        old= *dest;
@@ -49,7 +49,7 @@ gpointer InterlockedCompareExchangePointer(volatile gpointer *dest,
 {
        gpointer old;
        
-       pthread_once(&spin_once, spin_init);
+       mono_once(&spin_once, spin_init);
        pthread_mutex_lock(&spin);
        
        old= *dest;
@@ -66,7 +66,7 @@ gint32 InterlockedIncrement(volatile gint32 *dest)
 {
        gint32 ret;
        
-       pthread_once(&spin_once, spin_init);
+       mono_once(&spin_once, spin_init);
        pthread_mutex_lock(&spin);
        
        *dest++;
@@ -81,7 +81,7 @@ gint32 InterlockedDecrement(volatile gint32 *dest)
 {
        gint32 ret;
        
-       pthread_once(&spin_once, spin_init);
+       mono_once(&spin_once, spin_init);
        pthread_mutex_lock(&spin);
        
        *dest--;
@@ -96,7 +96,7 @@ gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
 {
        gint32 ret;
        
-       pthread_once(&spin_once, spin_init);
+       mono_once(&spin_once, spin_init);
        pthread_mutex_lock(&spin);
 
        ret=*dest;
@@ -111,7 +111,7 @@ gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch)
 {
        gpointer ret;
        
-       pthread_once(&spin_once, spin_init);
+       mono_once(&spin_once, spin_init);
        pthread_mutex_lock(&spin);
        
        ret=*dest;
@@ -126,7 +126,7 @@ gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
 {
        gint32 ret;
        
-       pthread_once(&spin_once, spin_init);
+       mono_once(&spin_once, spin_init);
        pthread_mutex_lock(&spin);
 
        ret= *dest;
index 5c33640b54a92fefef9c208e08ca0de4a690d92b..e3b4326bdc50581500f9c75b9511a5dcb9097da3 100644 (file)
@@ -26,7 +26,7 @@
  * 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)
@@ -43,7 +43,7 @@ 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(&section->mutex, &attr);
 }
 
index 131c572cdf71e167ec749ee70f1c62efdadf05ba..4e91047580cb1401093cc2ddf6218c2950d1a135 100644 (file)
@@ -14,7 +14,7 @@
 #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)
 {
@@ -34,7 +34,7 @@ guint32 GetLastError(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);
        
@@ -50,6 +50,6 @@ guint32 GetLastError(void)
 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));
 }
index 8168045100d3380da43ecaf51154d42b0da15073..60dfea7299e894ed5dd64c7524b9fbccb5e1d0f5 100644 (file)
@@ -35,7 +35,7 @@ struct _WapiHandleOps _wapi_event_ops = {
        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)
 {
@@ -116,7 +116,7 @@ gpointer CreateEvent(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean ma
        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) {
index 61fd61fbcbd30bf74e9dc0a57e9138e78353cffc..6e2896ae4a8812b9688bea3fd689da7ad865c0f6 100644 (file)
@@ -30,7 +30,6 @@
 
 #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]={
@@ -172,6 +171,7 @@ again:
 
 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;
@@ -180,8 +180,8 @@ gpointer _wapi_handle_new (WapiHandleType type)
 #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) {
index 102ce30ca82f4b9dba9a99e20bb7153951cd38d6..fbbc625ba3243c82d98a308ab30259e63a2219b2 100644 (file)
@@ -150,7 +150,7 @@ static struct {
 };
 
 
-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)
 {
@@ -1207,7 +1207,7 @@ gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
        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
@@ -1499,7 +1499,7 @@ gpointer GetStdHandle(WapiStdHandle stdhandle)
        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:
index a2661115e4d343955db48a4e4d6f594c00eee7bc..604afbe7103627fd829aa41b16e6a66d57c5b9d6 100644 (file)
@@ -62,6 +62,21 @@ pthread_mutex_timedlock (pthread_mutex_t *mutex, const struct timespec *timeout)
 #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
 
index ea533aa18423d95b6e70eae647bb27b3e062cea3..8e233167629ef3bc4ac7956f8fa49260a62c288b 100644 (file)
 
 #ifdef __cplusplus
 extern "C" {
+#pragma }
 #endif /* __cplusplus */
 
+#include <glib.h>
 #include <pthread.h>
 #include <time.h>
 
@@ -37,6 +39,16 @@ extern int pthread_mutex_timedlock (pthread_mutex_t *mutex,
 #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)
index 6675818873266030a99797d50f388652d1d4b0fb..0949a6871347a5b646f81dfbbd45bb9de71c2cb7 100644 (file)
@@ -35,7 +35,7 @@ struct _WapiHandleOps _wapi_mutex_ops = {
        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)
 {
@@ -169,7 +169,7 @@ gpointer CreateMutex(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean ow
        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) {
index 45887672faea5cf09ea2e049f4fc8ba48384ea78..b257c0d1e613ba6852d59252615973e2d99ca7d8 100644 (file)
@@ -38,7 +38,7 @@ struct _WapiHandleOps _wapi_process_ops = {
        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)
 {
@@ -76,7 +76,7 @@ gboolean CreateProcess (const gunichar2 *appname G_GNUC_UNUSED, gunichar2 *cmdli
                        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);
 }
index d5b29af8985ec434a2f95e714ebd237ab4b13c0e..c1a081d598d93b838b057f576a8448414f9b67ef 100644 (file)
@@ -36,7 +36,7 @@ struct _WapiHandleOps _wapi_sem_ops = {
        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)
 {
@@ -112,7 +112,7 @@ gpointer CreateSemaphore(WapiSecurityAttributes *security G_GNUC_UNUSED, gint32
        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
index 399c40a68445d99c6c5bfbb14ac23b691c441a0b..fc5e7f708bbf9d3bed119bd64242324049b4be23 100644 (file)
@@ -33,7 +33,7 @@
 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);
 
@@ -45,7 +45,7 @@ struct _WapiHandleOps _wapi_socket_ops = {
        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)
 {
@@ -130,7 +130,7 @@ static void error_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));
 }
 
@@ -139,7 +139,7 @@ int WSAGetLastError(void)
        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);
        
@@ -965,7 +965,7 @@ guint32 _wapi_socket(int domain, int type, int protocol)
                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) {
index 422bba1ed8d5baaaf02469f43afc661bfe7bb047..51f44cf644c82191aab695c89c2ac2aadb830a6c 100644 (file)
@@ -33,7 +33,7 @@
 /* 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;
 
@@ -52,7 +52,7 @@ struct _WapiHandleOps _wapi_thread_ops = {
        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)
 {
@@ -176,8 +176,8 @@ gpointer CreateThread(WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 st
        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);
index f955607614fc698c8f5dd5a46d5d85fbe8718b52..37feeeb5365ed3c8e81d4a244b383c74f7f5638a 100644 (file)
@@ -26,7 +26,7 @@
  */
 
 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)
 {
@@ -80,7 +80,7 @@ static void *timed_thread_start_routine(gpointer args)
 {
        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));