/// <summary>
        /// Entry point.
        /// </summary>
        public static void Main()
        {
            var threadExitCallbackDelegatePtr = Marshal.GetFunctionPointerForDelegate(ThreadExitCallbackDelegate);
            var callbackId = UnmanagedThread.SetThreadExitCallback(threadExitCallbackDelegatePtr);

            for (var i = 1; i <= ThreadCount; i++)
            {
                var threadLocalVal = i;

                var thread = new Thread(_ =>
                {
                    Console.WriteLine($"Managed thread #{threadLocalVal} started.");
                    UnmanagedThread.EnableCurrentThreadExitEvent(callbackId, new IntPtr(threadLocalVal));
                    Thread.Sleep(100);
                    Console.WriteLine($"Managed thread #{threadLocalVal} ended.");
                });

                thread.Start();
            }

            UnmanagedThreadsExitEvent.Wait();
            Console.WriteLine("All unmanaged threads have exited.");

            UnmanagedThread.RemoveThreadExitCallback(callbackId);
        }
Exemple #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="_instance"/> class.
        /// </summary>
        private Jvm(IntPtr jvmPtr)
        {
            Debug.Assert(jvmPtr != IntPtr.Zero);

            _jvmPtr = jvmPtr;

            var funcPtr = (JvmInterface **)jvmPtr;
            var func    = **funcPtr;

            GetDelegate(func.AttachCurrentThread, out _attachCurrentThread);

            // JVM is a singleton, so this is one-time subscription.
            // This is a shortcut - we pass DetachCurrentThread pointer directly as a thread exit callback,
            // because signatures happen to match exactly.
            _threadExitCallbackId = UnmanagedThread.SetThreadExitCallback(func.DetachCurrentThread);

            var env = AttachCurrentThread();

            _methodId = new MethodId(env);

            // Keep AppDomain check here to avoid JITting GetCallbacksFromDefaultDomain method on .NET Core
            // (which fails due to _AppDomain usage).
            _callbacks = AppDomain.CurrentDomain.IsDefaultAppDomain()
                ? new Callbacks(env, this)
                : GetCallbacksFromDefaultDomain();
        }
        public void TestInvalidCallbackIdThrowsException()
        {
            Assert.Throws <InvalidOperationException>(() =>
                                                      UnmanagedThread.EnableCurrentThreadExitEvent(int.MaxValue, new IntPtr(1)));

            Assert.Throws <InvalidOperationException>(() =>
                                                      UnmanagedThread.RemoveThreadExitCallback(int.MaxValue));
        }
Exemple #4
0
        /// <summary>
        /// Attaches current thread to the JVM and returns JNIEnv.
        /// </summary>
        public Env AttachCurrentThread()
        {
            if (_env == null)
            {
                IntPtr envPtr;
                var    res = _attachCurrentThread(_jvmPtr, out envPtr, IntPtr.Zero);

                if (res != JniResult.Success)
                {
                    throw new IgniteException("AttachCurrentThread failed: " + res);
                }

                _env = new Env(envPtr, this);
                UnmanagedThread.EnableCurrentThreadExitEvent(_threadExitCallbackId, _jvmPtr);
            }

            return(_env);
        }
Exemple #5
0
        public void TestThreadExitFiresWhenEnabled([Values(true, false)] bool enableThreadExitCallback)
        {
            using (var evt = new ManualResetEventSlim())
            {
                var threadLocalVal       = new IntPtr(42);
                var resultThreadLocalVal = IntPtr.Zero;

                UnmanagedThread.ThreadExitCallback callback = val =>
                {
                    // ReSharper disable once AccessToDisposedClosure
                    evt.Set();
                    resultThreadLocalVal = val;
                };

                GC.KeepAlive(callback);
                var callbackId = UnmanagedThread.SetThreadExitCallback(Marshal.GetFunctionPointerForDelegate(callback));

                try
                {
                    ParameterizedThreadStart threadStart = _ =>
                    {
                        if (enableThreadExitCallback)
                        {
                            UnmanagedThread.EnableCurrentThreadExitEvent(callbackId, threadLocalVal);
                        }
                    };

                    var t = new Thread(threadStart);

                    t.Start();
                    t.Join();

                    var threadExitCallbackCalled = evt.Wait(TimeSpan.FromSeconds(1));

                    Assert.AreEqual(enableThreadExitCallback, threadExitCallbackCalled);
                    Assert.AreEqual(enableThreadExitCallback ? threadLocalVal : IntPtr.Zero, resultThreadLocalVal);
                }
                finally
                {
                    UnmanagedThread.RemoveThreadExitCallback(callbackId);
                }
            }
        }