Merge pull request #1333 from joero74/ignore-missing-host
[mono.git] / mono / metadata / mono-wsq.c
index 83cc71589ccdcd43a295a11fd11bee51371c67b7..859fb69c55bf16d3e46548a37aeba73973c843e8 100644 (file)
@@ -5,12 +5,15 @@
  *   Gonzalo Paniagua Javier (gonzalo@novell.com)
  *
  * Copyright (c) 2010 Novell, Inc (http://www.novell.com)
+ * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
  */
 
 #include <string.h>
 #include <mono/metadata/object.h>
 #include <mono/metadata/mono-wsq.h>
 #include <mono/utils/mono-semaphore.h>
+#include <mono/utils/mono-tls.h>
+#include <mono/utils/atomic.h>
 
 #define INITIAL_LENGTH 32
 #define WSQ_DEBUG(...)
@@ -21,24 +24,31 @@ struct _MonoWSQ {
        volatile gint tail;
        MonoArray *queue;
        gint32 mask;
+       gint32 suspended;
        MonoSemType lock;
 };
 
-static guint32 wsq_tlskey = -1;
+#define NO_KEY ((guint32) -1)
+static MonoNativeTlsKey wsq_tlskey;
+static gboolean wsq_tlskey_inited = FALSE;
 
 void
 mono_wsq_init ()
 {
-       wsq_tlskey = TlsAlloc ();
+       if (wsq_tlskey_inited)
+               return;
+
+       mono_native_tls_alloc (&wsq_tlskey, NULL);
+       wsq_tlskey_inited = TRUE;
 }
 
 void
 mono_wsq_cleanup ()
 {
-       if (wsq_tlskey == -1)
+       if (!wsq_tlskey_inited)
                return;
-       TlsFree (wsq_tlskey);
-       wsq_tlskey = -1;
+       mono_native_tls_free (wsq_tlskey);
+       wsq_tlskey_inited = FALSE;
 }
 
 MonoWSQ *
@@ -47,34 +57,49 @@ mono_wsq_create ()
        MonoWSQ *wsq;
        MonoDomain *root;
 
+       if (!wsq_tlskey_inited)
+               return NULL;
+
        wsq = g_new0 (MonoWSQ, 1);
        wsq->mask = INITIAL_LENGTH - 1;
-       MONO_GC_REGISTER_ROOT (wsq->queue);
+       wsq->suspended = 0;
+       MONO_GC_REGISTER_ROOT_SINGLE (wsq->queue);
        root = mono_get_root_domain ();
        wsq->queue = mono_array_new_cached (root, mono_defaults.object_class, INITIAL_LENGTH);
        MONO_SEM_INIT (&wsq->lock, 1);
-       TlsSetValue (wsq_tlskey, wsq);
+       if (!mono_native_tls_set_value (wsq_tlskey, wsq)) {
+               mono_wsq_destroy (wsq);
+               wsq = NULL;
+       }
        return wsq;
 }
 
+gboolean
+mono_wsq_suspend (MonoWSQ *wsq)
+{
+       return InterlockedCompareExchange (&wsq->suspended, 1, 0) == 0;
+}
+
 void
 mono_wsq_destroy (MonoWSQ *wsq)
 {
        if (wsq == NULL || wsq->queue == NULL)
                return;
 
-       /* TODO: clean up queue if not empty */
+       g_assert (mono_wsq_count (wsq) == 0);
        MONO_GC_UNREGISTER_ROOT (wsq->queue);
        MONO_SEM_DESTROY (&wsq->lock);
-       if (wsq_tlskey != -1 && TlsGetValue (wsq_tlskey) == wsq)
-               TlsSetValue (wsq_tlskey, NULL);
        memset (wsq, 0, sizeof (MonoWSQ));
+       if (wsq_tlskey_inited && mono_native_tls_get_value (wsq_tlskey) == wsq)
+               mono_native_tls_set_value (wsq_tlskey, NULL);
        g_free (wsq);
 }
 
 gint
 mono_wsq_count (MonoWSQ *wsq)
 {
+       if (!wsq)
+               return 0;
        return ((wsq->tail - wsq->head) & wsq->mask);
 }
 
@@ -86,15 +111,20 @@ mono_wsq_local_push (void *obj)
        int count;
        MonoWSQ *wsq;
 
-       if (obj == NULL)
+       if (obj == NULL || !wsq_tlskey_inited)
                return FALSE;
 
-       wsq = (MonoWSQ *) TlsGetValue (wsq_tlskey);
+       wsq = (MonoWSQ *) mono_native_tls_get_value (wsq_tlskey);
        if (wsq == NULL) {
                WSQ_DEBUG ("local_push: no wsq\n");
                return FALSE;
        }
 
+       if (wsq->suspended) {
+               WSQ_DEBUG ("local_push: wsq suspended\n");
+               return FALSE;
+       }
+
        tail = wsq->tail;
        if (tail < wsq->head + wsq->mask) {
                mono_array_setref (wsq->queue, tail & wsq->mask, (MonoObject *) obj);
@@ -116,7 +146,7 @@ mono_wsq_local_push (void *obj)
                for (i = 0; i < length; i++)
                        mono_array_setref (new_array, i, mono_array_get (wsq->queue, MonoObject*, (i + head) & wsq->mask));
 
-               memset (mono_array_addr (wsq->queue, MonoObject *, 0), 0, sizeof (MonoObject*) * length);
+               mono_gc_bzero_aligned (mono_array_addr (wsq->queue, MonoObject *, 0), sizeof (MonoObject*) * length);
                wsq->queue = new_array;
                wsq->head = 0;
                wsq->tail = tail = count;
@@ -136,10 +166,10 @@ mono_wsq_local_pop (void **ptr)
        gboolean res;
        MonoWSQ *wsq;
 
-       if (ptr == NULL)
+       if (ptr == NULL || !wsq_tlskey_inited)
                return FALSE;
 
-       wsq = (MonoWSQ *) TlsGetValue (wsq_tlskey);
+       wsq = (MonoWSQ *) mono_native_tls_get_value (wsq_tlskey);
        if (wsq == NULL) {
                WSQ_DEBUG ("local_pop: no wsq\n");
                return FALSE;
@@ -176,13 +206,13 @@ mono_wsq_local_pop (void **ptr)
 void
 mono_wsq_try_steal (MonoWSQ *wsq, void **ptr, guint32 ms_timeout)
 {
-       if (wsq == NULL || ptr == NULL || *ptr != NULL)
+       if (wsq == NULL || ptr == NULL || *ptr != NULL || !wsq_tlskey_inited)
                return;
 
-       if (TlsGetValue (wsq_tlskey) == wsq)
+       if (mono_native_tls_get_value (wsq_tlskey) == wsq)
                return;
 
-       if (MONO_SEM_TIMEDWAIT (&wsq->lock, ms_timeout)) {
+       if (mono_sem_timedwait (&wsq->lock, ms_timeout, FALSE) == 0) {
                int head;
 
                head = wsq->head;