+ //XXX This would be nice to be true, but can happen due to self-aborts (and possibly set-pending-exception)
+ //if prot_count > 0, INTERRUPT_REQUESTED_BIT must never be set
+ // int prot_count = (state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT;
+ // g_assert (!(prot_count > 0 && (state & INTERRUPT_REQUESTED_BIT)));
+}
+
+void
+mono_threads_begin_abort_protected_block (void)
+{
+ MonoInternalThread *thread = mono_thread_internal_current ();
+ gsize old_state, new_state;
+ do {
+ old_state = thread->thread_state;
+ verify_thread_state (old_state);
+
+ int new_val = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT) + 1;
+
+ new_state = 0;
+ if (old_state & (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT)) {
+ if (old_state & INTERRUPT_REQUESTED_BIT)
+ printf ("begin prot happy as it demoted interrupt to deferred interrupt\n");
+ new_state |= INTERRUPT_REQUEST_DEFERRED_BIT;
+ }
+
+ //bounds check abort_prot_count
+ g_assert (new_val > 0);
+ g_assert (new_val < (1 << ABORT_PROT_BLOCK_BITS));
+ new_state |= new_val << ABORT_PROT_BLOCK_SHIFT;
+
+ } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
+}
+
+gboolean
+mono_threads_end_abort_protected_block (void)
+{
+ MonoInternalThread *thread = mono_thread_internal_current ();
+ gsize old_state, new_state;
+ do {
+ old_state = thread->thread_state;
+ verify_thread_state (old_state);
+
+ int new_val = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT) - 1;
+ new_state = 0;
+
+ if ((old_state & INTERRUPT_REQUEST_DEFERRED_BIT) && new_val == 0) {
+ printf ("end abort on alert, promoted deferred to pront interrupt\n");
+ new_state |= INTERRUPT_REQUESTED_BIT;
+ }
+
+ //bounds check abort_prot_count
+ g_assert (new_val >= 0);
+ g_assert (new_val < (1 << ABORT_PROT_BLOCK_BITS));
+ new_state |= new_val << ABORT_PROT_BLOCK_SHIFT;
+
+ } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
+ return (new_state & INTERRUPT_REQUESTED_BIT) == INTERRUPT_REQUESTED_BIT;
+}
+
+
+//Don't use this function, use inc/dec below
+static void
+mono_thread_abort_prot_block_count_add (MonoInternalThread *thread, int val)
+{
+ gsize old_state, new_state;
+ do {
+ old_state = thread->thread_state;
+ verify_thread_state (old_state);
+
+ int new_val = val + ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT);
+ //bounds check abort_prot_count
+ g_assert (new_val >= 0);
+ g_assert (new_val < (1 << ABORT_PROT_BLOCK_BITS));
+ new_state = (old_state & ~ABORT_PROT_BLOCK_MASK) | (new_val << ABORT_PROT_BLOCK_SHIFT);
+
+ } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
+}
+
+static void
+mono_thread_inc_abort_prot_block_count (MonoInternalThread *thread)
+{
+ mono_thread_abort_prot_block_count_add (thread, 1);
+}
+
+static void
+mono_thread_dec_abort_prot_block_count (MonoInternalThread *thread)
+{
+ mono_thread_abort_prot_block_count_add (thread, -1);
+}
+
+static gboolean
+mono_thread_get_interruption_requested (MonoInternalThread *thread)
+{
+ gsize state = thread->thread_state;
+ return (state & INTERRUPT_REQUESTED_BIT) == INTERRUPT_REQUESTED_BIT;
+}
+
+/* Returns TRUE is there was a state change */
+static gboolean
+mono_thread_clear_interruption_requested (MonoInternalThread *thread)
+{
+ gsize old_state, new_state;
+ do {
+ old_state = thread->thread_state;
+ verify_thread_state (old_state);
+
+ //Already cleared
+ if (!(old_state & (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT)))
+ return FALSE;
+ new_state = old_state & ~(INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT);
+ } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
+ return TRUE;
+}
+
+/* Returns TRUE is there was a state change */
+static gboolean
+mono_thread_set_interruption_requested (MonoInternalThread *thread)
+{
+ //always force when the current thread is doing it to itself.
+ gboolean force_interrupt = thread == mono_thread_internal_current ();
+ gsize old_state, new_state;
+ do {
+ old_state = thread->thread_state;
+ verify_thread_state (old_state);
+
+ int prot_count = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT);
+ //Already set
+ if (old_state & (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT))
+ return FALSE;
+
+ //If there's an outstanding prot block, we queue it
+ if (prot_count && !force_interrupt) {
+ printf ("set interrupt unhappy, as it's only putting a deferred req %d\n", force_interrupt);
+ new_state = old_state | INTERRUPT_REQUEST_DEFERRED_BIT;
+ } else
+ new_state = old_state | INTERRUPT_REQUESTED_BIT;
+ } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
+
+ return (new_state & INTERRUPT_REQUESTED_BIT) == INTERRUPT_REQUESTED_BIT;