bd588fc851a823a4720b4976f4800757a690ddb0
[mono.git] / mono / metadata / monitor.c
1 /*
2  * monitor.c:  Monitor locking functions
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * Copyright 2003 Ximian, Inc (http://www.ximian.com)
8  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9  */
10
11 #include <config.h>
12 #include <glib.h>
13 #include <string.h>
14
15 #include <mono/metadata/monitor.h>
16 #include <mono/metadata/threads-types.h>
17 #include <mono/metadata/exception.h>
18 #include <mono/metadata/threads.h>
19 #include <mono/io-layer/io-layer.h>
20 #include <mono/metadata/object-internals.h>
21 #include <mono/metadata/class-internals.h>
22 #include <mono/metadata/gc-internal.h>
23 #include <mono/metadata/method-builder.h>
24 #include <mono/metadata/debug-helpers.h>
25 #include <mono/metadata/tabledefs.h>
26 #include <mono/metadata/marshal.h>
27 #include <mono/metadata/profiler-private.h>
28 #include <mono/utils/mono-time.h>
29 #include <mono/utils/mono-semaphore.h>
30
31 /*
32  * Pull the list of opcodes
33  */
34 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
35         a = i,
36
37 enum {
38 #include "mono/cil/opcode.def"
39         LAST = 0xff
40 };
41 #undef OPDEF
42
43 /*#define LOCK_DEBUG(a) do { a; } while (0)*/
44 #define LOCK_DEBUG(a)
45
46 /*
47  * The monitor implementation here is based on
48  * http://www.usenix.org/events/jvm01/full_papers/dice/dice.pdf and
49  * http://www.research.ibm.com/people/d/dfb/papers/Bacon98Thin.ps
50  *
51  * The Dice paper describes a technique for saving lock record space
52  * by returning records to a free list when they become unused.  That
53  * sounds like unnecessary complexity to me, though if it becomes
54  * clear that unused lock records are taking up lots of space or we
55  * need to shave more time off by avoiding a malloc then we can always
56  * implement the free list idea later.  The timeout parameter to
57  * try_enter voids some of the assumptions about the reference count
58  * field in Dice's implementation too.  In his version, the thread
59  * attempting to lock a contended object will block until it succeeds,
60  * so the reference count will never be decremented while an object is
61  * locked.
62  *
63  * Bacon's thin locks have a fast path that doesn't need a lock record
64  * for the common case of locking an unlocked or shallow-nested
65  * object, but the technique relies on encoding the thread ID in 15
66  * bits (to avoid too much per-object space overhead.)  Unfortunately
67  * I don't think it's possible to reliably encode a pthread_t into 15
68  * bits. (The JVM implementation used seems to have a 15-bit
69  * per-thread identifier available.)
70  *
71  * This implementation then combines Dice's basic lock model with
72  * Bacon's simplification of keeping a lock record for the lifetime of
73  * an object.
74  */
75
76 struct _MonoThreadsSync
77 {
78         gsize owner;                    /* thread ID */
79         guint32 nest;
80 #ifdef HAVE_MOVING_COLLECTOR
81         gint32 hash_code;
82 #endif
83         volatile gint32 entry_count;
84         MonoSemType *entry_sem;
85         GSList *wait_list;
86         void *data;
87 };
88
89 typedef struct _MonitorArray MonitorArray;
90
91 struct _MonitorArray {
92         MonitorArray *next;
93         int num_monitors;
94         MonoThreadsSync monitors [MONO_ZERO_LEN_ARRAY];
95 };
96
97 #define mono_monitor_allocator_lock() EnterCriticalSection (&monitor_mutex)
98 #define mono_monitor_allocator_unlock() LeaveCriticalSection (&monitor_mutex)
99 static CRITICAL_SECTION monitor_mutex;
100 static MonoThreadsSync *monitor_freelist;
101 static MonitorArray *monitor_allocated;
102 static int array_size = 16;
103
104 #ifdef HAVE_KW_THREAD
105 static __thread gsize tls_pthread_self MONO_TLS_FAST;
106 #endif
107
108 #ifndef HOST_WIN32
109 #ifdef HAVE_KW_THREAD
110 #define GetCurrentThreadId() tls_pthread_self
111 #else
112 /* 
113  * The usual problem: we can't replace GetCurrentThreadId () with a macro because
114  * it is in a public header.
115  */
116 #define GetCurrentThreadId() ((gsize)pthread_self ())
117 #endif
118 #endif
119
120 void
121 mono_monitor_init (void)
122 {
123         InitializeCriticalSection (&monitor_mutex);
124 }
125  
126 void
127 mono_monitor_cleanup (void)
128 {
129         MonoThreadsSync *mon;
130         /* MonitorArray *marray, *next = NULL; */
131
132         /*DeleteCriticalSection (&monitor_mutex);*/
133
134         /* The monitors on the freelist don't have weak links - mark them */
135         for (mon = monitor_freelist; mon; mon = mon->data)
136                 mon->wait_list = (gpointer)-1;
137
138         /* FIXME: This still crashes with sgen (async_read.exe) */
139         /*
140         for (marray = monitor_allocated; marray; marray = next) {
141                 int i;
142
143                 for (i = 0; i < marray->num_monitors; ++i) {
144                         mon = &marray->monitors [i];
145                         if (mon->wait_list != (gpointer)-1)
146                                 mono_gc_weak_link_remove (&mon->data);
147                 }
148
149                 next = marray->next;
150                 g_free (marray);
151         }
152         */
153 }
154
155 /*
156  * mono_monitor_init_tls:
157  *
158  *   Setup TLS variables used by the monitor code for the current thread.
159  */
160 void
161 mono_monitor_init_tls (void)
162 {
163 #if !defined(HOST_WIN32) && defined(HAVE_KW_THREAD)
164         tls_pthread_self = pthread_self ();
165 #endif
166 }
167
168 static int
169 monitor_is_on_freelist (MonoThreadsSync *mon)
170 {
171         MonitorArray *marray;
172         for (marray = monitor_allocated; marray; marray = marray->next) {
173                 if (mon >= marray->monitors && mon < &marray->monitors [marray->num_monitors])
174                         return TRUE;
175         }
176         return FALSE;
177 }
178
179 /**
180  * mono_locks_dump:
181  * @include_untaken:
182  *
183  * Print a report on stdout of the managed locks currently held by
184  * threads. If @include_untaken is specified, list also inflated locks
185  * which are unheld.
186  * This is supposed to be used in debuggers like gdb.
187  */
188 void
189 mono_locks_dump (gboolean include_untaken)
190 {
191         int i;
192         int used = 0, on_freelist = 0, to_recycle = 0, total = 0, num_arrays = 0;
193         MonoThreadsSync *mon;
194         MonitorArray *marray;
195         for (mon = monitor_freelist; mon; mon = mon->data)
196                 on_freelist++;
197         for (marray = monitor_allocated; marray; marray = marray->next) {
198                 total += marray->num_monitors;
199                 num_arrays++;
200                 for (i = 0; i < marray->num_monitors; ++i) {
201                         mon = &marray->monitors [i];
202                         if (mon->data == NULL) {
203                                 if (i < marray->num_monitors - 1)
204                                         to_recycle++;
205                         } else {
206                                 if (!monitor_is_on_freelist (mon->data)) {
207                                         MonoObject *holder = mono_gc_weak_link_get (&mon->data);
208                                         if (mon->owner) {
209                                                 g_print ("Lock %p in object %p held by thread %p, nest level: %d\n",
210                                                         mon, holder, (void*)mon->owner, mon->nest);
211                                                 if (mon->entry_sem)
212                                                         g_print ("\tWaiting on semaphore %p: %d\n", mon->entry_sem, mon->entry_count);
213                                         } else if (include_untaken) {
214                                                 g_print ("Lock %p in object %p untaken\n", mon, holder);
215                                         }
216                                         used++;
217                                 }
218                         }
219                 }
220         }
221         g_print ("Total locks (in %d array(s)): %d, used: %d, on freelist: %d, to recycle: %d\n",
222                 num_arrays, total, used, on_freelist, to_recycle);
223 }
224
225 /* LOCKING: this is called with monitor_mutex held */
226 static void 
227 mon_finalize (MonoThreadsSync *mon)
228 {
229         LOCK_DEBUG (g_message ("%s: Finalizing sync %p", __func__, mon));
230
231         if (mon->entry_sem != NULL) {
232                 MONO_SEM_DESTROY (mon->entry_sem);
233                 g_free (mon->entry_sem);
234                 mon->entry_sem = NULL;
235         }
236         /* If this isn't empty then something is seriously broken - it
237          * means a thread is still waiting on the object that owned
238          * this lock, but the object has been finalized.
239          */
240         g_assert (mon->wait_list == NULL);
241
242         mon->entry_count = 0;
243         /* owner and nest are set in mon_new, no need to zero them out */
244
245         mon->data = monitor_freelist;
246         monitor_freelist = mon;
247         mono_perfcounters->gc_sync_blocks--;
248 }
249
250 /* LOCKING: this is called with monitor_mutex held */
251 static MonoThreadsSync *
252 mon_new (gsize id)
253 {
254         MonoThreadsSync *new;
255
256         if (!monitor_freelist) {
257                 MonitorArray *marray;
258                 int i;
259                 /* see if any sync block has been collected */
260                 new = NULL;
261                 for (marray = monitor_allocated; marray; marray = marray->next) {
262                         for (i = 0; i < marray->num_monitors; ++i) {
263                                 if (marray->monitors [i].data == NULL) {
264                                         new = &marray->monitors [i];
265                                         if (new->wait_list) {
266                                                 /* Orphaned events left by aborted threads */
267                                                 while (new->wait_list) {
268                                                         LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d): Closing orphaned event %d", GetCurrentThreadId (), new->wait_list->data));
269                                                         CloseHandle (new->wait_list->data);
270                                                         new->wait_list = g_slist_remove (new->wait_list, new->wait_list->data);
271                                                 }
272                                         }
273                                         mono_gc_weak_link_remove (&new->data);
274                                         new->data = monitor_freelist;
275                                         monitor_freelist = new;
276                                 }
277                         }
278                         /* small perf tweak to avoid scanning all the blocks */
279                         if (new)
280                                 break;
281                 }
282                 /* need to allocate a new array of monitors */
283                 if (!monitor_freelist) {
284                         MonitorArray *last;
285                         LOCK_DEBUG (g_message ("%s: allocating more monitors: %d", __func__, array_size));
286                         marray = g_malloc0 (sizeof (MonoArray) + array_size * sizeof (MonoThreadsSync));
287                         marray->num_monitors = array_size;
288                         array_size *= 2;
289                         /* link into the freelist */
290                         for (i = 0; i < marray->num_monitors - 1; ++i) {
291                                 marray->monitors [i].data = &marray->monitors [i + 1];
292                         }
293                         marray->monitors [i].data = NULL; /* the last one */
294                         monitor_freelist = &marray->monitors [0];
295                         /* we happend the marray instead of prepending so that
296                          * the collecting loop above will need to scan smaller arrays first
297                          */
298                         if (!monitor_allocated) {
299                                 monitor_allocated = marray;
300                         } else {
301                                 last = monitor_allocated;
302                                 while (last->next)
303                                         last = last->next;
304                                 last->next = marray;
305                         }
306                 }
307         }
308
309         new = monitor_freelist;
310         monitor_freelist = new->data;
311
312         new->owner = id;
313         new->nest = 1;
314         
315         mono_perfcounters->gc_sync_blocks++;
316         return new;
317 }
318
319 /*
320  * Format of the lock word:
321  * thinhash | fathash | data
322  *
323  * thinhash is the lower bit: if set data is the shifted hashcode of the object.
324  * fathash is another bit: if set the hash code is stored in the MonoThreadsSync
325  *   struct pointed to by data
326  * if neither bit is set and data is non-NULL, data is a MonoThreadsSync
327  */
328 typedef union {
329         gsize lock_word;
330         MonoThreadsSync *sync;
331 } LockWord;
332
333 enum {
334         LOCK_WORD_THIN_HASH = 1,
335         LOCK_WORD_FAT_HASH = 1 << 1,
336         LOCK_WORD_BITS_MASK = 0x3,
337         LOCK_WORD_HASH_SHIFT = 2
338 };
339
340 #define MONO_OBJECT_ALIGNMENT_SHIFT     3
341
342 /*
343  * mono_object_hash:
344  * @obj: an object
345  *
346  * Calculate a hash code for @obj that is constant while @obj is alive.
347  */
348 int
349 mono_object_hash (MonoObject* obj)
350 {
351 #ifdef HAVE_MOVING_COLLECTOR
352         LockWord lw;
353         unsigned int hash;
354         if (!obj)
355                 return 0;
356         lw.sync = obj->synchronisation;
357         if (lw.lock_word & LOCK_WORD_THIN_HASH) {
358                 /*g_print ("fast thin hash %d for obj %p store\n", (unsigned int)lw.lock_word >> LOCK_WORD_HASH_SHIFT, obj);*/
359                 return (unsigned int)lw.lock_word >> LOCK_WORD_HASH_SHIFT;
360         }
361         if (lw.lock_word & LOCK_WORD_FAT_HASH) {
362                 lw.lock_word &= ~LOCK_WORD_BITS_MASK;
363                 /*g_print ("fast fat hash %d for obj %p store\n", lw.sync->hash_code, obj);*/
364                 return lw.sync->hash_code;
365         }
366         /*
367          * while we are inside this function, the GC will keep this object pinned,
368          * since we are in the unmanaged stack. Thanks to this and to the hash
369          * function that depends only on the address, we can ignore the races if
370          * another thread computes the hash at the same time, because it'll end up
371          * with the same value.
372          */
373         hash = (GPOINTER_TO_UINT (obj) >> MONO_OBJECT_ALIGNMENT_SHIFT) * 2654435761u;
374         /* clear the top bits as they can be discarded */
375         hash &= ~(LOCK_WORD_BITS_MASK << 30);
376         /* no hash flags were set, so it must be a MonoThreadsSync pointer if not NULL */
377         if (lw.sync) {
378                 lw.sync->hash_code = hash;
379                 /*g_print ("storing hash code %d for obj %p in sync %p\n", hash, obj, lw.sync);*/
380                 lw.lock_word |= LOCK_WORD_FAT_HASH;
381                 /* this is safe since we don't deflate locks */
382                 obj->synchronisation = lw.sync;
383         } else {
384                 /*g_print ("storing thin hash code %d for obj %p\n", hash, obj);*/
385                 lw.lock_word = LOCK_WORD_THIN_HASH | (hash << LOCK_WORD_HASH_SHIFT);
386                 if (InterlockedCompareExchangePointer ((gpointer*)&obj->synchronisation, lw.sync, NULL) == NULL)
387                         return hash;
388                 /*g_print ("failed store\n");*/
389                 /* someone set the hash flag or someone inflated the object */
390                 lw.sync = obj->synchronisation;
391                 if (lw.lock_word & LOCK_WORD_THIN_HASH)
392                         return hash;
393                 lw.lock_word &= ~LOCK_WORD_BITS_MASK;
394                 lw.sync->hash_code = hash;
395                 lw.lock_word |= LOCK_WORD_FAT_HASH;
396                 /* this is safe since we don't deflate locks */
397                 obj->synchronisation = lw.sync;
398         }
399         return hash;
400 #else
401 /*
402  * Wang's address-based hash function:
403  *   http://www.concentric.net/~Ttwang/tech/addrhash.htm
404  */
405         return (GPOINTER_TO_UINT (obj) >> MONO_OBJECT_ALIGNMENT_SHIFT) * 2654435761u;
406 #endif
407 }
408
409 /* If allow_interruption==TRUE, the method will be interrumped if abort or suspend
410  * is requested. In this case it returns -1.
411  */ 
412 static inline gint32 
413 mono_monitor_try_enter_internal (MonoObject *obj, guint32 ms, gboolean allow_interruption)
414 {
415         MonoThreadsSync *mon;
416         gsize id = GetCurrentThreadId ();
417         MonoSemType *sem;
418         guint32 then = 0, now, delta;
419         guint32 waitms;
420         guint32 ret;
421         MonoInternalThread *thread;
422
423         LOCK_DEBUG (g_message("%s: (%d) Trying to lock object %p (%d ms)", __func__, id, obj, ms));
424
425         if (G_UNLIKELY (!obj)) {
426                 mono_raise_exception (mono_get_exception_argument_null ("obj"));
427                 return FALSE;
428         }
429
430 retry:
431         mon = obj->synchronisation;
432
433         /* If the object has never been locked... */
434         if (G_UNLIKELY (mon == NULL)) {
435                 mono_monitor_allocator_lock ();
436                 mon = mon_new (id);
437                 if (InterlockedCompareExchangePointer ((gpointer*)&obj->synchronisation, mon, NULL) == NULL) {
438                         mono_gc_weak_link_add (&mon->data, obj, FALSE);
439                         mono_monitor_allocator_unlock ();
440                         /* Successfully locked */
441                         return 1;
442                 } else {
443 #ifdef HAVE_MOVING_COLLECTOR
444                         LockWord lw;
445                         lw.sync = obj->synchronisation;
446                         if (lw.lock_word & LOCK_WORD_THIN_HASH) {
447                                 MonoThreadsSync *oldlw = lw.sync;
448                                 /* move the already calculated hash */
449                                 mon->hash_code = lw.lock_word >> LOCK_WORD_HASH_SHIFT;
450                                 lw.sync = mon;
451                                 lw.lock_word |= LOCK_WORD_FAT_HASH;
452                                 if (InterlockedCompareExchangePointer ((gpointer*)&obj->synchronisation, lw.sync, oldlw) == oldlw) {
453                                         mono_gc_weak_link_add (&mon->data, obj, FALSE);
454                                         mono_monitor_allocator_unlock ();
455                                         /* Successfully locked */
456                                         return 1;
457                                 } else {
458                                         mon_finalize (mon);
459                                         mono_monitor_allocator_unlock ();
460                                         goto retry;
461                                 }
462                         } else if (lw.lock_word & LOCK_WORD_FAT_HASH) {
463                                 mon_finalize (mon);
464                                 mono_monitor_allocator_unlock ();
465                                 /* get the old lock without the fat hash bit */
466                                 lw.lock_word &= ~LOCK_WORD_BITS_MASK;
467                                 mon = lw.sync;
468                         } else {
469                                 mon_finalize (mon);
470                                 mono_monitor_allocator_unlock ();
471                                 mon = obj->synchronisation;
472                         }
473 #else
474                         mon_finalize (mon);
475                         mono_monitor_allocator_unlock ();
476                         mon = obj->synchronisation;
477 #endif
478                 }
479         } else {
480 #ifdef HAVE_MOVING_COLLECTOR
481                 LockWord lw;
482                 lw.sync = mon;
483                 if (lw.lock_word & LOCK_WORD_THIN_HASH) {
484                         MonoThreadsSync *oldlw = lw.sync;
485                         mono_monitor_allocator_lock ();
486                         mon = mon_new (id);
487                         /* move the already calculated hash */
488                         mon->hash_code = lw.lock_word >> LOCK_WORD_HASH_SHIFT;
489                         lw.sync = mon;
490                         lw.lock_word |= LOCK_WORD_FAT_HASH;
491                         if (InterlockedCompareExchangePointer ((gpointer*)&obj->synchronisation, lw.sync, oldlw) == oldlw) {
492                                 mono_gc_weak_link_add (&mon->data, obj, TRUE);
493                                 mono_monitor_allocator_unlock ();
494                                 /* Successfully locked */
495                                 return 1;
496                         } else {
497                                 mon_finalize (mon);
498                                 mono_monitor_allocator_unlock ();
499                                 goto retry;
500                         }
501                 }
502 #endif
503         }
504
505 #ifdef HAVE_MOVING_COLLECTOR
506         {
507                 LockWord lw;
508                 lw.sync = mon;
509                 lw.lock_word &= ~LOCK_WORD_BITS_MASK;
510                 mon = lw.sync;
511         }
512 #endif
513
514         /* If the object has previously been locked but isn't now... */
515
516         /* This case differs from Dice's case 3 because we don't
517          * deflate locks or cache unused lock records
518          */
519         if (G_LIKELY (mon->owner == 0)) {
520                 /* Try to install our ID in the owner field, nest
521                  * should have been left at 1 by the previous unlock
522                  * operation
523                  */
524                 if (G_LIKELY (InterlockedCompareExchangePointer ((gpointer *)&mon->owner, (gpointer)id, 0) == 0)) {
525                         /* Success */
526                         g_assert (mon->nest == 1);
527                         return 1;
528                 } else {
529                         /* Trumped again! */
530                         goto retry;
531                 }
532         }
533
534         /* If the object is currently locked by this thread... */
535         if (mon->owner == id) {
536                 mon->nest++;
537                 return 1;
538         }
539
540         /* The object must be locked by someone else... */
541         mono_perfcounters->thread_contentions++;
542
543         /* If ms is 0 we don't block, but just fail straight away */
544         if (ms == 0) {
545                 LOCK_DEBUG (g_message ("%s: (%d) timed out, returning FALSE", __func__, id));
546                 return 0;
547         }
548
549         mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_CONTENTION);
550
551         /* The slow path begins here. */
552 retry_contended:
553         /* a small amount of duplicated code, but it allows us to insert the profiler
554          * callbacks without impacting the fast path: from here on we don't need to go back to the
555          * retry label, but to retry_contended. At this point mon is already installed in the object
556          * header.
557          */
558         /* This case differs from Dice's case 3 because we don't
559          * deflate locks or cache unused lock records
560          */
561         if (G_LIKELY (mon->owner == 0)) {
562                 /* Try to install our ID in the owner field, nest
563                 * should have been left at 1 by the previous unlock
564                 * operation
565                 */
566                 if (G_LIKELY (InterlockedCompareExchangePointer ((gpointer *)&mon->owner, (gpointer)id, 0) == 0)) {
567                         /* Success */
568                         g_assert (mon->nest == 1);
569                         mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_DONE);
570                         return 1;
571                 }
572         }
573
574         /* If the object is currently locked by this thread... */
575         if (mon->owner == id) {
576                 mon->nest++;
577                 mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_DONE);
578                 return 1;
579         }
580
581         /* We need to make sure there's a semaphore handle (creating it if
582          * necessary), and block on it
583          */
584         if (mon->entry_sem == NULL) {
585                 /* Create the semaphore */
586                 sem = g_new0 (MonoSemType, 1);
587                 MONO_SEM_INIT (sem, 0);
588                 g_assert (sem != NULL);
589                 if (InterlockedCompareExchangePointer ((gpointer*)&mon->entry_sem, sem, NULL) != NULL) {
590                         /* Someone else just put a handle here */
591                         MONO_SEM_DESTROY (sem);
592                         g_free (sem);
593                 }
594         }
595         
596         /* If we need to time out, record a timestamp and adjust ms,
597          * because WaitForSingleObject doesn't tell us how long it
598          * waited for.
599          *
600          * Don't block forever here, because theres a chance the owner
601          * thread released the lock while we were creating the
602          * semaphore: we would not get the wakeup.  Using the event
603          * handle technique from pulse/wait would involve locking the
604          * lock struct and therefore slowing down the fast path.
605          */
606         if (ms != INFINITE) {
607                 then = mono_msec_ticks ();
608                 if (ms < 100) {
609                         waitms = ms;
610                 } else {
611                         waitms = 100;
612                 }
613         } else {
614                 waitms = 100;
615         }
616         
617         InterlockedIncrement (&mon->entry_count);
618
619         mono_perfcounters->thread_queue_len++;
620         mono_perfcounters->thread_queue_max++;
621         thread = mono_thread_internal_current ();
622
623         mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
624
625         /*
626          * We pass TRUE instead of allow_interruption since we have to check for the
627          * StopRequested case below.
628          */
629         ret = MONO_SEM_TIMEDWAIT_ALERTABLE(mon->entry_sem, waitms, TRUE);
630
631         mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
632         
633         InterlockedDecrement (&mon->entry_count);
634         mono_perfcounters->thread_queue_len--;
635
636         if (ms != INFINITE) {
637                 now = mono_msec_ticks ();
638                 
639                 if (now < then) {
640                         /* The counter must have wrapped around */
641                         LOCK_DEBUG (g_message ("%s: wrapped around! now=0x%x then=0x%x", __func__, now, then));
642                         
643                         now += (0xffffffff - then);
644                         then = 0;
645
646                         LOCK_DEBUG (g_message ("%s: wrap rejig: now=0x%x then=0x%x delta=0x%x", __func__, now, then, now-then));
647                 }
648                 
649                 delta = now - then;
650                 if (delta >= ms) {
651                         ms = 0;
652                 } else {
653                         ms -= delta;
654                 }
655
656                 if ((ret == WAIT_TIMEOUT || (ret == WAIT_IO_COMPLETION && !allow_interruption)) && ms > 0) {
657                         /* More time left */
658                         goto retry_contended;
659                 }
660         } else {
661                 if (ret == WAIT_TIMEOUT || (ret == WAIT_IO_COMPLETION && !allow_interruption)) {
662                         if (ret == WAIT_IO_COMPLETION && (mono_thread_test_state (mono_thread_internal_current (), (ThreadState_StopRequested|ThreadState_SuspendRequested)))) {
663                                 /* 
664                                  * We have to obey a stop/suspend request even if 
665                                  * allow_interruption is FALSE to avoid hangs at shutdown.
666                                  */
667                                 mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_FAIL);
668                                 return -1;
669                         }
670                         /* Infinite wait, so just try again */
671                         goto retry_contended;
672                 }
673         }
674         
675         if (ret == WAIT_OBJECT_0) {
676                 /* retry from the top */
677                 goto retry_contended;
678         }
679
680         /* We must have timed out */
681         LOCK_DEBUG (g_message ("%s: (%d) timed out waiting, returning FALSE", __func__, id));
682
683         mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_FAIL);
684
685         if (ret == WAIT_IO_COMPLETION)
686                 return -1;
687         else 
688                 return 0;
689 }
690
691 gboolean 
692 mono_monitor_enter (MonoObject *obj)
693 {
694         return mono_monitor_try_enter_internal (obj, INFINITE, FALSE) == 1;
695 }
696
697 gboolean 
698 mono_monitor_try_enter (MonoObject *obj, guint32 ms)
699 {
700         return mono_monitor_try_enter_internal (obj, ms, FALSE) == 1;
701 }
702
703 void
704 mono_monitor_exit (MonoObject *obj)
705 {
706         MonoThreadsSync *mon;
707         guint32 nest;
708         
709         LOCK_DEBUG (g_message ("%s: (%d) Unlocking %p", __func__, GetCurrentThreadId (), obj));
710
711         if (G_UNLIKELY (!obj)) {
712                 mono_raise_exception (mono_get_exception_argument_null ("obj"));
713                 return;
714         }
715
716         mon = obj->synchronisation;
717
718 #ifdef HAVE_MOVING_COLLECTOR
719         {
720                 LockWord lw;
721                 lw.sync = mon;
722                 if (lw.lock_word & LOCK_WORD_THIN_HASH)
723                         return;
724                 lw.lock_word &= ~LOCK_WORD_BITS_MASK;
725                 mon = lw.sync;
726         }
727 #endif
728         if (G_UNLIKELY (mon == NULL)) {
729                 /* No one ever used Enter. Just ignore the Exit request as MS does */
730                 return;
731         }
732         if (G_UNLIKELY (mon->owner != GetCurrentThreadId ())) {
733                 return;
734         }
735         
736         nest = mon->nest - 1;
737         if (nest == 0) {
738                 LOCK_DEBUG (g_message ("%s: (%d) Object %p is now unlocked", __func__, GetCurrentThreadId (), obj));
739         
740                 /* object is now unlocked, leave nest==1 so we don't
741                  * need to set it when the lock is reacquired
742                  */
743                 mon->owner = 0;
744
745                 /* Do the wakeup stuff.  It's possible that the last
746                  * blocking thread gave up waiting just before we
747                  * release the semaphore resulting in a futile wakeup
748                  * next time there's contention for this object, but
749                  * it means we don't have to waste time locking the
750                  * struct.
751                  */
752                 if (mon->entry_count > 0) {
753                         MONO_SEM_POST (mon->entry_sem);
754                 }
755         } else {
756                 LOCK_DEBUG (g_message ("%s: (%d) Object %p is now locked %d times", __func__, GetCurrentThreadId (), obj, nest));
757                 mon->nest = nest;
758         }
759 }
760
761 void**
762 mono_monitor_get_object_monitor_weak_link (MonoObject *object)
763 {
764         LockWord lw;
765         MonoThreadsSync *sync = NULL;
766
767         lw.sync = object->synchronisation;
768         if (lw.lock_word & LOCK_WORD_FAT_HASH) {
769                 lw.lock_word &= ~LOCK_WORD_BITS_MASK;
770                 sync = lw.sync;
771         } else if (!(lw.lock_word & LOCK_WORD_THIN_HASH)) {
772                 sync = lw.sync;
773         }
774
775         if (sync && sync->data)
776                 return &sync->data;
777         return NULL;
778 }
779
780 static void
781 emit_obj_syncp_check (MonoMethodBuilder *mb, int syncp_loc, int *obj_null_branch, int *syncp_true_false_branch,
782         gboolean branch_on_true)
783 {
784         /*
785           ldarg         0                                                       obj
786           brfalse.s     obj_null
787         */
788
789         mono_mb_emit_byte (mb, CEE_LDARG_0);
790         *obj_null_branch = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
791
792         /*
793           ldarg         0                                                       obj
794           conv.i                                                                objp
795           ldc.i4        G_STRUCT_OFFSET(MonoObject, synchronisation)            objp off
796           add                                                                   &syncp
797           ldind.i                                                               syncp
798           stloc         syncp
799           ldloc         syncp                                                   syncp
800           brtrue/false.s        syncp_true_false
801         */
802
803         mono_mb_emit_byte (mb, CEE_LDARG_0);
804         mono_mb_emit_byte (mb, CEE_CONV_I);
805         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoObject, synchronisation));
806         mono_mb_emit_byte (mb, CEE_ADD);
807         mono_mb_emit_byte (mb, CEE_LDIND_I);
808         mono_mb_emit_stloc (mb, syncp_loc);
809         mono_mb_emit_ldloc (mb, syncp_loc);
810         *syncp_true_false_branch = mono_mb_emit_short_branch (mb, branch_on_true ? CEE_BRTRUE_S : CEE_BRFALSE_S);
811 }
812
813 static MonoMethod*
814 mono_monitor_get_fast_enter_method (MonoMethod *monitor_enter_method)
815 {
816         static MonoMethod *fast_monitor_enter;
817         static MonoMethod *compare_exchange_method;
818
819         MonoMethodBuilder *mb;
820         int obj_null_branch, syncp_null_branch, has_owner_branch, other_owner_branch, tid_branch;
821         int tid_loc, syncp_loc, owner_loc;
822         int thread_tls_offset;
823
824 #ifdef HAVE_MOVING_COLLECTOR
825         return NULL;
826 #endif
827
828         thread_tls_offset = mono_thread_get_tls_offset ();
829         if (thread_tls_offset == -1)
830                 return NULL;
831
832         if (fast_monitor_enter)
833                 return fast_monitor_enter;
834
835         if (!compare_exchange_method) {
836                 MonoMethodDesc *desc;
837                 MonoClass *class;
838
839                 desc = mono_method_desc_new ("Interlocked:CompareExchange(intptr&,intptr,intptr)", FALSE);
840                 class = mono_class_from_name (mono_defaults.corlib, "System.Threading", "Interlocked");
841                 compare_exchange_method = mono_method_desc_search_in_class (desc, class);
842                 mono_method_desc_free (desc);
843
844                 if (!compare_exchange_method)
845                         return NULL;
846         }
847
848         mb = mono_mb_new (mono_defaults.monitor_class, "FastMonitorEnter", MONO_WRAPPER_UNKNOWN);
849
850         mb->method->slot = -1;
851         mb->method->flags = METHOD_ATTRIBUTE_PUBLIC | METHOD_ATTRIBUTE_STATIC |
852                 METHOD_ATTRIBUTE_HIDE_BY_SIG | METHOD_ATTRIBUTE_FINAL;
853
854         tid_loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
855         syncp_loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
856         owner_loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
857
858         emit_obj_syncp_check (mb, syncp_loc, &obj_null_branch, &syncp_null_branch, FALSE);
859
860         /*
861           mono. tls     thread_tls_offset                                       threadp
862           ldc.i4        G_STRUCT_OFFSET(MonoThread, tid)                        threadp off
863           add                                                                   &tid
864           ldind.i                                                               tid
865           stloc         tid
866           ldloc         syncp                                                   syncp
867           ldc.i4        G_STRUCT_OFFSET(MonoThreadsSync, owner)                 syncp off
868           add                                                                   &owner
869           ldind.i                                                               owner
870           stloc         owner
871           ldloc         owner                                                   owner
872           brtrue.s      tid
873         */
874
875         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
876         mono_mb_emit_byte (mb, CEE_MONO_TLS);
877         mono_mb_emit_i4 (mb, thread_tls_offset);
878         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoInternalThread, tid));
879         mono_mb_emit_byte (mb, CEE_ADD);
880         mono_mb_emit_byte (mb, CEE_LDIND_I);
881         mono_mb_emit_stloc (mb, tid_loc);
882         mono_mb_emit_ldloc (mb, syncp_loc);
883         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoThreadsSync, owner));
884         mono_mb_emit_byte (mb, CEE_ADD);
885         mono_mb_emit_byte (mb, CEE_LDIND_I);
886         mono_mb_emit_stloc (mb, owner_loc);
887         mono_mb_emit_ldloc (mb, owner_loc);
888         tid_branch = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
889
890         /*
891           ldloc         syncp                                                   syncp
892           ldc.i4        G_STRUCT_OFFSET(MonoThreadsSync, owner)                 syncp off
893           add                                                                   &owner
894           ldloc         tid                                                     &owner tid
895           ldc.i4        0                                                       &owner tid 0
896           call          System.Threading.Interlocked.CompareExchange            oldowner
897           brtrue.s      has_owner
898           ret
899         */
900
901         mono_mb_emit_ldloc (mb, syncp_loc);
902         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoThreadsSync, owner));
903         mono_mb_emit_byte (mb, CEE_ADD);
904         mono_mb_emit_ldloc (mb, tid_loc);
905         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
906         mono_mb_emit_managed_call (mb, compare_exchange_method, NULL);
907         has_owner_branch = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
908         mono_mb_emit_byte (mb, CEE_RET);
909
910         /*
911          tid:
912           ldloc         owner                                                   owner
913           ldloc         tid                                                     owner tid
914           brne.s        other_owner
915           ldloc         syncp                                                   syncp
916           ldc.i4        G_STRUCT_OFFSET(MonoThreadsSync, nest)                  syncp off
917           add                                                                   &nest
918           dup                                                                   &nest &nest
919           ldind.i4                                                              &nest nest
920           ldc.i4        1                                                       &nest nest 1
921           add                                                                   &nest nest+
922           stind.i4
923           ret
924         */
925
926         mono_mb_patch_short_branch (mb, tid_branch);
927         mono_mb_emit_ldloc (mb, owner_loc);
928         mono_mb_emit_ldloc (mb, tid_loc);
929         other_owner_branch = mono_mb_emit_short_branch (mb, CEE_BNE_UN_S);
930         mono_mb_emit_ldloc (mb, syncp_loc);
931         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoThreadsSync, nest));
932         mono_mb_emit_byte (mb, CEE_ADD);
933         mono_mb_emit_byte (mb, CEE_DUP);
934         mono_mb_emit_byte (mb, CEE_LDIND_I4);
935         mono_mb_emit_byte (mb, CEE_LDC_I4_1);
936         mono_mb_emit_byte (mb, CEE_ADD);
937         mono_mb_emit_byte (mb, CEE_STIND_I4);
938         mono_mb_emit_byte (mb, CEE_RET);
939
940         /*
941          obj_null, syncp_null, has_owner, other_owner:
942           ldarg         0                                                       obj
943           call          System.Threading.Monitor.Enter
944           ret
945         */
946
947         mono_mb_patch_short_branch (mb, obj_null_branch);
948         mono_mb_patch_short_branch (mb, syncp_null_branch);
949         mono_mb_patch_short_branch (mb, has_owner_branch);
950         mono_mb_patch_short_branch (mb, other_owner_branch);
951         mono_mb_emit_byte (mb, CEE_LDARG_0);
952         mono_mb_emit_managed_call (mb, monitor_enter_method, NULL);
953         mono_mb_emit_byte (mb, CEE_RET);
954
955         fast_monitor_enter = mono_mb_create_method (mb, mono_signature_no_pinvoke (monitor_enter_method), 5);
956         mono_mb_free (mb);
957
958         return fast_monitor_enter;
959 }
960
961 static MonoMethod*
962 mono_monitor_get_fast_exit_method (MonoMethod *monitor_exit_method)
963 {
964         static MonoMethod *fast_monitor_exit;
965
966         MonoMethodBuilder *mb;
967         int obj_null_branch, has_waiting_branch, has_syncp_branch, owned_branch, nested_branch;
968         int thread_tls_offset;
969         int syncp_loc;
970
971 #ifdef HAVE_MOVING_COLLECTOR
972         return NULL;
973 #endif
974
975         thread_tls_offset = mono_thread_get_tls_offset ();
976         if (thread_tls_offset == -1)
977                 return NULL;
978
979         if (fast_monitor_exit)
980                 return fast_monitor_exit;
981
982         mb = mono_mb_new (mono_defaults.monitor_class, "FastMonitorExit", MONO_WRAPPER_UNKNOWN);
983
984         mb->method->slot = -1;
985         mb->method->flags = METHOD_ATTRIBUTE_PUBLIC | METHOD_ATTRIBUTE_STATIC |
986                 METHOD_ATTRIBUTE_HIDE_BY_SIG | METHOD_ATTRIBUTE_FINAL;
987
988         syncp_loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
989
990         emit_obj_syncp_check (mb, syncp_loc, &obj_null_branch, &has_syncp_branch, TRUE);
991
992         /*
993           ret
994         */
995
996         mono_mb_emit_byte (mb, CEE_RET);
997
998         /*
999          has_syncp:
1000           ldloc         syncp                                                   syncp
1001           ldc.i4        G_STRUCT_OFFSET(MonoThreadsSync, owner)                 syncp off
1002           add                                                                   &owner
1003           ldind.i                                                               owner
1004           mono. tls     thread_tls_offset                                       owner threadp
1005           ldc.i4        G_STRUCT_OFFSET(MonoThread, tid)                        owner threadp off
1006           add                                                                   owner &tid
1007           ldind.i                                                               owner tid
1008           beq.s         owned
1009         */
1010
1011         mono_mb_patch_short_branch (mb, has_syncp_branch);
1012         mono_mb_emit_ldloc (mb, syncp_loc);
1013         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoThreadsSync, owner));
1014         mono_mb_emit_byte (mb, CEE_ADD);
1015         mono_mb_emit_byte (mb, CEE_LDIND_I);
1016         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1017         mono_mb_emit_byte (mb, CEE_MONO_TLS);
1018         mono_mb_emit_i4 (mb, thread_tls_offset);
1019         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoInternalThread, tid));
1020         mono_mb_emit_byte (mb, CEE_ADD);
1021         mono_mb_emit_byte (mb, CEE_LDIND_I);
1022         owned_branch = mono_mb_emit_short_branch (mb, CEE_BEQ_S);
1023
1024         /*
1025           ret
1026         */
1027
1028         mono_mb_emit_byte (mb, CEE_RET);
1029
1030         /*
1031          owned:
1032           ldloc         syncp                                                   syncp
1033           ldc.i4        G_STRUCT_OFFSET(MonoThreadsSync, nest)                  syncp off
1034           add                                                                   &nest
1035           dup                                                                   &nest &nest
1036           ldind.i4                                                              &nest nest
1037           dup                                                                   &nest nest nest
1038           ldc.i4        1                                                       &nest nest nest 1
1039           bgt.un.s      nested                                                  &nest nest
1040         */
1041
1042         mono_mb_patch_short_branch (mb, owned_branch);
1043         mono_mb_emit_ldloc (mb, syncp_loc);
1044         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoThreadsSync, nest));
1045         mono_mb_emit_byte (mb, CEE_ADD);
1046         mono_mb_emit_byte (mb, CEE_DUP);
1047         mono_mb_emit_byte (mb, CEE_LDIND_I4);
1048         mono_mb_emit_byte (mb, CEE_DUP);
1049         mono_mb_emit_byte (mb, CEE_LDC_I4_1);
1050         nested_branch = mono_mb_emit_short_branch (mb, CEE_BGT_UN_S);
1051
1052         /*
1053           pop                                                                   &nest
1054           pop
1055           ldloc         syncp                                                   syncp
1056           ldc.i4        G_STRUCT_OFFSET(MonoThreadsSync, entry_count)           syncp off
1057           add                                                                   &count
1058           ldind.i4                                                              count
1059           brtrue.s      has_waiting
1060         */
1061
1062         mono_mb_emit_byte (mb, CEE_POP);
1063         mono_mb_emit_byte (mb, CEE_POP);
1064         mono_mb_emit_ldloc (mb, syncp_loc);
1065         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoThreadsSync, entry_count));
1066         mono_mb_emit_byte (mb, CEE_ADD);
1067         mono_mb_emit_byte (mb, CEE_LDIND_I4);
1068         has_waiting_branch = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1069
1070         /*
1071           ldloc         syncp                                                   syncp
1072           ldc.i4        G_STRUCT_OFFSET(MonoThreadsSync, owner)                 syncp off
1073           add                                                                   &owner
1074           ldnull                                                                &owner 0
1075           stind.i
1076           ret
1077         */
1078
1079         mono_mb_emit_ldloc (mb, syncp_loc);
1080         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoThreadsSync, owner));
1081         mono_mb_emit_byte (mb, CEE_ADD);
1082         mono_mb_emit_byte (mb, CEE_LDNULL);
1083         mono_mb_emit_byte (mb, CEE_STIND_I);
1084         mono_mb_emit_byte (mb, CEE_RET);
1085
1086         /*
1087          nested:
1088           ldc.i4        1                                                       &nest nest 1
1089           sub                                                                   &nest nest-
1090           stind.i4
1091           ret
1092         */
1093
1094         mono_mb_patch_short_branch (mb, nested_branch);
1095         mono_mb_emit_byte (mb, CEE_LDC_I4_1);
1096         mono_mb_emit_byte (mb, CEE_SUB);
1097         mono_mb_emit_byte (mb, CEE_STIND_I4);
1098         mono_mb_emit_byte (mb, CEE_RET);
1099
1100         /*
1101          obj_null, has_waiting:
1102           ldarg         0                                                       obj
1103           call          System.Threading.Monitor.Exit
1104           ret
1105          */
1106
1107         mono_mb_patch_short_branch (mb, obj_null_branch);
1108         mono_mb_patch_short_branch (mb, has_waiting_branch);
1109         mono_mb_emit_byte (mb, CEE_LDARG_0);
1110         mono_mb_emit_managed_call (mb, monitor_exit_method, NULL);
1111         mono_mb_emit_byte (mb, CEE_RET);
1112
1113         fast_monitor_exit = mono_mb_create_method (mb, mono_signature_no_pinvoke (monitor_exit_method), 5);
1114         mono_mb_free (mb);
1115
1116         return fast_monitor_exit;
1117 }
1118
1119 MonoMethod*
1120 mono_monitor_get_fast_path (MonoMethod *enter_or_exit)
1121 {
1122         if (strcmp (enter_or_exit->name, "Enter") == 0)
1123                 return mono_monitor_get_fast_enter_method (enter_or_exit);
1124         if (strcmp (enter_or_exit->name, "Exit") == 0)
1125                 return mono_monitor_get_fast_exit_method (enter_or_exit);
1126         g_assert_not_reached ();
1127         return NULL;
1128 }
1129
1130 /*
1131  * mono_monitor_threads_sync_member_offset:
1132  * @owner_offset: returns size and offset of the "owner" member
1133  * @nest_offset: returns size and offset of the "nest" member
1134  * @entry_count_offset: returns size and offset of the "entry_count" member
1135  *
1136  * Returns the offsets and sizes of three members of the
1137  * MonoThreadsSync struct.  The Monitor ASM fastpaths need this.
1138  */
1139 void
1140 mono_monitor_threads_sync_members_offset (int *owner_offset, int *nest_offset, int *entry_count_offset)
1141 {
1142         MonoThreadsSync ts;
1143
1144 #define ENCODE_OFF_SIZE(o,s)    (((o) << 8) | ((s) & 0xff))
1145
1146         *owner_offset = ENCODE_OFF_SIZE (G_STRUCT_OFFSET (MonoThreadsSync, owner), sizeof (ts.owner));
1147         *nest_offset = ENCODE_OFF_SIZE (G_STRUCT_OFFSET (MonoThreadsSync, nest), sizeof (ts.nest));
1148         *entry_count_offset = ENCODE_OFF_SIZE (G_STRUCT_OFFSET (MonoThreadsSync, entry_count), sizeof (ts.entry_count));
1149 }
1150
1151 gboolean 
1152 ves_icall_System_Threading_Monitor_Monitor_try_enter (MonoObject *obj, guint32 ms)
1153 {
1154         gint32 res;
1155
1156         do {
1157                 res = mono_monitor_try_enter_internal (obj, ms, TRUE);
1158                 if (res == -1)
1159                         mono_thread_interruption_checkpoint ();
1160         } while (res == -1);
1161         
1162         return res == 1;
1163 }
1164
1165 void
1166 ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var (MonoObject *obj, guint32 ms, char *lockTaken)
1167 {
1168         gint32 res;
1169         do {
1170                 res = mono_monitor_try_enter_internal (obj, ms, TRUE);
1171                 /*This means we got interrupted during the wait and didn't got the monitor.*/
1172                 if (res == -1)
1173                         mono_thread_interruption_checkpoint ();
1174         } while (res == -1);
1175         /*It's safe to do it from here since interruption would happen only on the wrapper.*/
1176         *lockTaken = res == 1;
1177 }
1178
1179 gboolean 
1180 ves_icall_System_Threading_Monitor_Monitor_test_owner (MonoObject *obj)
1181 {
1182         MonoThreadsSync *mon;
1183         
1184         LOCK_DEBUG (g_message ("%s: Testing if %p is owned by thread %d", __func__, obj, GetCurrentThreadId()));
1185
1186         mon = obj->synchronisation;
1187 #ifdef HAVE_MOVING_COLLECTOR
1188         {
1189                 LockWord lw;
1190                 lw.sync = mon;
1191                 if (lw.lock_word & LOCK_WORD_THIN_HASH)
1192                         return FALSE;
1193                 lw.lock_word &= ~LOCK_WORD_BITS_MASK;
1194                 mon = lw.sync;
1195         }
1196 #endif
1197         if (mon == NULL) {
1198                 return FALSE;
1199         }
1200         
1201         if(mon->owner==GetCurrentThreadId ()) {
1202                 return(TRUE);
1203         }
1204         
1205         return(FALSE);
1206 }
1207
1208 gboolean 
1209 ves_icall_System_Threading_Monitor_Monitor_test_synchronised (MonoObject *obj)
1210 {
1211         MonoThreadsSync *mon;
1212
1213         LOCK_DEBUG (g_message("%s: (%d) Testing if %p is owned by any thread", __func__, GetCurrentThreadId (), obj));
1214         
1215         mon = obj->synchronisation;
1216 #ifdef HAVE_MOVING_COLLECTOR
1217         {
1218                 LockWord lw;
1219                 lw.sync = mon;
1220                 if (lw.lock_word & LOCK_WORD_THIN_HASH)
1221                         return FALSE;
1222                 lw.lock_word &= ~LOCK_WORD_BITS_MASK;
1223                 mon = lw.sync;
1224         }
1225 #endif
1226         if (mon == NULL) {
1227                 return FALSE;
1228         }
1229         
1230         if (mon->owner != 0) {
1231                 return TRUE;
1232         }
1233         
1234         return FALSE;
1235 }
1236
1237 /* All wait list manipulation in the pulse, pulseall and wait
1238  * functions happens while the monitor lock is held, so we don't need
1239  * any extra struct locking
1240  */
1241
1242 void
1243 ves_icall_System_Threading_Monitor_Monitor_pulse (MonoObject *obj)
1244 {
1245         MonoThreadsSync *mon;
1246         
1247         LOCK_DEBUG (g_message ("%s: (%d) Pulsing %p", __func__, GetCurrentThreadId (), obj));
1248         
1249         mon = obj->synchronisation;
1250 #ifdef HAVE_MOVING_COLLECTOR
1251         {
1252                 LockWord lw;
1253                 lw.sync = mon;
1254                 if (lw.lock_word & LOCK_WORD_THIN_HASH) {
1255                         mono_raise_exception (mono_get_exception_synchronization_lock ("Not locked"));
1256                         return;
1257                 }
1258                 lw.lock_word &= ~LOCK_WORD_BITS_MASK;
1259                 mon = lw.sync;
1260         }
1261 #endif
1262         if (mon == NULL) {
1263                 mono_raise_exception (mono_get_exception_synchronization_lock ("Not locked"));
1264                 return;
1265         }
1266         if (mon->owner != GetCurrentThreadId ()) {
1267                 mono_raise_exception (mono_get_exception_synchronization_lock ("Not locked by this thread"));
1268                 return;
1269         }
1270
1271         LOCK_DEBUG (g_message ("%s: (%d) %d threads waiting", __func__, GetCurrentThreadId (), g_slist_length (mon->wait_list)));
1272         
1273         if (mon->wait_list != NULL) {
1274                 LOCK_DEBUG (g_message ("%s: (%d) signalling and dequeuing handle %p", __func__, GetCurrentThreadId (), mon->wait_list->data));
1275         
1276                 SetEvent (mon->wait_list->data);
1277                 mon->wait_list = g_slist_remove (mon->wait_list, mon->wait_list->data);
1278         }
1279 }
1280
1281 void
1282 ves_icall_System_Threading_Monitor_Monitor_pulse_all (MonoObject *obj)
1283 {
1284         MonoThreadsSync *mon;
1285         
1286         LOCK_DEBUG (g_message("%s: (%d) Pulsing all %p", __func__, GetCurrentThreadId (), obj));
1287
1288         mon = obj->synchronisation;
1289 #ifdef HAVE_MOVING_COLLECTOR
1290         {
1291                 LockWord lw;
1292                 lw.sync = mon;
1293                 if (lw.lock_word & LOCK_WORD_THIN_HASH) {
1294                         mono_raise_exception (mono_get_exception_synchronization_lock ("Not locked"));
1295                         return;
1296                 }
1297                 lw.lock_word &= ~LOCK_WORD_BITS_MASK;
1298                 mon = lw.sync;
1299         }
1300 #endif
1301         if (mon == NULL) {
1302                 mono_raise_exception (mono_get_exception_synchronization_lock ("Not locked"));
1303                 return;
1304         }
1305         if (mon->owner != GetCurrentThreadId ()) {
1306                 mono_raise_exception (mono_get_exception_synchronization_lock ("Not locked by this thread"));
1307                 return;
1308         }
1309
1310         LOCK_DEBUG (g_message ("%s: (%d) %d threads waiting", __func__, GetCurrentThreadId (), g_slist_length (mon->wait_list)));
1311
1312         while (mon->wait_list != NULL) {
1313                 LOCK_DEBUG (g_message ("%s: (%d) signalling and dequeuing handle %p", __func__, GetCurrentThreadId (), mon->wait_list->data));
1314         
1315                 SetEvent (mon->wait_list->data);
1316                 mon->wait_list = g_slist_remove (mon->wait_list, mon->wait_list->data);
1317         }
1318 }
1319
1320 gboolean
1321 ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms)
1322 {
1323         MonoThreadsSync *mon;
1324         HANDLE event;
1325         guint32 nest;
1326         guint32 ret;
1327         gboolean success = FALSE;
1328         gint32 regain;
1329         MonoInternalThread *thread = mono_thread_internal_current ();
1330
1331         LOCK_DEBUG (g_message ("%s: (%d) Trying to wait for %p with timeout %dms", __func__, GetCurrentThreadId (), obj, ms));
1332         
1333         mon = obj->synchronisation;
1334 #ifdef HAVE_MOVING_COLLECTOR
1335         {
1336                 LockWord lw;
1337                 lw.sync = mon;
1338                 if (lw.lock_word & LOCK_WORD_THIN_HASH) {
1339                         mono_raise_exception (mono_get_exception_synchronization_lock ("Not locked"));
1340                         return FALSE;
1341                 }
1342                 lw.lock_word &= ~LOCK_WORD_BITS_MASK;
1343                 mon = lw.sync;
1344         }
1345 #endif
1346         if (mon == NULL) {
1347                 mono_raise_exception (mono_get_exception_synchronization_lock ("Not locked"));
1348                 return FALSE;
1349         }
1350         if (mon->owner != GetCurrentThreadId ()) {
1351                 mono_raise_exception (mono_get_exception_synchronization_lock ("Not locked by this thread"));
1352                 return FALSE;
1353         }
1354
1355         /* Do this WaitSleepJoin check before creating the event handle */
1356         mono_thread_current_check_pending_interrupt ();
1357         
1358         event = CreateEvent (NULL, FALSE, FALSE, NULL);
1359         if (event == NULL) {
1360                 mono_raise_exception (mono_get_exception_synchronization_lock ("Failed to set up wait event"));
1361                 return FALSE;
1362         }
1363         
1364         LOCK_DEBUG (g_message ("%s: (%d) queuing handle %p", __func__, GetCurrentThreadId (), event));
1365
1366         mono_thread_current_check_pending_interrupt ();
1367         
1368         mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1369
1370         mon->wait_list = g_slist_append (mon->wait_list, event);
1371         
1372         /* Save the nest count, and release the lock */
1373         nest = mon->nest;
1374         mon->nest = 1;
1375         mono_monitor_exit (obj);
1376
1377         LOCK_DEBUG (g_message ("%s: (%d) Unlocked %p lock %p", __func__, GetCurrentThreadId (), obj, mon));
1378
1379         /* There's no race between unlocking mon and waiting for the
1380          * event, because auto reset events are sticky, and this event
1381          * is private to this thread.  Therefore even if the event was
1382          * signalled before we wait, we still succeed.
1383          */
1384         ret = WaitForSingleObjectEx (event, ms, TRUE);
1385
1386         /* Reset the thread state fairly early, so we don't have to worry
1387          * about the monitor error checking
1388          */
1389         mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1390         
1391         if (mono_thread_interruption_requested ()) {
1392                 /* 
1393                  * Can't remove the event from wait_list, since the monitor is not locked by
1394                  * us. So leave it there, mon_new () will delete it when the mon structure
1395                  * is placed on the free list.
1396                  * FIXME: The caller expects to hold the lock after the wait returns, but it
1397                  * doesn't happen in this case:
1398                  * http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=97268
1399                  */
1400                 return FALSE;
1401         }
1402
1403         /* Regain the lock with the previous nest count */
1404         do {
1405                 regain = mono_monitor_try_enter_internal (obj, INFINITE, TRUE);
1406                 if (regain == -1) 
1407                         mono_thread_interruption_checkpoint ();
1408         } while (regain == -1);
1409
1410         if (regain == 0) {
1411                 /* Something went wrong, so throw a
1412                  * SynchronizationLockException
1413                  */
1414                 CloseHandle (event);
1415                 mono_raise_exception (mono_get_exception_synchronization_lock ("Failed to regain lock"));
1416                 return FALSE;
1417         }
1418
1419         mon->nest = nest;
1420
1421         LOCK_DEBUG (g_message ("%s: (%d) Regained %p lock %p", __func__, GetCurrentThreadId (), obj, mon));
1422
1423         if (ret == WAIT_TIMEOUT) {
1424                 /* Poll the event again, just in case it was signalled
1425                  * while we were trying to regain the monitor lock
1426                  */
1427                 ret = WaitForSingleObjectEx (event, 0, FALSE);
1428         }
1429
1430         /* Pulse will have popped our event from the queue if it signalled
1431          * us, so we only do it here if the wait timed out.
1432          *
1433          * This avoids a race condition where the thread holding the
1434          * lock can Pulse several times before the WaitForSingleObject
1435          * returns.  If we popped the queue here then this event might
1436          * be signalled more than once, thereby starving another
1437          * thread.
1438          */
1439         
1440         if (ret == WAIT_OBJECT_0) {
1441                 LOCK_DEBUG (g_message ("%s: (%d) Success", __func__, GetCurrentThreadId ()));
1442                 success = TRUE;
1443         } else {
1444                 LOCK_DEBUG (g_message ("%s: (%d) Wait failed, dequeuing handle %p", __func__, GetCurrentThreadId (), event));
1445                 /* No pulse, so we have to remove ourself from the
1446                  * wait queue
1447                  */
1448                 mon->wait_list = g_slist_remove (mon->wait_list, event);
1449         }
1450         CloseHandle (event);
1451         
1452         return success;
1453 }
1454