Как создать универсальный класс из внутреннего вызова, получая сбой «Невозможно перенести поток ... из STATE_BLOCKING с DO_BLOCKING» - PullRequest
0 голосов
/ 17 мая 2019

Я встраиваю mono и пытаюсь создать экземпляр универсального класса из внутреннего вызова с помощью mono API.

Я получаю List из базовой библиотеки, затем создаю List<string>, вызывая Type.MakeGenericType.Кажется, это работает, но я получаю сбой в будущем.

Я получаю mono_coop_cond_broadcast Cannot transition thread ... from STATE_BLOCKING with DO_BLOCKING изнутри mono_runtime_object_init.

main.cpp:

#include <mono/jit/jit.h>
#include <mono/metadata/assembly.h>

#include <assert.h>

#define ASSERT(cond, msg) assert(cond && msg)

MonoDomain* domain = nullptr;

MonoClass* createListClass(MonoClass* elemClass) {
  auto listCls = mono_class_from_name(mono_get_corlib(), "System.Collections.Generic", "List`1");
  ASSERT(listCls, "Unable to find list class");
  auto listObj = mono_type_get_object(domain, mono_class_get_type(listCls));

  auto listObjClass = mono_object_get_class((MonoObject*)listObj);
  auto makeGeneric = mono_class_get_method_from_name(listObjClass, "MakeGenericType", 1);
  ASSERT(makeGeneric, "Unable to find make generic method");

  auto metaClass = mono_class_from_name(mono_get_corlib(), "System", "Type");
  ASSERT(metaClass, "Unable to find type class");

  auto argArray = mono_array_new(domain, metaClass, 1);
  auto elemTypeObj = mono_type_get_object(domain, mono_class_get_type(elemClass));
  mono_array_set(argArray, MonoReflectionType*, 0, elemTypeObj);

  void* args[] = {argArray};
  auto retObj = mono_runtime_invoke(makeGeneric, listObj, args, nullptr);
  ASSERT(retObj, "Unable to instantiate generic type");

  auto retType = mono_reflection_type_get_type((MonoReflectionType*)retObj);
  ASSERT(retType, "Unable to get type from reflection type");

  auto retClass = mono_class_from_mono_type(retType);
  bool inited = mono_class_init(retClass);
  ASSERT(inited, "Unable to init class");

  return retClass;
}

extern "C" MonoObject* InternalCall() {
  auto stringList = createListClass(mono_get_string_class());

  auto inst = mono_object_new(domain, stringList);

  mono_runtime_object_init(inst); // <-- crash here

  return inst;
}

int main(int argc, char** argv) {
    ASSERT(argc > 1, "Requres at least one argument: assembly path");

    domain = mono_jit_init  ("intergen");
    ASSERT(domain, "Failed to init domain");

    mono_add_internal_call("Foo::Bar", (void*)InternalCall);

    auto assembly = mono_domain_assembly_open(domain, argv[1]);
    ASSERT(assembly, "Failed to open assembly");

    auto ret = mono_jit_exec(domain, assembly, argc - 1, argv + 1);

    mono_jit_cleanup(domain);

    return ret;
}

main.cs:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;

class Foo
{
    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    public extern static List<string> Bar();

    static void Main()
    {
        Console.WriteLine(Bar());
    }
}

То же происходит сбой, когда я пытаюсь вызвать mono_object_to_string для любого MonoReflectionType* экземпляра (даже если я не уверен, что это допустимая операция).

Что я делаю не так?Правильно ли, что приведение MonoReflectionType* к MonoObject* является допустимой операцией?

...