2 * mono-wsq.c: work-stealing queue
5 * Gonzalo Paniagua Javier (gonzalo@novell.com)
7 * Copyright (c) 2010 Novell, Inc (http://www.novell.com)
11 #include <mono/metadata/object.h>
12 #include <mono/metadata/mono-wsq.h>
13 #include <mono/utils/mono-semaphore.h>
15 #define INITIAL_LENGTH 32
16 #define WSQ_DEBUG(...)
17 //#define WSQ_DEBUG(...) g_message(__VA_ARGS__)
27 static guint32 wsq_tlskey = -1;
32 wsq_tlskey = TlsAlloc ();
50 wsq = g_new0 (MonoWSQ, 1);
51 wsq->mask = INITIAL_LENGTH - 1;
52 MONO_GC_REGISTER_ROOT (wsq->queue);
53 root = mono_get_root_domain ();
54 wsq->queue = mono_array_new_cached (root, mono_defaults.object_class, INITIAL_LENGTH);
55 MONO_SEM_INIT (&wsq->lock, 1);
56 TlsSetValue (wsq_tlskey, wsq);
61 mono_wsq_destroy (MonoWSQ *wsq)
63 if (wsq == NULL || wsq->queue == NULL)
66 /* TODO: clean up queue if not empty */
67 MONO_GC_UNREGISTER_ROOT (wsq->queue);
68 MONO_SEM_DESTROY (&wsq->lock);
69 if (wsq_tlskey != -1 && TlsGetValue (wsq_tlskey) == wsq)
70 TlsSetValue (wsq_tlskey, NULL);
71 memset (wsq, 0, sizeof (MonoWSQ));
76 mono_wsq_count (MonoWSQ *wsq)
78 return ((wsq->tail - wsq->head) & wsq->mask);
82 mono_wsq_local_push (void *obj)
92 wsq = (MonoWSQ *) TlsGetValue (wsq_tlskey);
94 WSQ_DEBUG ("local_push: no wsq\n");
99 if (tail < wsq->head + wsq->mask) {
100 mono_array_setref (wsq->queue, tail & wsq->mask, (MonoObject *) obj);
101 wsq->tail = tail + 1;
102 WSQ_DEBUG ("local_push: OK %p %p\n", wsq, obj);
106 MONO_SEM_WAIT (&wsq->lock);
108 count = wsq->tail - wsq->head;
109 if (count >= wsq->mask) {
110 MonoArray *new_array;
114 length = mono_array_length (wsq->queue);
115 new_array = mono_array_new_cached (mono_get_root_domain (), mono_defaults.object_class, length * 2);
116 for (i = 0; i < length; i++)
117 mono_array_setref (new_array, i, mono_array_get (wsq->queue, MonoObject*, (i + head) & wsq->mask));
119 memset (mono_array_addr (wsq->queue, MonoObject *, 0), 0, sizeof (MonoObject*) * length);
120 wsq->queue = new_array;
122 wsq->tail = tail = count;
123 wsq->mask = (wsq->mask << 1) | 1;
125 mono_array_setref (wsq->queue, tail & wsq->mask, obj);
126 wsq->tail = tail + 1;
127 MONO_SEM_POST (&wsq->lock);
128 WSQ_DEBUG ("local_push: LOCK %p %p\n", wsq, obj);
133 mono_wsq_local_pop (void **ptr)
142 wsq = (MonoWSQ *) TlsGetValue (wsq_tlskey);
144 WSQ_DEBUG ("local_pop: no wsq\n");
149 if (wsq->head >= tail) {
150 WSQ_DEBUG ("local_pop: empty\n");
154 InterlockedExchange (&wsq->tail, tail);
155 if (wsq->head <= tail) {
156 *ptr = mono_array_get (wsq->queue, void *, tail & wsq->mask);
157 mono_array_set (wsq->queue, void *, tail & wsq->mask, NULL);
158 WSQ_DEBUG ("local_pop: GOT ONE %p %p\n", wsq, *ptr);
162 MONO_SEM_WAIT (&wsq->lock);
163 if (wsq->head <= tail) {
164 *ptr = mono_array_get (wsq->queue, void *, tail & wsq->mask);
165 mono_array_set (wsq->queue, void *, tail & wsq->mask, NULL);
168 wsq->tail = tail + 1;
171 MONO_SEM_POST (&wsq->lock);
172 WSQ_DEBUG ("local_pop: LOCK %d %p %p\n", res, wsq, *ptr);
177 mono_wsq_try_steal (MonoWSQ *wsq, void **ptr, guint32 ms_timeout)
179 if (wsq == NULL || ptr == NULL || *ptr != NULL)
182 if (TlsGetValue (wsq_tlskey) == wsq)
185 if (MONO_SEM_TIMEDWAIT (&wsq->lock, ms_timeout)) {
189 InterlockedExchange (&wsq->head, head + 1);
190 if (head < wsq->tail) {
191 *ptr = mono_array_get (wsq->queue, void *, head & wsq->mask);
192 mono_array_set (wsq->queue, void *, head & wsq->mask, NULL);
193 WSQ_DEBUG ("STEAL %p %p\n", wsq, *ptr);
197 MONO_SEM_POST (&wsq->lock);