*
* Copyright 2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
if (new_->wait_list) {
/* Orphaned events left by aborted threads */
while (new_->wait_list) {
- LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d): Closing orphaned event %d", mono_thread_info_get_small_id (), new->wait_list->data));
+ LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d): Closing orphaned event %d", mono_thread_info_get_small_id (), new_->wait_list->data));
CloseHandle (new_->wait_list->data);
new_->wait_list = g_slist_remove (new_->wait_list, new_->wait_list->data);
}
LockWord lw;
MonoThreadsSync *mon;
HANDLE sem;
- guint32 then = 0, now, delta;
+ gint64 then = 0, now, delta;
guint32 waitms;
guint32 ret;
guint32 new_status, old_status, tmp_status;
* We pass TRUE instead of allow_interruption since we have to check for the
* StopRequested case below.
*/
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
ret = WaitForSingleObjectEx (mon->entry_sem, waitms, TRUE);
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
* We have to obey a stop/suspend request even if
* allow_interruption is FALSE to avoid hangs at shutdown.
*/
- if (!mono_thread_test_state (mono_thread_internal_current (), (MonoThreadState)(ThreadState_StopRequested | ThreadState_SuspendRequested))) {
+ if (!mono_thread_test_state (mono_thread_internal_current (), (MonoThreadState)(ThreadState_StopRequested | ThreadState_SuspendRequested | ThreadState_AbortRequested))) {
if (ms != INFINITE) {
now = mono_msec_ticks ();
- if (now < then) {
- LOCK_DEBUG (g_message ("%s: wrapped around! now=0x%x then=0x%x", __func__, now, then));
- now += (0xffffffff - then);
- then = 0;
-
- LOCK_DEBUG (g_message ("%s: wrap rejig: now=0x%x then=0x%x delta=0x%x", __func__, now, then, now-then));
- }
+ /* it should not overflow before ~30k years */
+ g_assert (now >= then);
delta = now - then;
if (delta >= ms) {
}
gboolean
+mono_monitor_enter_fast (MonoObject *obj)
+{
+ return mono_monitor_try_enter_internal (obj, 0, FALSE) == 1;
+}
+
+gboolean
mono_monitor_try_enter (MonoObject *obj, guint32 ms)
{
return mono_monitor_try_enter_internal (obj, ms, FALSE) == 1;
*nest_offset = ENCODE_OFF_SIZE (MONO_STRUCT_OFFSET (MonoThreadsSync, nest), sizeof (ts.nest));
}
-gboolean
-ves_icall_System_Threading_Monitor_Monitor_try_enter (MonoObject *obj, guint32 ms)
-{
- gint32 res;
-
- 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_try_enter_with_atomic_var (MonoObject *obj, guint32 ms, char *lockTaken)
{
do {
res = mono_monitor_try_enter_internal (obj, ms, TRUE);
/*This means we got interrupted during the wait and didn't got the monitor.*/
- if (res == -1)
- mono_thread_interruption_checkpoint ();
+ if (res == -1) {
+ MonoException *exc = mono_thread_interruption_checkpoint ();
+ if (exc) {
+ mono_set_pending_exception (exc);
+ return;
+ }
+ }
} while (res == -1);
/*It's safe to do it from here since interruption would happen only on the wrapper.*/
*lockTaken = res == 1;
void
mono_monitor_enter_v4 (MonoObject *obj, char *lock_taken)
{
-
if (*lock_taken == 1) {
mono_set_pending_exception (mono_get_exception_argument ("lockTaken", "lockTaken is already true"));
return;
ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var (obj, INFINITE, lock_taken);
}
+/*
+ * mono_monitor_enter_v4_fast:
+ *
+ * Same as mono_monitor_enter_v4, but return immediately if the
+ * monitor cannot be acquired.
+ * Returns TRUE if the lock was acquired, FALSE otherwise.
+ */
+gboolean
+mono_monitor_enter_v4_fast (MonoObject *obj, char *lock_taken)
+{
+ if (*lock_taken == 1)
+ return FALSE;
+ if (G_UNLIKELY (!obj))
+ return FALSE;
+ gint32 res = mono_monitor_try_enter_internal (obj, 0, TRUE);
+ *lock_taken = res == 1;
+ return res == 1;
+}
+
gboolean
ves_icall_System_Threading_Monitor_Monitor_test_owner (MonoObject *obj)
{
* is private to this thread. Therefore even if the event was
* signalled before we wait, we still succeed.
*/
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
ret = WaitForSingleObjectEx (event, ms, TRUE);
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
/* Reset the thread state fairly early, so we don't have to worry
* about the monitor error checking
*/
mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
-
- if (mono_thread_interruption_requested ()) {
- /*
- * Can't remove the event from wait_list, since the monitor is not locked by
- * us. So leave it there, mon_new () will delete it when the mon structure
- * is placed on the free list.
- * FIXME: The caller expects to hold the lock after the wait returns, but it
- * doesn't happen in this case:
- * http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=97268
- */
- return FALSE;
- }
/* Regain the lock with the previous nest count */
do {
regain = mono_monitor_try_enter_inflated (obj, INFINITE, TRUE, id);
- if (regain == -1)
- mono_thread_interruption_checkpoint ();
+ /* We must regain the lock before handling interruption requests */
} while (regain == -1);
- if (regain == 0) {
- /* Something went wrong, so throw a
- * SynchronizationLockException
- */
- CloseHandle (event);
- mono_set_pending_exception (mono_get_exception_synchronization_lock ("Failed to regain lock"));
- return FALSE;
- }
+ g_assert (regain == 1);
mon->nest = nest;
/* Poll the event again, just in case it was signalled
* while we were trying to regain the monitor lock
*/
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
ret = WaitForSingleObjectEx (event, 0, FALSE);
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
}
/* Pulse will have popped our event from the queue if it signalled