#include <mono/metadata/monitor.h>
#include <mono/metadata/threads-types.h>
#include <mono/metadata/exception.h>
+#include <mono/metadata/threads.h>
#include <mono/io-layer/io-layer.h>
#include <mono/os/gc_wrapper.h>
return(new);
}
-gboolean mono_monitor_try_enter (MonoObject *obj, guint32 ms)
+/* If allow_interruption==TRUE, the method will be interrumped if abort or suspend
+ * is requested. In this case it returns -1.
+ */
+static gint32 mono_monitor_try_enter_internal (MonoObject *obj, guint32 ms, gboolean allow_interruption)
{
MonoThreadsSync *mon;
guint32 id=GetCurrentThreadId ();
HANDLE sem;
- guint32 then, now, delta;
+ guint32 then=0, now, delta;
guint32 waitms;
guint32 ret;
mon=mon_new(id);
if(InterlockedCompareExchangePointer ((gpointer*)&obj->synchronisation, mon, NULL)==NULL) {
/* Successfully locked */
- return(TRUE);
+ return(1);
} else {
/* Another thread got in first, so try again.
* GC will take care of the monitor record
/* If the object is currently locked by this thread... */
if(mon->owner==id) {
mon->nest++;
- return(TRUE);
+ return(1);
}
/* If the object has previously been locked but isn't now... */
if(InterlockedCompareExchange (&mon->owner, id, 0)==0) {
/* Success */
g_assert (mon->nest==1);
- return(TRUE);
+ return(1);
} else {
/* Trumped again! */
goto retry;
": (%d) timed out, returning FALSE", id);
#endif
- return(FALSE);
+ return(0);
}
/* The slow path begins here. We need to make sure theres a
}
InterlockedIncrement (&mon->entry_count);
- ret=WaitForSingleObject (mon->entry_sem, waitms);
+ ret=WaitForSingleObjectEx (mon->entry_sem, waitms, allow_interruption);
InterlockedDecrement (&mon->entry_count);
-
+
if(ms!=INFINITE) {
now=GetTickCount ();
ms-=delta;
}
- if(ret==WAIT_TIMEOUT && ms>0) {
+ if((ret==WAIT_TIMEOUT || (ret==WAIT_IO_COMPLETION && !allow_interruption)) && ms>0) {
/* More time left */
goto retry;
}
} else {
- if(ret==WAIT_TIMEOUT) {
+ if(ret==WAIT_TIMEOUT || (ret==WAIT_IO_COMPLETION && !allow_interruption)) {
/* Infinite wait, so just try again */
goto retry;
}
": (%d) timed out waiting, returning FALSE", id);
#endif
- return(FALSE);
+ if (ret==WAIT_IO_COMPLETION) return(-1);
+ else return(0);
+}
+
+gboolean mono_monitor_enter (MonoObject *obj)
+{
+ return mono_monitor_try_enter_internal (obj, INFINITE, FALSE) == 1;
+}
+
+gboolean mono_monitor_try_enter (MonoObject *obj, guint32 ms)
+{
+ return mono_monitor_try_enter_internal (obj, ms, FALSE) == 1;
}
void mono_monitor_exit (MonoObject *obj)
return;
}
if(mon->owner!=GetCurrentThreadId ()) {
- mono_raise_exception (mono_get_exception_synchronization_lock ("Not locked by this thread"));
return;
}
gboolean ves_icall_System_Threading_Monitor_Monitor_try_enter(MonoObject *obj,
guint32 ms)
{
+ gint32 res;
MONO_ARCH_SAVE_REGS;
- return(mono_monitor_try_enter (obj, ms));
+ do {
+ res = mono_monitor_try_enter_internal (obj, ms, TRUE);
+ if (res == -1)
+ mono_thread_interruption_checkpoint ();
+ }
+ while (res == -1);
+
+ return(res == 1);
}
void ves_icall_System_Threading_Monitor_Monitor_exit(MonoObject *obj)
HANDLE event;
guint32 nest;
guint32 ret;
- gboolean success=FALSE, regain;
+ gboolean success=FALSE;
+ gint32 regain;
MONO_ARCH_SAVE_REGS;
* is private to this thread. Therefore even if the event was
* signalled before we wait, we still succeed.
*/
- ret=WaitForSingleObject (event, ms);
+ ret=WaitForSingleObjectEx (event, ms, TRUE);
+ if (mono_thread_interruption_requested ()) {
+ CloseHandle (event);
+ return(FALSE);
+ }
+
/* Regain the lock with the previous nest count */
- regain=mono_monitor_try_enter (obj, INFINITE);
- if(regain==FALSE) {
+ do {
+ regain=mono_monitor_try_enter_internal (obj, INFINITE, TRUE);
+ if (regain == -1)
+ mono_thread_interruption_checkpoint ();
+ }
+ while (regain == -1);
+
+ if(regain==0) {
/* Something went wrong, so throw a
* SynchronizationLockException
*/
/* Poll the event again, just in case it was signalled
* while we were trying to regain the monitor lock
*/
- ret=WaitForSingleObject (event, 0);
+ ret=WaitForSingleObjectEx (event, 0, FALSE);
}
/* Pulse will have popped our event from the queue if it signalled