* 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;
};
-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 *
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);
}
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);
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)
+ 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)
+ 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;