Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
14ec7da
Be more cautious when creating new threads
garuma Feb 18, 2011
3fc9184
Lock-free work-stealing queue for the Thread pool
garuma Feb 18, 2011
91a198d
Set threads list to NULL early on before freeing to avoid segfault wh…
garuma Feb 18, 2011
f9c527c
Pass local threadworker wsq around to avoid hitting thread local stor…
garuma Feb 18, 2011
fbd4fb3
Further optimize work-stealing algorithm in TP
garuma Feb 21, 2011
2cabbb3
Check wsq count before trying to steal from it
garuma Feb 21, 2011
81f0955
Cache threads value before iterating
garuma Feb 21, 2011
4ead3bd
Don't free list when runtime is shutting down.
garuma Feb 21, 2011
4d87668
Reorder rank of the extra wsq parameter to be less confusing
garuma Feb 21, 2011
7668cfa
Use __thread TLS when possible when storing thread specific work-stea…
garuma Feb 21, 2011
72ab732
Use 64bits integer when we are on x86_64
garuma Feb 21, 2011
f4296cb
Use more sensible names for 32bits/64bits Interlocked functions used …
garuma Feb 21, 2011
8839e3b
Use a gnative data type instead of manually gint32/gint64
garuma Feb 22, 2011
93d5b87
Unref objects when dequeuing so that GC can kick in
garuma Feb 22, 2011
578984e
Fix a buggy setref overlapping when growing the array
garuma Feb 22, 2011
fb76fa6
Let monitor_thread also handle the deletion of threads making thread …
garuma Feb 22, 2011
d7cbafd
Remove warning
garuma Feb 22, 2011
ff0a765
Simplify condition
garuma Feb 22, 2011
e257200
Compute starting time only if the first pass isn't successful when st…
garuma Feb 22, 2011
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion mcs/build/profiles/basic.make
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ endif
$(PROFILE_EXE): $(topdir)/build/common/basic-profile-check.cs
$(BOOTSTRAP_MCS) /warn:0 /out:$@ $<
echo -n "Bootstrap compiler: " 1>&2
$(BOOTSTRAP_MCS) --version 1>&2
# $(BOOTSTRAP_MCS) --version 1>&2

$(PROFILE_OUT): $(PROFILE_EXE)
$(PROFILE_RUNTIME) $< > $@ 2>&1
64 changes: 32 additions & 32 deletions mcs/class/corlib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -90,35 +90,35 @@ $(cmp_makefrag): $(cmp_response)
$(cmp_response) $(cmp_makefrag): Makefile $(depsdir)/.stamp
endif

vts = VersionTolerantSerialization
vtsdir = Test/System.Runtime.Serialization.Formatters.Binary/$(vts)
test-vts:
$(MCS) -target:library \
$(vtsdir)/$(vts)TestLib/1.0/Address.cs
$(MCS) $(test_nunit_ref) \
-r:$(vtsdir)/$(vts)TestLib/1.0/Address.dll \
$(vtsdir)/BinarySerializationOverVersions.cs
cp $(vtsdir)/$(vts)TestLib/1.0/Address.dll $(vtsdir)
$(MCS) -target:library \
$(vtsdir)/$(vts)TestLib/2.0/Address.cs
$(MCS) -target:library \
$(vtsdir)/$(vts)TestLib/3.0/Address.cs
$(MCS) -target:library \
$(vtsdir)/$(vts)TestLib/4.0/Address.cs
$(MCS) -target:library \
$(vtsdir)/$(vts)TestLib/5.0/Address.cs
$(MCS) -target:library \
$(vtsdir)/$(vts)TestLib/6.0/Address.cs
run-test-vts: test-vts
$(TEST_RUNTIME) $(RUNTIME_FLAGS) $(TEST_HARNESS) -noshadow \
$(vtsdir)/BinarySerializationOverVersions.exe
test: test-vts
run-test: run-test-vts

EXTRA_DISTFILES += \
$(vtsdir)/$(vts)TestLib/1.0/Address.cs \
$(vtsdir)/$(vts)TestLib/2.0/Address.cs \
$(vtsdir)/$(vts)TestLib/3.0/Address.cs \
$(vtsdir)/$(vts)TestLib/4.0/Address.cs \
$(vtsdir)/$(vts)TestLib/5.0/Address.cs \
$(vtsdir)/BinarySerializationOverVersions.cs
# vts = VersionTolerantSerialization
# vtsdir = Test/System.Runtime.Serialization.Formatters.Binary/$(vts)
# test-vts:
# $(MCS) -target:library \
# $(vtsdir)/$(vts)TestLib/1.0/Address.cs
# $(MCS) $(test_nunit_ref) \
# -r:$(vtsdir)/$(vts)TestLib/1.0/Address.dll \
# $(vtsdir)/BinarySerializationOverVersions.cs
# cp $(vtsdir)/$(vts)TestLib/1.0/Address.dll $(vtsdir)
# $(MCS) -target:library \
# $(vtsdir)/$(vts)TestLib/2.0/Address.cs
# $(MCS) -target:library \
# $(vtsdir)/$(vts)TestLib/3.0/Address.cs
# $(MCS) -target:library \
# $(vtsdir)/$(vts)TestLib/4.0/Address.cs
# $(MCS) -target:library \
# $(vtsdir)/$(vts)TestLib/5.0/Address.cs
# $(MCS) -target:library \
# $(vtsdir)/$(vts)TestLib/6.0/Address.cs
# run-test-vts: test-vts
# $(TEST_RUNTIME) $(RUNTIME_FLAGS) $(TEST_HARNESS) -noshadow \
# $(vtsdir)/BinarySerializationOverVersions.exe
# test: test-vts
# run-test: run-test-vts

# EXTRA_DISTFILES += \
# $(vtsdir)/$(vts)TestLib/1.0/Address.cs \
# $(vtsdir)/$(vts)TestLib/2.0/Address.cs \
# $(vtsdir)/$(vts)TestLib/3.0/Address.cs \
# $(vtsdir)/$(vts)TestLib/4.0/Address.cs \
# $(vtsdir)/$(vts)TestLib/5.0/Address.cs \
# $(vtsdir)/BinarySerializationOverVersions.cs
241 changes: 144 additions & 97 deletions mono/metadata/mono-wsq.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,84 @@
#include <mono/metadata/object.h>
#include <mono/metadata/mono-wsq.h>
#include <mono/utils/mono-semaphore.h>
#include <mono/utils/mono-time.h>
#include <glib.h>

#define INITIAL_LENGTH 32
#define WSQ_DEBUG(...)
//#define WSQ_DEBUG(...) g_message(__VA_ARGS__)

#define array_get(_array, _index) mono_array_get((_array), void*, (_index))
#define array_length(_array) ((_array)->max_length)
#define array_clear(_array, _index) mono_array_set ((_array), void *, (_index), NULL);

#define NO_KEY ((guint32) -1)
static guint32 wsq_tlskey = NO_KEY;

/* Macros borrowed from domain.c
* Look there for the rationale behind this
*/
#if (defined(__i386__) || defined(__x86_64__)) && !defined(HOST_WIN32)
#define NO_TLS_SET_VALUE
#endif

#ifdef HAVE_KW_THREAD

static __thread MonoWSQ * tls_local_wsq MONO_TLS_FAST;

#define GET_LOCAL_WSQ() tls_local_wsq

#ifdef NO_TLS_SET_VALUE
#define SET_LOCAL_WSQ(x) do { \
tls_local_wsq = x; \
} while (FALSE)
#else
#define SET_LOCAL_WSQ(x) do { \
tls_local_wsq = x; \
TlsSetValue (wsq_tlskey, x); \
} while (FALSE)
#endif

#else

#define GET_LOCAL_WSQ() ((MonoWSQ *)TlsGetValue (wsq_tlskey))
#define SET_LOCAL_WSQ(x) TlsSetValue (wsq_tlskey, x);

#endif

#if defined(__x86_64__)
typedef gint64 gnative;
#else
typedef gint32 gnative;
#endif

struct _MonoWSQ {
volatile gint head;
volatile gint tail;
gnative top;
gnative bottom;
gnative upper_bound;
MonoArray *queue;
gint32 mask;
MonoSemType lock;
};

#define NO_KEY ((guint32) -1)
static guint32 wsq_tlskey = NO_KEY;
/* Redefine the Interlocked* functions for 64bits
*/
#if defined(__x86_64__)
static inline gint64 NativeInterlockedIncrement(volatile gint64 *val)
{
gint64 tmp;
__asm__ __volatile__ ("lock; xadd %0, %1" : "=r" (tmp), "=m" (*val) : "0" (1), "m" (*val));
return(tmp+1);
}

static inline gint64 NativeInterlockedCompareExchange(volatile gint64 *dest, gint64 exch, gint64 comp)
{
gint64 old;
__asm__ __volatile__ ("lock; cmpxchg %2, %0" : "=m" (*dest), "=a" (old) : "r" (exch), "m" (*dest), "a" (comp));
return (old);
}
#else
#define NativeInterlockedIncrement(addr) InterlockedIncrement(addr)
#define NativeInterlockedCompareExchange(addr, newval, compval) InterlockedCompareExchange(addr, newval, compval)
#endif

void
mono_wsq_init ()
Expand All @@ -52,15 +115,11 @@ mono_wsq_create ()
return NULL;

wsq = g_new0 (MonoWSQ, 1);
wsq->mask = INITIAL_LENGTH - 1;
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)) {
mono_wsq_destroy (wsq);
wsq = NULL;
}
SET_LOCAL_WSQ(wsq);

return wsq;
}

Expand All @@ -72,10 +131,9 @@ mono_wsq_destroy (MonoWSQ *wsq)

g_assert (mono_wsq_count (wsq) == 0);
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 != NO_KEY && GET_LOCAL_WSQ() == wsq)
SET_LOCAL_WSQ (NULL);
g_free (wsq);
}

Expand All @@ -84,126 +142,115 @@ mono_wsq_count (MonoWSQ *wsq)
{
if (!wsq)
return 0;
return ((wsq->tail - wsq->head) & wsq->mask);
return wsq->bottom - wsq->top;
}

gboolean
mono_wsq_local_push (void *obj)
{
int tail;
int head;
int count;
MonoWSQ *wsq;
gnative b;
MonoArray* a;
gint size;

if (obj == NULL || wsq_tlskey == NO_KEY)
return FALSE;

wsq = (MonoWSQ *) TlsGetValue (wsq_tlskey);
if (wsq == NULL) {
WSQ_DEBUG ("local_push: no wsq\n");
wsq = GET_LOCAL_WSQ();
if (wsq == NULL)
return FALSE;
}

tail = wsq->tail;
if (tail < wsq->head + wsq->mask) {
mono_array_setref (wsq->queue, tail & wsq->mask, (MonoObject *) obj);
wsq->tail = tail + 1;
WSQ_DEBUG ("local_push: OK %p %p\n", wsq, obj);
return TRUE;
}
b = wsq->bottom;
a = wsq->queue;
size = array_length (a);

MONO_SEM_WAIT (&wsq->lock);
head = wsq->head;
count = wsq->tail - wsq->head;
if (count >= wsq->mask) {
if (b - wsq->upper_bound >= size - 1) {
MonoArray *new_array;
int length;
gint new_size;
int i;

length = mono_array_length (wsq->queue);
new_array = mono_array_new_cached (mono_get_root_domain (), mono_defaults.object_class, length * 2);
for (i = 0; i < length; i++)
mono_array_setref (new_array, i, mono_array_get (wsq->queue, MonoObject*, (i + head) & wsq->mask));
new_size = size * 2;
new_array = mono_array_new_cached (mono_get_root_domain (), mono_defaults.object_class, new_size);

i = wsq->upper_bound = wsq->top;
for (; i < b; ++i)
mono_array_setref (new_array, i, array_get (a, i % size));

memset (mono_array_addr (wsq->queue, MonoObject *, 0), 0, sizeof (MonoObject*) * length);
wsq->queue = new_array;
wsq->head = 0;
wsq->tail = tail = count;
wsq->mask = (wsq->mask << 1) | 1;
size = new_size;
wsq->queue = a = new_array;
}
mono_array_setref (wsq->queue, tail & wsq->mask, obj);
wsq->tail = tail + 1;
MONO_SEM_POST (&wsq->lock);
WSQ_DEBUG ("local_push: LOCK %p %p\n", wsq, obj);

mono_array_setref (a, b % size, obj);
NativeInterlockedIncrement (&wsq->bottom);

return TRUE;
}

gboolean
mono_wsq_local_pop (void **ptr)
mono_wsq_local_pop (MonoWSQ *wsq, void **ptr)
{
int tail;
gboolean res;
MonoWSQ *wsq;
gnative b, t;
gint size;
gint length;
MonoArray* a;

if (ptr == NULL || wsq_tlskey == NO_KEY)
if (ptr == NULL || wsq == NULL)
return FALSE;
b = --wsq->bottom;
a = wsq->queue;
t = wsq->top;
size = b - t;

wsq = (MonoWSQ *) TlsGetValue (wsq_tlskey);
if (wsq == NULL) {
WSQ_DEBUG ("local_pop: no wsq\n");
if (size < 0) {
wsq->bottom = t;
return FALSE;
}

tail = wsq->tail;
if (wsq->head >= tail) {
WSQ_DEBUG ("local_pop: empty\n");
return FALSE;
}
tail--;
InterlockedExchange (&wsq->tail, tail);
if (wsq->head <= tail) {
*ptr = mono_array_get (wsq->queue, void *, tail & wsq->mask);
mono_array_set (wsq->queue, void *, tail & wsq->mask, NULL);
WSQ_DEBUG ("local_pop: GOT ONE %p %p\n", wsq, *ptr);
length = array_length (a);
*ptr = array_get (a, b % length);
if (size > 0) {
array_clear (a, b % length);
return TRUE;
}

MONO_SEM_WAIT (&wsq->lock);
if (wsq->head <= tail) {
*ptr = mono_array_get (wsq->queue, void *, tail & wsq->mask);
mono_array_set (wsq->queue, void *, tail & wsq->mask, NULL);
res = TRUE;
} else {
wsq->tail = tail + 1;
res = FALSE;
}
MONO_SEM_POST (&wsq->lock);
WSQ_DEBUG ("local_pop: LOCK %d %p %p\n", res, wsq, *ptr);
return res;
wsq->bottom = t + 1;
if (NativeInterlockedCompareExchange (&wsq->top, t + 1, t) != t)
return FALSE;

array_clear (a, b % length);
return TRUE;
}

void
mono_wsq_try_steal (MonoWSQ *wsq, void **ptr, guint32 ms_timeout)
{
if (wsq == NULL || ptr == NULL || *ptr != NULL || wsq_tlskey == NO_KEY)
return;
gnative t, b;
gint size;
MonoArray* a;
guint32 start_ticks = 0;

if (TlsGetValue (wsq_tlskey) == wsq)
if (wsq == NULL || ptr == NULL || *ptr != NULL)
return;

if (mono_sem_timedwait (&wsq->lock, ms_timeout, FALSE) == 0) {
int head;

head = wsq->head;
InterlockedExchange (&wsq->head, head + 1);
if (head < wsq->tail) {
*ptr = mono_array_get (wsq->queue, void *, head & wsq->mask);
mono_array_set (wsq->queue, void *, head & wsq->mask, NULL);
WSQ_DEBUG ("STEAL %p %p\n", wsq, *ptr);
} else {
wsq->head = head;
}
MONO_SEM_POST (&wsq->lock);
}
}
do {
t = wsq->top;
b = wsq->bottom;

if (b - t <= 0)
return;

if (NativeInterlockedCompareExchange (&wsq->top, t + 1, t) == t)
break;

if (start_ticks == 0)
start_ticks = mono_msec_ticks ();

if (!ms_timeout || mono_msec_ticks () - start_ticks < ms_timeout)
return;
} while (TRUE);

a = wsq->queue;
size = array_length (a);
*ptr = array_get (a, t % size);
array_clear (a, t % size);
}
Loading