Merge pull request #4274 from kumpera/cctor-abort
authorRodrigo Kumpera <kumpera@users.noreply.github.com>
Sun, 22 Jan 2017 15:20:38 +0000 (10:20 -0500)
committerGitHub <noreply@github.com>
Sun, 22 Jan 2017 15:20:38 +0000 (10:20 -0500)
[runtime] Latest attempt at the cctor abort race. All tests passing locally.

1  2 
mono/metadata/icall.c
mono/metadata/object-internals.h
mono/metadata/object.c
mono/metadata/threads-types.h
mono/metadata/threads.c

diff --combined mono/metadata/icall.c
index 3e87be6daf94477e3de8824cdcf2ca0a7f128956,4c0477d9e17397b9142a2d6ab6c655bfeb61fb63..774bf8bc50fc32363f9d11632acf7b0422bf80cb
@@@ -46,7 -46,7 +46,7 @@@
  #include <mono/metadata/tabledefs.h>
  #include <mono/metadata/exception.h>
  #include <mono/metadata/exception-internals.h>
 -#include <mono/metadata/file-io.h>
 +#include <mono/metadata/w32file.h>
  #include <mono/metadata/console-io.h>
  #include <mono/metadata/mono-route.h>
  #include <mono/metadata/w32socket.h>
@@@ -85,6 -85,7 +85,6 @@@
  #include <mono/metadata/w32mutex.h>
  #include <mono/metadata/w32semaphore.h>
  #include <mono/metadata/w32event.h>
 -#include <mono/io-layer/io-layer.h>
  #include <mono/utils/monobitset.h>
  #include <mono/utils/mono-time.h>
  #include <mono/utils/mono-proclib.h>
@@@ -96,8 -97,6 +96,8 @@@
  #include <mono/utils/bsearch.h>
  #include <mono/utils/mono-os-mutex.h>
  #include <mono/utils/mono-threads.h>
 +#include <mono/metadata/w32error.h>
 +#include <mono/utils/w32api.h>
  
  #include "decimal-ms.h"
  #include "number-ms.h"
@@@ -2966,12 -2965,11 +2966,12 @@@ ves_icall_System_RuntimeType_IsWindowsR
  }
  
  ICALL_EXPORT void
 -ves_icall_MonoMethod_GetPInvoke (MonoReflectionMethod *method, int* flags, MonoString** entry_point, MonoString** dll_name)
 +ves_icall_MonoMethod_GetPInvoke (MonoReflectionMethodHandle ref_method, int* flags, MonoStringHandleOut entry_point, MonoStringHandleOut dll_name, MonoError *error)
  {
        MonoDomain *domain = mono_domain_get ();
 -      MonoImage *image = method->method->klass->image;
 -      MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method->method;
 +      MonoMethod *method = MONO_HANDLE_GETVAL (ref_method, method);
 +      MonoImage *image = method->klass->image;
 +      MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
        MonoTableInfo *tables = image->tables;
        MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
        MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
        const char *import = NULL;
        const char *scope = NULL;
  
 +      mono_error_init (error);
 +
        if (image_is_dynamic (image)) {
                MonoReflectionMethodAux *method_aux = 
 -                      (MonoReflectionMethodAux *)g_hash_table_lookup (((MonoDynamicImage*)image)->method_aux_hash, method->method);
 +                      (MonoReflectionMethodAux *)g_hash_table_lookup (((MonoDynamicImage*)image)->method_aux_hash, method);
                if (method_aux) {
                        import = method_aux->dllentry;
                        scope = method_aux->dll;
                }
  
                if (!import || !scope) {
 -                      mono_set_pending_exception (mono_get_exception_argument ("method", "System.Reflection.Emit method with invalid pinvoke information"));
 +                      mono_error_set_argument (error, "method", "System.Refleciton.Emit method with invalid pinvoke information");
                        return;
                }
        }
        }
        
        *flags = piinfo->piflags;
 -      *entry_point = mono_string_new (domain, import);
 -      *dll_name = mono_string_new (domain, scope);
 +      MONO_HANDLE_ASSIGN (entry_point,  mono_string_new_handle (domain, import, error));
 +      return_if_nok (error);
 +      MONO_HANDLE_ASSIGN (dll_name, mono_string_new_handle (domain, scope, error));
  }
  
 -ICALL_EXPORT MonoReflectionMethod *
 -ves_icall_MonoMethod_GetGenericMethodDefinition (MonoReflectionMethod *method)
 +ICALL_EXPORT MonoReflectionMethodHandle
 +ves_icall_MonoMethod_GetGenericMethodDefinition (MonoReflectionMethodHandle ref_method, MonoError *error)
  {
 -      MonoMethodInflated *imethod;
 -      MonoMethod *result;
 -      MonoReflectionMethod *ret = NULL;
 -      MonoError error;
 +      mono_error_init (error);
 +      MonoMethod *method = MONO_HANDLE_GETVAL (ref_method, method);
  
 -      if (method->method->is_generic)
 -              return method;
 +      if (method->is_generic)
 +              return ref_method;
  
 -      if (!method->method->is_inflated)
 -              return NULL;
 +      if (!method->is_inflated)
 +              return MONO_HANDLE_CAST (MonoReflectionMethod, NULL_HANDLE);
  
 -      imethod = (MonoMethodInflated *) method->method;
 +      MonoMethodInflated *imethod = (MonoMethodInflated *) method;
  
 -      result = imethod->declaring;
 +      MonoMethod *result = imethod->declaring;
        /* Not a generic method.  */
        if (!result->is_generic)
 -              return NULL;
 +              return MONO_HANDLE_CAST (MonoReflectionMethod, NULL_HANDLE);
  
 -      if (image_is_dynamic (method->method->klass->image)) {
 -              MonoDynamicImage *image = (MonoDynamicImage*)method->method->klass->image;
 -              MonoReflectionMethod *res;
 +      if (image_is_dynamic (method->klass->image)) {
 +              MonoDynamicImage *image = (MonoDynamicImage*)method->klass->image;
  
                /*
                 * FIXME: Why is this stuff needed at all ? Why can't the code below work for
                 * the dynamic case as well ?
                 */
                mono_image_lock ((MonoImage*)image);
 -              res = (MonoReflectionMethod *)mono_g_hash_table_lookup (image->generic_def_objects, imethod);
 +              MonoReflectionMethodHandle res = MONO_HANDLE_NEW (MonoReflectionMethod, mono_g_hash_table_lookup (image->generic_def_objects, imethod));
                mono_image_unlock ((MonoImage*)image);
  
 -              if (res)
 +              if (!MONO_HANDLE_IS_NULL (res))
                        return res;
        }
  
                MonoClass *klass = ((MonoMethod *) imethod)->klass;
                /*Generic methods gets the context of the GTD.*/
                if (mono_class_get_context (klass)) {
 -                      result = mono_class_inflate_generic_method_full_checked (result, klass, mono_class_get_context (klass), &error);
 -                      if (!mono_error_ok (&error))
 -                              goto leave;
 +                      result = mono_class_inflate_generic_method_full_checked (result, klass, mono_class_get_context (klass), error);
 +                      return_val_if_nok (error, MONO_HANDLE_CAST (MonoReflectionMethod, NULL_HANDLE));
                }
        }
  
 -      ret = mono_method_get_object_checked (mono_object_domain (method), result, NULL, &error);
 -leave:
 -      if (!mono_error_ok (&error))
 -              mono_error_set_pending_exception (&error);
 -      return ret;
 +      return mono_method_get_object_handle (MONO_HANDLE_DOMAIN (ref_method), result, NULL, error);
  }
  
  ICALL_EXPORT gboolean
 -ves_icall_MonoMethod_get_IsGenericMethod (MonoReflectionMethod *method)
 +ves_icall_MonoMethod_get_IsGenericMethod (MonoReflectionMethodHandle ref_method, MonoError *erro)
  {
 -      return mono_method_signature (method->method)->generic_param_count != 0;
 +      MonoMethod *method = MONO_HANDLE_GETVAL (ref_method, method);
 +      return mono_method_signature (method)->generic_param_count != 0;
  }
  
  ICALL_EXPORT gboolean
 -ves_icall_MonoMethod_get_IsGenericMethodDefinition (MonoReflectionMethod *method)
 +ves_icall_MonoMethod_get_IsGenericMethodDefinition (MonoReflectionMethodHandle ref_method, MonoError *Error)
  {
 -      return method->method->is_generic;
 +      MonoMethod *method = MONO_HANDLE_GETVAL (ref_method, method);
 +      return method->is_generic;
  }
  
 -ICALL_EXPORT MonoArray*
 -ves_icall_MonoMethod_GetGenericArguments (MonoReflectionMethod *method)
 +static gboolean
 +set_array_generic_argument_handle_inflated (MonoDomain *domain, MonoGenericInst *inst, int i, MonoArrayHandle arr, MonoError *error)
  {
 -      MonoError error;
 -      MonoReflectionType *rt;
 -      MonoArray *res;
 -      MonoDomain *domain;
 -      int count, i;
 +      HANDLE_FUNCTION_ENTER ();
 +      mono_error_init (error);
 +      MonoReflectionTypeHandle rt = mono_type_get_object_handle (domain, inst->type_argv [i], error);
 +      if (!is_ok (error))
 +              goto leave;
 +      MONO_HANDLE_ARRAY_SETREF (arr, i, rt);
 +leave:
 +      HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
 +}
 +
 +static gboolean
 +set_array_generic_argument_handle_gparam (MonoDomain *domain, MonoGenericContainer *container, int i, MonoArrayHandle arr, MonoError *error)
 +{
 +      HANDLE_FUNCTION_ENTER ();
 +      mono_error_init (error);
 +      MonoGenericParam *param = mono_generic_container_get_param (container, i);
 +      MonoClass *pklass = mono_class_from_generic_parameter_internal (param);
 +      MonoReflectionTypeHandle rt = mono_type_get_object_handle (domain, &pklass->byval_arg, error);
 +      if (!is_ok (error))
 +              goto leave;
 +      MONO_HANDLE_ARRAY_SETREF (arr, i, rt);
 +leave:
 +      HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
 +}
  
 -      domain = mono_object_domain (method);
 +ICALL_EXPORT MonoArrayHandle
 +ves_icall_MonoMethod_GetGenericArguments (MonoReflectionMethodHandle ref_method, MonoError *error)
 +{
 +      mono_error_init (error);
 +      MonoDomain *domain = MONO_HANDLE_DOMAIN (ref_method);
 +      MonoMethod *method = MONO_HANDLE_GETVAL (ref_method, method);
  
 -      if (method->method->is_inflated) {
 -              MonoGenericInst *inst = mono_method_get_context (method->method)->method_inst;
 +      if (method->is_inflated) {
 +              MonoGenericInst *inst = mono_method_get_context (method)->method_inst;
  
                if (inst) {
 -                      count = inst->type_argc;
 -                      res = mono_array_new_checked (domain, mono_defaults.systemtype_class, count, &error);
 -                      if (mono_error_set_pending_exception (&error))
 -                              return NULL;
 -
 -                      for (i = 0; i < count; i++) {
 -                              rt = mono_type_get_object_checked (domain, inst->type_argv [i], &error);
 -                              if (mono_error_set_pending_exception (&error))
 -                                      return NULL;
 +                      int count = inst->type_argc;
 +                      MonoArrayHandle res = mono_array_new_handle (domain, mono_defaults.systemtype_class, count, error);
 +                      return_val_if_nok (error, MONO_HANDLE_CAST (MonoArray, NULL_HANDLE));
  
 -                              mono_array_setref (res, i, rt);
 +                      for (int i = 0; i < count; i++) {
 +                              if (!set_array_generic_argument_handle_inflated (domain, inst, i, res, error))
 +                                      break;
                        }
 -
 +                      return_val_if_nok (error, MONO_HANDLE_CAST (MonoArray, NULL_HANDLE));
                        return res;
                }
        }
  
 -      count = mono_method_signature (method->method)->generic_param_count;
 -      res = mono_array_new_checked (domain, mono_defaults.systemtype_class, count, &error);
 -      if (mono_error_set_pending_exception (&error))
 -              return NULL;
 -
 -      for (i = 0; i < count; i++) {
 -              MonoGenericContainer *container = mono_method_get_generic_container (method->method);
 -              MonoGenericParam *param = mono_generic_container_get_param (container, i);
 -              MonoClass *pklass = mono_class_from_generic_parameter_internal (param);
 -
 -              rt = mono_type_get_object_checked (domain, &pklass->byval_arg, &error);
 -              if (mono_error_set_pending_exception (&error))
 -                      return NULL;
 +      int count = mono_method_signature (method)->generic_param_count;
 +      MonoArrayHandle res = mono_array_new_handle (domain, mono_defaults.systemtype_class, count, error);
 +      return_val_if_nok (error, MONO_HANDLE_CAST (MonoArray, NULL_HANDLE));
  
 -              mono_array_setref (res, i, rt);
 +      MonoGenericContainer *container = mono_method_get_generic_container (method);
 +      for (int i = 0; i < count; i++) {
 +              if (!set_array_generic_argument_handle_gparam (domain, container, i, res, error))
 +                      break;
        }
 -
 +      return_val_if_nok (error, MONO_HANDLE_CAST (MonoArray, NULL_HANDLE));
        return res;
  }
  
@@@ -5248,10 -5236,9 +5248,10 @@@ ves_icall_MonoField_get_core_clr_securi
  }
  
  ICALL_EXPORT int
 -ves_icall_MonoMethod_get_core_clr_security_level (MonoReflectionMethod *rfield)
 +ves_icall_MonoMethod_get_core_clr_security_level (MonoReflectionMethodHandle rfield, MonoError *error)
  {
 -      MonoMethod *method = rfield->method;
 +      mono_error_init (error);
 +      MonoMethod *method = MONO_HANDLE_GETVAL (rfield, method);
        return mono_security_core_clr_method_level (method, TRUE);
  }
  
@@@ -6646,6 -6633,10 +6646,10 @@@ ves_icall_System_Environment_Exit (int 
        /* Suspend all managed threads since the runtime is going away */
        mono_thread_suspend_all_other_threads ();
  
+       //FIXME shutdown is, weirdly enough, abortible in gc.c so we add this hack for now, see https://bugzilla.xamarin.com/show_bug.cgi?id=51653
+       mono_threads_begin_abort_protected_block ();
+       mono_thread_info_clear_self_interrupt ();
        mono_runtime_quit ();
  #endif
  
@@@ -6692,7 -6683,7 +6696,7 @@@ mono_icall_get_logical_drives (void
        ptr = buf;
  
        while (size > initial_size) {
 -              size = (guint) GetLogicalDriveStrings (initial_size, ptr);
 +              size = (guint) mono_w32file_get_logical_drive (initial_size, ptr);
                if (size > initial_size) {
                        if (ptr != buf)
                                g_free (ptr);
@@@ -6748,7 -6739,7 +6752,7 @@@ ves_icall_System_IO_DriveInfo_GetDriveF
        MonoError error;
        gunichar2 volume_name [MAX_PATH + 1];
        
 -      if (GetVolumeInformation (mono_string_chars (path), NULL, 0, NULL, NULL, NULL, volume_name, MAX_PATH + 1) == FALSE)
 +      if (mono_w32file_get_volume_information (mono_string_chars (path), NULL, 0, NULL, NULL, NULL, volume_name, MAX_PATH + 1) == FALSE)
                return NULL;
        MonoString *result = mono_string_from_utf16_checked (volume_name, &error);
        mono_error_set_pending_exception (&error);
@@@ -7027,12 -7018,24 +7031,12 @@@ ves_icall_System_IO_DriveInfo_GetDiskFr
                                                gint32 *error)
  {
        gboolean result;
 -      ULARGE_INTEGER wapi_free_bytes_avail;
 -      ULARGE_INTEGER wapi_total_number_of_bytes;
 -      ULARGE_INTEGER wapi_total_number_of_free_bytes;
  
        *error = ERROR_SUCCESS;
 -      result = GetDiskFreeSpaceEx (mono_string_chars (path_name), &wapi_free_bytes_avail, &wapi_total_number_of_bytes,
 -                                   &wapi_total_number_of_free_bytes);
  
 -      if (result) {
 -              *free_bytes_avail = wapi_free_bytes_avail.QuadPart;
 -              *total_number_of_bytes = wapi_total_number_of_bytes.QuadPart;
 -              *total_number_of_free_bytes = wapi_total_number_of_free_bytes.QuadPart;
 -      } else {
 -              *free_bytes_avail = 0;
 -              *total_number_of_bytes = 0;
 -              *total_number_of_free_bytes = 0;
 -              *error = GetLastError ();
 -      }
 +      result = mono_w32file_get_disk_free_space (mono_string_chars (path_name), free_bytes_avail, total_number_of_bytes, total_number_of_free_bytes);
 +      if (!result)
 +              *error = mono_w32error_get_last ();
  
        return result;
  }
  static inline guint32
  mono_icall_drive_info_get_drive_type (MonoString *root_path_name)
  {
 -      return GetDriveType (mono_string_chars (root_path_name));
 +      return mono_w32file_get_drive_type (mono_string_chars (root_path_name));
  }
  #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
  
@@@ -7258,31 -7261,168 +7262,31 @@@ ves_icall_System_Activator_CreateInstan
        return MONO_HANDLE_NEW (MonoObject, mono_object_new_checked (domain, klass, error));
  }
  
 -ICALL_EXPORT MonoReflectionMethod *
 -ves_icall_MonoMethod_get_base_method (MonoReflectionMethod *m, gboolean definition)
 +ICALL_EXPORT MonoReflectionMethodHandle
 +ves_icall_MonoMethod_get_base_method (MonoReflectionMethodHandle m, gboolean definition, MonoError *error)
  {
 -      MonoReflectionMethod *ret = NULL;
 -      MonoError error;
 -
 -      MonoClass *klass, *parent;
 -      MonoGenericContext *generic_inst = NULL;
 -      MonoMethod *method = m->method;
 -      MonoMethod *result = NULL;
 -      int slot;
 -
 -      if (method->klass == NULL)
 -              return m;
 -
 -      if (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
 -          MONO_CLASS_IS_INTERFACE (method->klass) ||
 -          method->flags & METHOD_ATTRIBUTE_NEW_SLOT)
 -              return m;
 -
 -      slot = mono_method_get_vtable_slot (method);
 -      if (slot == -1)
 -              return m;
 -
 -      klass = method->klass;
 -      if (mono_class_is_ginst (klass)) {
 -              generic_inst = mono_class_get_context (klass);
 -              klass = mono_class_get_generic_class (klass)->container_class;
 -      }
 -
 -retry:
 -      if (definition) {
 -              /* At the end of the loop, klass points to the eldest class that has this virtual function slot. */
 -              for (parent = klass->parent; parent != NULL; parent = parent->parent) {
 -                      /* on entry, klass is either a plain old non-generic class and generic_inst == NULL
 -                         or klass is the generic container class and generic_inst is the instantiation.
 -
 -                         when we go to the parent, if the parent is an open constructed type, we need to
 -                         replace the type parameters by the definitions from the generic_inst, and then take it
 -                         apart again into the klass and the generic_inst.
 -
 -                         For cases like this:
 -                         class C<T> : B<T, int> {
 -                             public override void Foo () { ... }
 -                         }
 -                         class B<U,V> : A<HashMap<U,V>> {
 -                             public override void Foo () { ... }
 -                         }
 -                         class A<X> {
 -                             public virtual void Foo () { ... }
 -                         }
 -
 -                         if at each iteration the parent isn't open, we can skip inflating it.  if at some
 -                         iteration the parent isn't generic (after possible inflation), we set generic_inst to
 -                         NULL;
 -                      */
 -                      MonoGenericContext *parent_inst = NULL;
 -                      if (mono_class_is_open_constructed_type (mono_class_get_type (parent))) {
 -                              parent = mono_class_inflate_generic_class_checked (parent, generic_inst, &error);
 -                              if (!mono_error_ok (&error)) {
 -                                      mono_error_set_pending_exception (&error);
 -                                      return NULL;
 -                              }
 -                      }
 -                      if (mono_class_is_ginst (parent)) {
 -                              parent_inst = mono_class_get_context (parent);
 -                              parent = mono_class_get_generic_class (parent)->container_class;
 -                      }
 -
 -                      mono_class_setup_vtable (parent);
 -                      if (parent->vtable_size <= slot)
 -                              break;
 -                      klass = parent;
 -                      generic_inst = parent_inst;
 -              }
 -      } else {
 -              klass = klass->parent;
 -              if (!klass)
 -                      return m;
 -              if (mono_class_is_open_constructed_type (mono_class_get_type (klass))) {
 -                      klass = mono_class_inflate_generic_class_checked (klass, generic_inst, &error);
 -                      if (!mono_error_ok (&error)) {
 -                              mono_error_set_pending_exception (&error);
 -                              return NULL;
 -                      }
 -
 -                      generic_inst = NULL;
 -              }
 -              if (mono_class_is_ginst (klass)) {
 -                      generic_inst = mono_class_get_context (klass);
 -                      klass = mono_class_get_generic_class (klass)->container_class;
 -              }
 -
 -      }
 -
 -      if (generic_inst) {
 -              klass = mono_class_inflate_generic_class_checked (klass, generic_inst, &error);
 -              if (!mono_error_ok (&error)) {
 -                      mono_error_set_pending_exception (&error);
 -                      return NULL;
 -              }
 -      }
 -
 -      if (klass == method->klass)
 -              return m;
 +      mono_error_init (error);
 +      MonoMethod *method = MONO_HANDLE_GETVAL (m, method);
  
 -      /*This is possible if definition == FALSE.
 -       * Do it here to be really sure we don't read invalid memory.
 -       */
 -      if (slot >= klass->vtable_size)
 +      MonoMethod *base = mono_method_get_base_method (method, definition, error);
 +      return_val_if_nok (error, MONO_HANDLE_CAST (MonoReflectionMethod, NULL_HANDLE));
 +      if (base == method)
                return m;
 -
 -      mono_class_setup_vtable (klass);
 -
 -      result = klass->vtable [slot];
 -      if (result == NULL) {
 -              /* It is an abstract method */
 -              gboolean found = FALSE;
 -              gpointer iter = NULL;
 -              while ((result = mono_class_get_methods (klass, &iter))) {
 -                      if (result->slot == slot) {
 -                              found = TRUE;
 -                              break;
 -                      }
 -              }
 -              /* found might be FALSE if we looked in an abstract class
 -               * that doesn't override an abstract method of its
 -               * parent: 
 -               *   abstract class Base {
 -               *     public abstract void Foo ();
 -               *   }
 -               *   abstract class Derived : Base { }
 -               *   class Child : Derived {
 -               *     public override void Foo () { }
 -               *  }
 -               *
 -               *  if m was Child.Foo and we ask for the base method,
 -               *  then we get here with klass == Derived and found == FALSE
 -               */
 -              /* but it shouldn't be the case that if we're looking
 -               * for the definition and didn't find a result; the
 -               * loop above should've taken us as far as we could
 -               * go! */
 -              g_assert (!(definition && !found));
 -              if (!found)
 -                      goto retry;
 -      }
 -
 -      g_assert (result != NULL);
 -
 -      ret = mono_method_get_object_checked (mono_domain_get (), result, NULL, &error);
 -      mono_error_set_pending_exception (&error);
 -      return ret;
 +      else
 +              return mono_method_get_object_handle (mono_domain_get (), base, NULL, error);
  }
  
 -ICALL_EXPORT MonoString*
 -ves_icall_MonoMethod_get_name (MonoReflectionMethod *m)
 +ICALL_EXPORT MonoStringHandle
 +ves_icall_MonoMethod_get_name (MonoReflectionMethodHandle m, MonoError *error)
  {
 -      MonoMethod *method = m->method;
 +      mono_error_init (error);
 +      MonoMethod *method = MONO_HANDLE_GETVAL (m, method);
  
 -      MONO_OBJECT_SETREF (m, name, mono_string_new (mono_object_domain (m), method->name));
 -      return m->name;
 +      MonoStringHandle s = mono_string_new_handle (MONO_HANDLE_DOMAIN (m), method->name, error);
 +      if (!is_ok (error))
 +              return NULL_HANDLE_STRING;
 +      MONO_HANDLE_SET (m, name, s);
 +      return s;
  }
  
  ICALL_EXPORT void
index 67a185e07fa7565497e266f7cdcac2fe40df8220,2d175ae3a0636efddf89afb88330c2c4587c1c0a..2c4780ac2330963984e52efe5e8f26ba8143ecf2
@@@ -375,7 -375,7 +375,7 @@@ struct _MonoInternalThread 
        int _serialized_principal_version;
        gpointer appdomain_refs;
        /* This is modified using atomic ops, so keep it a gint32 */
-       gint32 interruption_requested;
+       gint32 __interruption_requested;
        MonoCoopMutex *synch_cs;
        MonoBoolean threadpool_thread;
        MonoBoolean thread_interrupt_requested;
        gpointer interrupt_on_stop;
        gsize    flags;
        gpointer thread_pinning_ref;
-       gsize abort_protected_block_count;
+       gsize __abort_protected_block_count;
        gint32 priority;
        GPtrArray *owned_mutexes;
        MonoOSEvent *suspended;
        gint32 self_suspended; // TRUE | FALSE
+       gsize thread_state;
        /* 
         * These fields are used to avoid having to increment corlib versions
         * when a new field is added to this structure.
         * Please synchronize any changes with InternalThread in Thread.cs, i.e. add the
         * same field there.
         */
-       gsize unused1;
        gsize unused2;
  
        /* This is used only to check that we are in sync between the representation
@@@ -1837,8 -1838,8 +1838,8 @@@ mono_runtime_exec_main_checked (MonoMet
  int
  mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc);
  
 -MonoReflectionMethod*
 -ves_icall_MonoMethod_MakeGenericMethod_impl (MonoReflectionMethod *rmethod, MonoArray *types);
 +MonoReflectionMethodHandle
 +ves_icall_MonoMethod_MakeGenericMethod_impl (MonoReflectionMethodHandle rmethod, MonoArrayHandle types, MonoError *error);
  
  gint32
  ves_icall_ModuleBuilder_getToken (MonoReflectionModuleBuilderHandle mb, MonoObjectHandle obj, gboolean create_open_instance, MonoError *error);
diff --combined mono/metadata/object.c
index 699c7d225fb78b8e5899d38738fef4b01619464a,51d8627a74afbdeeff5c56944b084b5d788c4807..9da8a225049d2dd73cb916a5180ba7a3f6643024
@@@ -50,7 -50,7 +50,7 @@@
  #include <mono/utils/mono-threads.h>
  #include <mono/utils/mono-threads-coop.h>
  #include "cominterop.h"
 -#include <mono/io-layer/io-layer.h>
 +#include <mono/utils/w32api.h>
  
  static void
  get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
@@@ -441,7 -441,7 +441,7 @@@ mono_runtime_class_init_full (MonoVTabl
  
                mono_threads_begin_abort_protected_block ();
                mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
-               mono_threads_end_abort_protected_block ();
+               gboolean got_pending_interrupt = mono_threads_end_abort_protected_block ();
  
                //exception extracted, error will be set to the right value later
                if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
                        mono_domain_set (last_domain, TRUE);
                lock->done = TRUE;
                mono_type_init_unlock (lock);
+               //This can happen if the cctor self-aborts
                if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
                        pending_tae = exc;
                //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
-               if (!pending_tae && mono_get_eh_callbacks ()->mono_above_abort_threshold ())
+               if (!pending_tae && got_pending_interrupt)
                        pending_tae = mono_thread_try_resume_interruption ();
        } else {
                /* this just blocks until the initializing thread is done */
index 626a26bb31b61b214a561a40402e1cb8ffeb7fa4,a259c7ff1641577b7c2a4efc6769875d01829d64..c473777932a32d97d7ba6899877ebacff9b6fff4
@@@ -53,6 -53,10 +53,6 @@@ typedef enum 
  #define SPECIAL_STATIC_THREAD 1
  #define SPECIAL_STATIC_CONTEXT 2
  
 -#ifdef HOST_WIN32
 -typedef SECURITY_ATTRIBUTES WapiSecurityAttributes;
 -#endif
 -
  typedef struct _MonoInternalThread MonoInternalThread;
  
  typedef void (*MonoThreadCleanupFunc) (MonoNativeThreadId tid);
@@@ -248,7 -252,7 +248,7 @@@ MONO_API voi
  mono_threads_detach_coop (gpointer cookie, gpointer *dummy);
  
  void mono_threads_begin_abort_protected_block (void);
void mono_threads_end_abort_protected_block (void);
gboolean mono_threads_end_abort_protected_block (void);
  MonoException* mono_thread_try_resume_interruption (void);
  
  gboolean
diff --combined mono/metadata/threads.c
index abc29bf0022c3d70c33af64cac939df00c980834,809f66472fd148163693278f3a40b1cc0afbd401..bbbb9f69b88052bd30133aac0b262a525a511911
@@@ -28,6 -28,7 +28,6 @@@
  #include <mono/metadata/gc-internals.h>
  #include <mono/metadata/marshal.h>
  #include <mono/metadata/runtime.h>
 -#include <mono/io-layer/io-layer.h>
  #include <mono/metadata/object-internals.h>
  #include <mono/metadata/mono-debug-debugger.h>
  #include <mono/utils/monobitset.h>
@@@ -52,8 -53,6 +52,8 @@@
  #include <mono/metadata/gc-internals.h>
  #include <mono/metadata/reflection-internals.h>
  #include <mono/metadata/abi-details.h>
 +#include <mono/metadata/w32error.h>
 +#include <mono/utils/w32api.h>
  
  #ifdef HAVE_SIGNAL_H
  #include <signal.h>
@@@ -229,6 -228,167 +229,167 @@@ get_next_managed_thread_id (void
        return InterlockedIncrement (&managed_thread_id_counter);
  }
  
+ enum {
+       INTERRUPT_REQUESTED_BIT = 0x1,
+       INTERRUPT_REQUEST_DEFERRED_BIT = 0x2,
+       ABORT_PROT_BLOCK_SHIFT = 2,
+       ABORT_PROT_BLOCK_BITS = 8,
+       ABORT_PROT_BLOCK_MASK = (((1 << ABORT_PROT_BLOCK_BITS) - 1) << ABORT_PROT_BLOCK_SHIFT)
+ };
+ static int
+ mono_thread_get_abort_prot_block_count (MonoInternalThread *thread)
+ {
+       gsize state = thread->thread_state;
+       return (state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT;
+ }
+ static void
+ verify_thread_state (gsize state)
+ {
+       //can't have both INTERRUPT_REQUESTED_BIT and INTERRUPT_REQUEST_DEFERRED_BIT set at the same time
+       g_assert ((state & (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT)) != (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT));
+       //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;
+ }
  static inline MonoNativeThreadId
  thread_get_tid (MonoInternalThread *thread)
  {
@@@ -796,7 -956,7 +957,7 @@@ create_thread (MonoThread *thread, Mono
                mono_threads_lock ();
                mono_g_hash_table_remove (threads_starting_up, thread);
                mono_threads_unlock ();
 -              mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", GetLastError());
 +              mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", mono_w32error_get_last());
                /* ref is not going to be decremented in start_wrapper_internal */
                InterlockedDecrement (&start_info->ref);
                ret = FALSE;
@@@ -1008,7 -1168,7 +1169,7 @@@ mono_thread_detach_internal (MonoIntern
        Leaving the counter unbalanced will cause a performance degradation since all threads
        will now keep checking their local flags all the time.
        */
-       if (InterlockedExchange (&thread->interruption_requested, 0) != 0)
+       if (mono_thread_clear_interruption_requested (thread))
                InterlockedDecrement (&thread_interruption_requested);
  
        mono_threads_lock ();
@@@ -4307,7 -4467,7 +4468,7 @@@ mono_thread_execute_interruption (void
        LOCK_THREAD (thread);
  
        /* MonoThread::interruption_requested can only be changed with atomics */
-       if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
+       if (mono_thread_clear_interruption_requested (thread)) {
                /* this will consume pending APC calls */
  #ifdef HOST_WIN32
                WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
@@@ -4387,7 -4547,7 +4548,7 @@@ mono_thread_request_interruption (gbool
                thread->state & ThreadState_Background)
                ExitThread (1);
  #endif
-       if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
+       if (!mono_thread_set_interruption_requested (thread))
                return NULL;
        InterlockedIncrement (&thread_interruption_requested);
  
@@@ -4431,7 -4591,7 +4592,7 @@@ mono_thread_resume_interruption (void
        if (!still_aborting)
                return FALSE;
  
-       if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
+       if (!mono_thread_set_interruption_requested (thread))
                return NULL;
        InterlockedIncrement (&thread_interruption_requested);
  
@@@ -4446,7 -4606,7 +4607,7 @@@ gboolean mono_thread_interruption_reque
                MonoInternalThread *thread = mono_thread_internal_current ();
                /* The thread may already be stopping */
                if (thread != NULL) 
-                       return (thread->interruption_requested);
+                       return mono_thread_get_interruption_requested (thread);
        }
        return FALSE;
  }
@@@ -4459,7 -4619,7 +4620,7 @@@ mono_thread_interruption_checkpoint_req
        /* The thread may already be stopping */
        if (!thread)
                return NULL;
-       if (!thread->interruption_requested)
+       if (!mono_thread_get_interruption_requested (thread))
                return NULL;
        if (!bypass_abort_protection && is_running_protected_wrapper ())
                return NULL;
@@@ -4690,11 -4850,11 +4851,11 @@@ async_abort_critical (MonoThreadInfo *i
        The target thread is running at least one protected block, which must not be interrupted, so we give up.
        The protected block code will give them a chance when appropriate.
        */
-       if (thread->abort_protected_block_count)
+       if (mono_thread_get_abort_prot_block_count (thread) > 0)
                return MonoResumeThread;
  
        /*someone is already interrupting it*/
-       if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
+       if (!mono_thread_set_interruption_requested (thread))
                return MonoResumeThread;
  
        InterlockedIncrement (&thread_interruption_requested);
@@@ -4789,7 -4949,7 +4950,7 @@@ async_suspend_critical (MonoThreadInfo 
                        return KeepSuspended;
                }
        } else {
-               if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
+               if (mono_thread_set_interruption_requested (thread))
                        InterlockedIncrement (&thread_interruption_requested);
                if (data->interrupt)
                        data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
@@@ -5097,34 -5257,15 +5258,15 @@@ mono_threads_detach_coop (gpointer cook
        }
  }
  
- void
- mono_threads_begin_abort_protected_block (void)
- {
-       MonoInternalThread *thread;
-       thread = mono_thread_internal_current ();
-       ++thread->abort_protected_block_count;
-       mono_memory_barrier ();
- }
- void
- mono_threads_end_abort_protected_block (void)
- {
-       MonoInternalThread *thread;
-       thread = mono_thread_internal_current ();
-       mono_memory_barrier ();
-       --thread->abort_protected_block_count;
- }
  MonoException*
  mono_thread_try_resume_interruption (void)
  {
        MonoInternalThread *thread;
  
        thread = mono_thread_internal_current ();
-       if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
+       if (!mono_get_eh_callbacks ()->mono_above_abort_threshold ())
+               return NULL;
+       if (mono_thread_get_abort_prot_block_count (thread) > 0 || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
                return NULL;
  
        return mono_thread_resume_interruption ();
@@@ -5144,7 -5285,7 +5286,7 @@@ mono_threads_is_ready_to_be_interrupte
                return FALSE;
        }
  
-       if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
+       if (mono_thread_get_abort_prot_block_count (thread) || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
                UNLOCK_THREAD (thread);
                return FALSE;
        }