microsoft / ClearScript

A library for adding scripting to .NET applications. Supports V8 (Windows, Linux, macOS) and JScript/VBScript (Windows).
https://microsoft.github.io/ClearScript/
MIT License
1.77k stars 148 forks source link

Interrupt not working after await or if is async operations awaiting inside javascript #466

Closed dementcore closed 1 year ago

dementcore commented 1 year ago

Hello!! Is there a way to interrupt execution when is async operations waiting or after an await?

In this example code (console project) the scripts never ends if the line taskCompletionSource.SetResult("input from host"); is commented. If the line taskCompletionSource.SetResult("input from host"); is uncommented the script ends normally and is not interrupted.

  internal class Program
    {
        static void Main(string[] args)
        {
            TaskCompletionSource<string> taskCompletionSource = new TaskCompletionSource<string>();

            var flags = V8ScriptEngineFlags.EnableTaskPromiseConversion | V8ScriptEngineFlags.HideHostExceptions |
                V8ScriptEngineFlags.EnableStringifyEnhancements | V8ScriptEngineFlags.EnableDateTimeConversion
                | V8ScriptEngineFlags.DisableGlobalMembers;

            V8ScriptEngine engine;

            engine = new V8ScriptEngine(flags);
            engine.EnableRuntimeInterruptPropagation = true;
            engine.SuppressExtensionMethodEnumeration = true;

            engine.AddHostObject("api", new API(taskCompletionSource));
            engine.Script.done = new ManualResetEventSlim();
            var code = @"
            async function main() {
                api.WriteLine('before await');
                var inputFromHost = await api.GetInputFromHost();
                api.WriteLine('after await');
                api.WriteLine(inputFromHost);
                done.Set();
            }

            main();
";

            engine.Execute(code);
            //taskCompletionSource.SetResult("input from host"); //uncommenting this line makes the script ends but is never interrupted
            engine.Interrupt();

            engine.Script.done.Wait();
            Console.WriteLine("Script finished");
            Console.ReadLine();
        }
    }

    public class API
    {
        TaskCompletionSource<string> taskCompletionSource;

        public API(TaskCompletionSource<string> taskCompletionSource)
        {
            this.taskCompletionSource = taskCompletionSource;
        }

        public Task<string> GetInputFromHost()
        {
            return taskCompletionSource.Task;
        }

        public void WriteLine(string data)
        {
            Console.WriteLine(data);
        }
    }

I´m doing something wrong or this is a bug?

Tested on Microsoft.ClearScript.V8.Native.win-x64 v7.3.5

ClearScriptLib commented 1 year ago

Hi @dementcore,

The Interrupt method isn't "async-aware". When called, it does nothing if the engine isn't executing script code. The best you can do is "awake" the script code by setting your task to a completed state.

Cheers!

dementcore commented 1 year ago

Thanks for your answer.

If you uncomment the line taskCompletionSource.SetResult the script “awakes” but is not interrupted and ends normally.

It should get interrupted inmediately, right?

ClearScriptLib commented 1 year ago

The SetResult call triggers synchronous re-entry into main, which then returns before you call Interrupt.

dementcore commented 1 year ago

Hi @ClearScriptLib!! Now i understand it. Thank you very much for your answer.