* 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(...)
volatile gint tail;
MonoArray *queue;
gint32 mask;
+ gint32 suspended;
MonoSemType lock;
};
#define NO_KEY ((guint32) -1)
-static guint32 wsq_tlskey = NO_KEY;
+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 == NO_KEY)
+ if (!wsq_tlskey_inited)
return;
- TlsFree (wsq_tlskey);
- wsq_tlskey = NO_KEY;
+ mono_native_tls_free (wsq_tlskey);
+ wsq_tlskey_inited = FALSE;
}
MonoWSQ *
MonoWSQ *wsq;
MonoDomain *root;
- if (wsq_tlskey == NO_KEY)
+ if (!wsq_tlskey_inited)
return NULL;
wsq = g_new0 (MonoWSQ, 1);
wsq->mask = INITIAL_LENGTH - 1;
+ 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);
- if (!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)
{
MONO_GC_UNREGISTER_ROOT (wsq->queue);
MONO_SEM_DESTROY (&wsq->lock);
memset (wsq, 0, sizeof (MonoWSQ));
- if (wsq_tlskey != NO_KEY && TlsGetValue (wsq_tlskey) == wsq)
- TlsSetValue (wsq_tlskey, NULL);
+ if (wsq_tlskey_inited && mono_native_tls_get_value (wsq_tlskey) == wsq)
+ mono_native_tls_set_value (wsq_tlskey, NULL);
g_free (wsq);
}
int count;
MonoWSQ *wsq;
- if (obj == NULL || wsq_tlskey == NO_KEY)
+ 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);
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;
gboolean res;
MonoWSQ *wsq;
- if (ptr == NULL || wsq_tlskey == NO_KEY)
+ 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;
void
mono_wsq_try_steal (MonoWSQ *wsq, void **ptr, guint32 ms_timeout)
{
- if (wsq == NULL || ptr == NULL || *ptr != NULL || wsq_tlskey == NO_KEY)
+ 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, FALSE) == 0) {