From e9e809b3545ffd8d9e7b6e49de0d18385baf4be2 Mon Sep 17 00:00:00 2001 From: Miguel de Icaza Date: Fri, 15 Dec 2006 22:47:09 +0000 Subject: [PATCH] This patch contains: SafeHandle implemenation http://www.mono-project.com/SafeHandles for status WaitHandle updates for using with new SafeWaitHandle. Marshal replaces g_error with exceptions in a few areas. 2006-12-15 Miguel de Icaza * marshal.c (mono_free_bstr): On Unix, this is g_free. (mono_string_from_bstr, mono_string_to_bstr): Implement bstr conversions (for the tests in corlib to pass). 2006-12-14 Miguel de Icaza * marshal.c (emit_ptr_to_object_conv): For now, ignore MONO_MARSHAL_CONV_SAFEHANDLE on return values (we need to throw an exception if a ref SafeHandle in a struct has changed). (emit_struct_conv): Do not perform layout checks for classes derived from SafeHandle, as those are specially handled. (emit_object_to_ptr_conv): Add support for MONO_MARSHAL_CONV_SAFEHANDLE conversion. (emit_marshal_safehandle): Implement conversion of return values of safehandles (MARSHAL_ACTION_CONV_RESULT). * threads.c: WaitHandle now is compiled with two different handles "IntPtr os_handle" for 1.x and "SafeWaitHandle safe_wait_handle" for 2.0. (ves_icall_System_Threading_WaitHandle_WaitAll_internal) (ves_icall_System_Threading_WaitHandle_WaitAny_internal): Adjust these routines to cope with both kinds of fields. 2006-12-12 Miguel de Icaza * metadata.c (mono_type_to_unmanaged): Handle the case where type->data.klass is a SafeHandle, and in that case, return the size of a pointer (MONO_NATIVE_INT) and set the conversion to be MONO_MARSHAL_CONV_SAFEHANDLE. 2006-12-11 Miguel de Icaza * marshal.c (emit_marshal): Hook up to the MONO_TYPE_CLASS and MONO_TYPE_OBJECT cases and check for a SafeHandle here before calling emit_marshal_object. (emit_marshal_safehandle): Implement marshalling of SafeHandle parameters (no ref support yet). (MarshalAction): Document the defines as I implement them for SafeHandle. (emit_marshal_object): indentation police. * class-internals.h: Define MonoSafeHandle. Add safehandle_class to MonoDefaults type. * verify.c: Add System.Runtime.InteropServices.SafeHandle to the list of classes to check for fields. * domain.c (mono_init_internal): Add SafeHandle to the list of mono_defaults loaded. svn path=/trunk/mono/; revision=69551 --- mono/metadata/ChangeLog | 59 ++++++++ mono/metadata/class-internals.h | 11 ++ mono/metadata/domain.c | 2 + mono/metadata/marshal.c | 292 +++++++++++++++++++++++++++++++++++----- mono/metadata/metadata.c | 16 ++- mono/metadata/metadata.h | 3 +- mono/metadata/threads.c | 56 +++++--- mono/metadata/verify.c | 12 ++ 8 files changed, 401 insertions(+), 50 deletions(-) diff --git a/mono/metadata/ChangeLog b/mono/metadata/ChangeLog index e33d7bb4468..3b8d06546a3 100644 --- a/mono/metadata/ChangeLog +++ b/mono/metadata/ChangeLog @@ -1,3 +1,62 @@ +2006-12-15 Miguel de Icaza + + * marshal.c (mono_free_bstr): On Unix, this is g_free. + (mono_string_from_bstr, mono_string_to_bstr): Implement bstr + conversions (for the tests in corlib to pass). + +2006-12-14 Miguel de Icaza + + * marshal.c (emit_ptr_to_object_conv): For now, ignore + MONO_MARSHAL_CONV_SAFEHANDLE on return values (we need to throw an + exception if a ref SafeHandle in a struct has changed). + + (emit_struct_conv): Do not perform layout checks for classes + derived from SafeHandle, as those are specially handled. + + (emit_object_to_ptr_conv): Add support for + MONO_MARSHAL_CONV_SAFEHANDLE conversion. + + (emit_marshal_safehandle): Implement conversion of return values + of safehandles (MARSHAL_ACTION_CONV_RESULT). + + * threads.c: WaitHandle now is compiled with two different handles + "IntPtr os_handle" for 1.x and "SafeWaitHandle safe_wait_handle" + for 2.0. + + (ves_icall_System_Threading_WaitHandle_WaitAll_internal) + (ves_icall_System_Threading_WaitHandle_WaitAny_internal): Adjust + these routines to cope with both kinds of fields. + +2006-12-12 Miguel de Icaza + + * metadata.c (mono_type_to_unmanaged): Handle the case where + type->data.klass is a SafeHandle, and in that case, return the + size of a pointer (MONO_NATIVE_INT) and set the conversion to be + MONO_MARSHAL_CONV_SAFEHANDLE. + +2006-12-11 Miguel de Icaza + + * marshal.c (emit_marshal): Hook up to the MONO_TYPE_CLASS and + MONO_TYPE_OBJECT cases and check for a SafeHandle here before + calling emit_marshal_object. + + (emit_marshal_safehandle): Implement marshalling of + SafeHandle parameters (no ref support yet). + + (MarshalAction): Document the defines as I implement + them for SafeHandle. + + (emit_marshal_object): indentation police. + + * class-internals.h: Define MonoSafeHandle. + Add safehandle_class to MonoDefaults type. + + * verify.c: Add System.Runtime.InteropServices.SafeHandle to the + list of classes to check for fields. + + * domain.c (mono_init_internal): Add SafeHandle to the list of + mono_defaults loaded. + 2006-12-15 Raja R Harinath Fix #80253 diff --git a/mono/metadata/class-internals.h b/mono/metadata/class-internals.h index c37b16bc49d..23d205fbb13 100644 --- a/mono/metadata/class-internals.h +++ b/mono/metadata/class-internals.h @@ -561,6 +561,16 @@ typedef struct { gboolean enabled; } MonoStats; +/* + * The definition of the first field in SafeHandle, + * Keep in sync with SafeHandle.cs, this is only used + * to access the `handle' parameter. + */ +typedef struct { + MonoObject base; + void *handle; +} MonoSafeHandle; + extern MonoStats mono_stats MONO_INTERNAL; typedef gpointer (*MonoTrampoline) (MonoMethod *method); @@ -716,6 +726,7 @@ typedef struct { MonoClass *variant_class; MonoClass *com_object_class; MonoClass *com_interop_proxy_class; + MonoClass *safehandle_class; } MonoDefaults; extern MonoDefaults mono_defaults MONO_INTERNAL; diff --git a/mono/metadata/domain.c b/mono/metadata/domain.c index e9a73bea164..92a4d98b810 100644 --- a/mono/metadata/domain.c +++ b/mono/metadata/domain.c @@ -819,6 +819,8 @@ mono_init_internal (const char *filename, const char *exe_filename, const char * mono_defaults.com_interop_proxy_class = mono_class_from_name ( mono_defaults.corlib, "Mono.Interop", "ComInteropProxy"); + mono_defaults.safehandle_class = mono_class_from_name ( + mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle"); /* * Note that mono_defaults.generic_*_class is only non-NULL if we're diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c index f132f1f056e..23d50ccccc7 100644 --- a/mono/metadata/marshal.c +++ b/mono/metadata/marshal.c @@ -154,6 +154,22 @@ mono_marshal_set_last_error_windows (int error); static void mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func); +static void init_safe_handle (void); + +/* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */ +static MonoMethod *sh_dangerous_add_ref; +static MonoMethod *sh_dangerous_release; + + +static void +init_safe_handle () +{ + sh_dangerous_add_ref = mono_class_get_method_from_name ( + mono_defaults.safehandle_class, "DangerousAddRef", 1); + sh_dangerous_release = mono_class_get_method_from_name ( + mono_defaults.safehandle_class, "DangerousRelease", 0); +} + static void register_icall (gpointer func, const char *name, const char *sigstr, gboolean save) { @@ -896,8 +912,16 @@ mono_string_to_bstr (MonoString *string_obj) return NULL; return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj)); #else - g_error ("UnmanagedMarshal.BStr is not implemented."); - return NULL; + int slen = mono_string_length (string_obj); + char *ret = g_malloc (slen * 2 + 4 + 2); + if (ret == NULL) + return NULL; + memcpy (ret + 4, mono_string_chars (string_obj), slen * 2); + * ((guint32 *) ret) = slen * 2; + ret [4 + slen * 2] = 0; + ret [5 + slen * 2] = 0; + + return ret + 4; #endif } @@ -909,8 +933,7 @@ mono_string_from_bstr (gpointer bstr) return NULL; return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr)); #else - g_error ("UnmanagedMarshal.BStr is not implemented."); - return NULL; + return mono_string_new_utf16 (mono_domain_get (), ((char *)bstr) - 4, *(guint32 *) bstr); #endif } @@ -920,7 +943,7 @@ mono_free_bstr (gpointer bstr) #ifdef PLATFORM_WIN32 SysFreeString ((BSTR)bstr); #else - g_error ("Free BSTR is not implemented."); + g_free (((char *)bstr) - 4); #endif } @@ -1837,6 +1860,23 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_patch_short_branch (mb, pos_failed); break; } + + case MONO_MARSHAL_CONV_SAFEHANDLE: { + /* + * Passing SafeHandles as ref does not allow the unmanaged code + * to change the SafeHandle value. If the value is changed, + * we should issue a diagnostic exception (NotSupportedException) + * that informs the user that changes to handles in unmanaged code + * is not supported. + * + * Since we currently have no access to the original + * SafeHandle that was used during the marshalling, + * for now we just ignore this, and ignore/discard any + * changes that might have happened to the handle. + */ + break; + } + case MONO_MARSHAL_CONV_STR_BSTR: case MONO_MARSHAL_CONV_STR_ANSIBSTR: case MONO_MARSHAL_CONV_STR_TBSTR: @@ -2171,6 +2211,39 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_patch_short_branch (mb, pos_failed); break; } + + case MONO_MARSHAL_CONV_SAFEHANDLE: { + int dar_release_slot; + + dar_release_slot = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg); + + /* + * The following is ifdefed-out, because I have no way of doing the + * DangerousRelease when destroying the structure + */ +#if 0 + /* set release = false */ + mono_mb_emit_icon (mb, 0); + mono_mb_emit_stloc (mb, dar_release_slot); + if (!sh_dangerous_add_ref) + init_safe_handle (); + + /* safehandle.DangerousAddRef (ref release) */ + mono_mb_emit_ldloc (mb, 0); /* the source */ + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_ldloc_addr (mb, dar_release_slot); + mono_mb_emit_managed_call (mb, sh_dangerous_add_ref, NULL); +#endif + + /* Pull the handle field from SafeHandle */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle)); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_byte (mb, CEE_STIND_I); + break; + } default: { char *msg = g_strdup_printf ("marshalling conversion %d not implemented", conv); MonoException *exc = mono_get_exception_not_implemented (msg); @@ -2230,18 +2303,26 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object) usize = info->fields [i + 1].offset - info->fields [i].offset; } - /* - * FIXME: Should really check for usize==0 and msize>0, but we apply - * the layout to the managed structure as well. - */ - if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && (usize == 0)) { - if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) || ((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type)))) - g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a reference field at the same offset as another field.", mono_type_full_name (&klass->byval_arg)); + if (klass != mono_defaults.safehandle_class){ + /* + * FIXME: Should really check for usize==0 and msize>0, but we apply + * the layout to the managed structure as well. + */ + + if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && (usize == 0)) { + if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) || + ((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type)))) + g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a " + "reference field at the same offset as another field.", + mono_type_full_name (&klass->byval_arg)); + } + + if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) + g_error ("Type %s which is passed to unmanaged code must have a StructLayout attribute", + mono_type_full_name (&klass->byval_arg)); + } - - if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) - g_error ("Type %s which is passed to unmanaged code must have a StructLayout attribute", mono_type_full_name (&klass->byval_arg)); - + switch (conv) { case MONO_MARSHAL_CONV_NONE: { int t; @@ -2322,6 +2403,7 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object) } else { static MonoMethod *get_native_variant_for_object = NULL; + if (!get_native_variant_for_object) get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2); @@ -2333,7 +2415,7 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object) break; } - default: + default: g_warning ("marshaling type %02x not implemented", ftype->type); g_assert_not_reached (); } @@ -5223,10 +5305,34 @@ typedef struct { } EmitMarshalContext; typedef enum { + /* + * This is invoked to convert arguments from the current types to + * the underlying types expected by the platform routine. If required, + * the methods create a temporary variable with the proper type, and return + * the location for it (either the passed argument, or the newly allocated + * local slot). + */ MARSHAL_ACTION_CONV_IN, + + /* + * This operation is called to push the actual value that was optionally + * converted on the first stage + */ MARSHAL_ACTION_PUSH, + + /* + * Convert byref arguments back or free resources allocated during the + * CONV_IN stage + */ MARSHAL_ACTION_CONV_OUT, + + /* + * The result from the unmanaged call is at the top of the stack when + * this action is invoked. The result should be stored in the + * third local variable slot. + */ MARSHAL_ACTION_CONV_RESULT, + MARSHAL_ACTION_MANAGED_CONV_IN, MARSHAL_ACTION_MANAGED_CONV_OUT, MARSHAL_ACTION_MANAGED_CONV_RESULT @@ -5913,10 +6019,124 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t, } static int +emit_marshal_safehandle (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + + if (t->byref) + g_error ("SafeHandle ACTION_PUSH by ref not yet handled\n"); + + switch (action){ + case MARSHAL_ACTION_CONV_IN: { + + MonoType *intptr_type; + int dar_release_slot; + + intptr_type = &mono_defaults.int_class->byval_arg; + conv_arg = mono_mb_add_local (mb, intptr_type); + *conv_arg_type = intptr_type; + + /* Create local to hold the ref parameter to DangerousAddRef */ + dar_release_slot = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg); + + /* set release = false; */ + mono_mb_emit_icon (mb, 0); + mono_mb_emit_stloc (mb, dar_release_slot); + + if (!sh_dangerous_add_ref) + init_safe_handle (); + + /* safehandle.DangerousAddRef (ref release) */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc_addr (mb, dar_release_slot); + mono_mb_emit_managed_call (mb, sh_dangerous_add_ref, NULL); + + /* Pull the handle field from SafeHandle */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle)); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_stloc (mb, conv_arg); + + break; + } + + case MARSHAL_ACTION_PUSH: + mono_mb_emit_ldloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_CONV_OUT: { + /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */ + int dar_release_slot = conv_arg + 1; + int label_next; + + if (!sh_dangerous_release) + init_safe_handle (); + + mono_mb_emit_ldloc (mb, dar_release_slot); + label_next = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_managed_call (mb, sh_dangerous_release, NULL); + mono_mb_patch_addr (mb, label_next, mb->pos - (label_next + 4)); + break; + } + + case MARSHAL_ACTION_CONV_RESULT: { + MonoMethod *ctor = NULL; + int intptr_handle_slot; + + if (t->data.klass->flags & TYPE_ATTRIBUTE_ABSTRACT){ + mono_mb_emit_byte (mb, CEE_POP); + mono_mb_emit_exception_marshal_directive (mb, "Returned SafeHandles should not be abstract"); + break; + } + + ctor = mono_class_get_method_from_name (t->data.klass, ".ctor", 0); + if (ctor == NULL){ + mono_mb_emit_byte (mb, CEE_POP); + mono_mb_emit_exception (mb, "MissingMethodException", "paramterless constructor required"); + break; + } + /* Store the IntPtr results into a local */ + intptr_handle_slot = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + mono_mb_emit_stloc (mb, intptr_handle_slot); + + /* Create return value */ + mono_mb_emit_op (mb, CEE_NEWOBJ, ctor); + mono_mb_emit_stloc (mb, 3); + + /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */ + mono_mb_emit_ldloc (mb, 3); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle)); + mono_mb_emit_ldloc (mb, intptr_handle_slot); + mono_mb_emit_byte (mb, CEE_STIND_I); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_IN: + printf ("Missing MANAGED_CONV_IN\n"); + break; + + case MARSHAL_ACTION_MANAGED_CONV_OUT: + printf ("Missing MANAGED_CONV_OUT\n"); + break; + + case MARSHAL_ACTION_MANAGED_CONV_RESULT: + printf ("Missing MANAGED_CONV_RESULT\n"); + break; + default: + printf ("Unhandled case for MarshalAction: %d\n", action); + } + + return conv_arg; +} + +static int emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) { MonoMethodBuilder *mb = m->mb; MonoClass *klass = t->data.klass; @@ -5925,8 +6145,8 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, if (mono_class_from_mono_type (t) == mono_defaults.object_class && (!spec || (spec && spec->native != MONO_NATIVE_STRUCT)) && (!spec || (spec && (spec->native != MONO_NATIVE_IUNKNOWN && - spec->native != MONO_NATIVE_IDISPATCH && - spec->native != MONO_NATIVE_INTERFACE)))) { + spec->native != MONO_NATIVE_IDISPATCH && + spec->native != MONO_NATIVE_INTERFACE)))) { mono_raise_exception (mono_get_exception_not_implemented ("Marshalling of type object is not implemented")); } @@ -7339,6 +7559,9 @@ emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t, return emit_marshal_string (m, argnum, t, spec, conv_arg, conv_arg_type, action); case MONO_TYPE_CLASS: case MONO_TYPE_OBJECT: + if (mono_class_is_subclass_of (t->data.klass, mono_defaults.safehandle_class, FALSE)) + return emit_marshal_safehandle (m, argnum, t, spec, conv_arg, conv_arg_type, action); + return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action); case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: @@ -9013,10 +9236,14 @@ ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray *s MONO_CHECK_ARG_NULL (src); MONO_CHECK_ARG_NULL (dest); - g_assert (src->obj.vtable->klass->rank == 1); - g_assert (start_index >= 0); - g_assert (length >= 0); - g_assert (start_index + length <= mono_array_length (src)); + if (src->obj.vtable->klass->rank != 1) + mono_raise_exception (mono_get_exception_argument ("array", "array is multi-dimensional")); + if (start_index < 0) + mono_raise_exception (mono_get_exception_argument ("startIndex", "Must be >= 0")); + if (length < 0) + mono_raise_exception (mono_get_exception_argument ("length", "Must be >= 0")); + if (start_index + length > mono_array_length (src)) + mono_raise_exception (mono_get_exception_argument ("length", "start_index + length > array length")); element_size = mono_array_element_size (src->obj.vtable->klass); @@ -9038,10 +9265,14 @@ ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer s MONO_CHECK_ARG_NULL (src); MONO_CHECK_ARG_NULL (dest); - g_assert (dest->obj.vtable->klass->rank == 1); - g_assert (start_index >= 0); - g_assert (length >= 0); - g_assert (start_index + length <= mono_array_length (dest)); + if (dest->obj.vtable->klass->rank != 1) + mono_raise_exception (mono_get_exception_argument ("array", "array is multi-dimensional")); + if (start_index < 0) + mono_raise_exception (mono_get_exception_argument ("startIndex", "Must be >= 0")); + if (length < 0) + mono_raise_exception (mono_get_exception_argument ("length", "Must be >= 0")); + if (start_index + length > mono_array_length (dest)) + mono_raise_exception (mono_get_exception_argument ("length", "start_index + length > array length")); element_size = mono_array_element_size (dest->obj.vtable->klass); @@ -9532,6 +9763,7 @@ mono_struct_delete_old (MonoClass *klass, char *ptr) case MONO_MARSHAL_CONV_STR_TBSTR: mono_marshal_free (*(gpointer *)cpos); break; + default: continue; } diff --git a/mono/metadata/metadata.c b/mono/metadata/metadata.c index 094ea0c314d..d1b5ac8d3a2 100644 --- a/mono/metadata/metadata.c +++ b/mono/metadata/metadata.c @@ -4148,7 +4148,17 @@ mono_metadata_free_marshal_spec (MonoMarshalSpec *spec) } g_free (spec); } - + +/** + * mono_type_to_unmanaged: + * + * Returns: A MonoMarshalNative enumeration value (MONO_NATIVE_) value + * describing the underlying native reprensetation of the type. + * + * In addition the value pointed by + * "conv" will contain the kind of marshalling required for this + * particular type one of the MONO_MARSHAL_CONV_ enumeration values. + */ guint32 mono_type_to_unmanaged (MonoType *type, MonoMarshalSpec *mspec, gboolean as_field, gboolean unicode, MonoMarshalConv *conv) @@ -4294,6 +4304,10 @@ handle_enum: *conv = MONO_MARSHAL_CONV_DEL_FTN; return MONO_NATIVE_FUNC; } + if (type->data.klass == mono_defaults.safehandle_class){ + *conv = MONO_MARSHAL_CONV_SAFEHANDLE; + return MONO_NATIVE_INT; + } *conv = MONO_MARSHAL_CONV_OBJECT_STRUCT; return MONO_NATIVE_STRUCT; } diff --git a/mono/metadata/metadata.h b/mono/metadata/metadata.h index 4fdefd49394..8fb6e134593 100644 --- a/mono/metadata/metadata.h +++ b/mono/metadata/metadata.h @@ -173,7 +173,8 @@ typedef enum { MONO_MARSHAL_CONV_DEL_FTN, MONO_MARSHAL_CONV_FTN_DEL, MONO_MARSHAL_FREE_ARRAY, - MONO_MARSHAL_CONV_BSTR_STR + MONO_MARSHAL_CONV_BSTR_STR, + MONO_MARSHAL_CONV_SAFEHANDLE } MonoMarshalConv; typedef struct { diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c index dfbe2f24dde..9ac3715c59f 100644 --- a/mono/metadata/threads.c +++ b/mono/metadata/threads.c @@ -85,9 +85,11 @@ typedef struct { #define UICULTURES_START_IDX NUM_CACHED_CULTURES /* - * The "os_handle" field of the WaitHandle class. + * The "os_handle" field or the "safe_wait_handle" field of the WaitHandle class. + * the former is used for 1.x profiles, the later for 2.0 */ static MonoClassField *wait_handle_os_handle_field = NULL; +static MonoClassField *wait_handle_safe_handle_field = NULL; /* Controls access to the 'threads' hash table */ #define mono_threads_lock() EnterCriticalSection (&threads_mutex) @@ -856,6 +858,20 @@ gboolean ves_icall_System_Threading_Thread_Join_internal(MonoThread *this, return(FALSE); } +static void +ensure_wait_handle_fields () +{ + MonoClass *klass; + + if (wait_handle_os_handle_field == 0 && wait_handle_safe_handle_field == 0) { + /* Get the field os_handle which will contain the actual handle */ + klass = mono_class_from_name(mono_defaults.corlib, "System.Threading", "WaitHandle"); + wait_handle_os_handle_field = mono_class_get_field_from_name(klass, "os_handle"); + if (wait_handle_os_handle_field == NULL) + wait_handle_safe_handle_field = mono_class_get_field_from_name (klass, "safe_wait_handle"); + } +} + /* FIXME: exitContext isnt documented */ gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext) { @@ -864,7 +880,6 @@ gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_ guint32 ret; guint32 i; MonoObject *waitHandle; - MonoClass *klass; MonoThread *thread = mono_thread_current (); MONO_ARCH_SAVE_REGS; @@ -875,15 +890,18 @@ gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_ numhandles = mono_array_length(mono_handles); handles = g_new0(HANDLE, numhandles); - if (wait_handle_os_handle_field == 0) { - /* Get the field os_handle which will contain the actual handle */ - klass = mono_class_from_name(mono_defaults.corlib, "System.Threading", "WaitHandle"); - wait_handle_os_handle_field = mono_class_get_field_from_name(klass, "os_handle"); - } + ensure_wait_handle_fields (); for(i = 0; i < numhandles; i++) { - waitHandle = mono_array_get(mono_handles, MonoObject*, i); - mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]); + waitHandle = mono_array_get(mono_handles, MonoObject*, i); + if (wait_handle_os_handle_field != NULL) + mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]); + else { + MonoSafeHandle *sh; + + mono_field_get_value(waitHandle, wait_handle_safe_handle_field, &sh); + handles [i] = sh->handle; + } } if(ms== -1) { @@ -926,7 +944,6 @@ gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_ha guint32 ret; guint32 i; MonoObject *waitHandle; - MonoClass *klass; MonoThread *thread = mono_thread_current (); MONO_ARCH_SAVE_REGS; @@ -937,15 +954,18 @@ gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_ha numhandles = mono_array_length(mono_handles); handles = g_new0(HANDLE, numhandles); - if (wait_handle_os_handle_field == 0) { - /* Get the field os_handle which will contain the actual handle */ - klass = mono_class_from_name(mono_defaults.corlib, "System.Threading", "WaitHandle"); - wait_handle_os_handle_field = mono_class_get_field_from_name(klass, "os_handle"); - } - + ensure_wait_handle_fields (); + for(i = 0; i < numhandles; i++) { - waitHandle = mono_array_get(mono_handles, MonoObject*, i); - mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]); + waitHandle = mono_array_get(mono_handles, MonoObject*, i); + if (wait_handle_os_handle_field != NULL) + mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]); + else { + MonoSafeHandle *sh; + + mono_field_get_value(waitHandle, wait_handle_safe_handle_field, &sh); + handles [i] = sh->handle; + } } if(ms== -1) { diff --git a/mono/metadata/verify.c b/mono/metadata/verify.c index 4c8a8ed5461..4cb45fbe8f5 100644 --- a/mono/metadata/verify.c +++ b/mono/metadata/verify.c @@ -2582,6 +2582,17 @@ globalization_classes_to_check [] = { {NULL, NULL} }; +static const FieldDesc +safe_handle_fields[] ={ + {"handle", G_STRUCT_OFFSET (MonoSafeHandle, handle)}, + {NULL, 0} +}; + +static const ClassDesc interop_classes_to_check [] = { + {"SafeHandle", safe_handle_fields}, + {NULL, NULL} +}; + typedef struct { const char *name; const ClassDesc *types; @@ -2597,6 +2608,7 @@ namespaces_to_check[] = { {"System.Diagnostics", system_diagnostics_classes_to_check}, {"System", system_classes_to_check}, {"System.Globalization", globalization_classes_to_check}, + {"System.Runtime.InteropServices", interop_classes_to_check}, {NULL, NULL} }; -- 2.11.4.GIT