Guo Hui 6 роки тому
батько
коміт
f11f00a1e7

+ 3 - 0
src/Chino.Chip.Emulator/ChipControl.cs

@@ -32,5 +32,8 @@ namespace Chino
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         public static extern void SetupSystemTimer(TimeSpan timeSlice);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern void RestoreContext(in ThreadContextArch context);
     }
 }

+ 3 - 0
src/Chino.Kernel/KernelServices.cs

@@ -9,9 +9,12 @@ namespace Chino
     {
         public static Scheduler Scheduler { get; private set; }
 
+        public static IRQDispatcher IRQDispatcher { get; private set; }
+
         internal static void Initialize()
         {
             Scheduler = new Scheduler();
+            IRQDispatcher = new IRQDispatcher();
         }
     }
 }

+ 50 - 0
src/Chino.Kernel/Threading/IRQDispatcher.cs

@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+using System.Threading;
+using Chino.Chip;
+
+namespace Chino.Threading
+{
+    public enum SystemIRQ : uint
+    {
+        SystemTick,
+        COUNT
+    }
+
+    public delegate void SystemIRQHandler(SystemIRQ irq, in ThreadContextArch context);
+
+    public class IRQDispatcher
+    {
+        private readonly SystemIRQHandler?[] _systemIRQHandlers = new SystemIRQHandler?[(int)SystemIRQ.COUNT];
+
+        public void RegisterSystemIRQ(SystemIRQ irq, SystemIRQHandler? handler)
+        {
+            Debug.Assert(irq < SystemIRQ.COUNT);
+            Volatile.Write(ref _systemIRQHandlers[(int)irq], handler);
+        }
+
+        internal void DispatchSystemIRQ(SystemIRQ irq, in ThreadContextArch context)
+        {
+            Debug.Assert(irq < SystemIRQ.COUNT);
+            var handler = Volatile.Read(ref _systemIRQHandlers[(int)irq]);
+            if (handler != null)
+                handler(irq, context);
+            else
+                UnhandledIRQ(irq);
+
+            ExitIRQHandler();
+        }
+
+        private void ExitIRQHandler()
+        {
+            ChipControl.RestoreContext(KernelServices.Scheduler.SelectedThread.Value.Thread.Context.Arch);
+        }
+
+        private void UnhandledIRQ(SystemIRQ irq)
+        {
+            Debug.Fail("Unhandled IRQ");
+        }
+    }
+}

+ 17 - 1
src/Chino.Kernel/Threading/Scheduler.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
+using Chino.Chip;
 using Chino.Collections;
 
 namespace Chino.Threading
@@ -10,12 +11,14 @@ namespace Chino.Threading
         private readonly LinkedList<ThreadScheduleEntry> _readyThreads = new LinkedList<ThreadScheduleEntry>();
         private readonly LinkedList<ThreadScheduleEntry> _suspendedThreads = new LinkedList<ThreadScheduleEntry>();
         private LinkedListNode<ThreadScheduleEntry>? _runningThread = null;
-        private LinkedListNode<ThreadScheduleEntry>? _selectedThread = null;
+        private LinkedListNode<ThreadScheduleEntry> _selectedThread;
         private readonly Thread _idleThread;
         private bool _isRunning;
 
         public TimeSpan TimeSlice { get; private set; } = TimeSpan.FromMilliseconds(10);
 
+        public LinkedListNode<ThreadScheduleEntry> SelectedThread => _selectedThread;
+
         public ulong TickCount { get; private set; }
 
         public Scheduler()
@@ -37,6 +40,7 @@ namespace Chino.Threading
             _isRunning = true;
             Debug.Assert(_selectedThread != null);
             _runningThread = _selectedThread;
+            KernelServices.IRQDispatcher.RegisterSystemIRQ(SystemIRQ.SystemTick, OnSystemTick);
             ChipControl.SetupSystemTimer(TimeSlice);
             ChipControl.StartSchedule(_selectedThread.Value.Thread.Context.Arch);
 
@@ -55,6 +59,18 @@ namespace Chino.Threading
             }
         }
 
+        private void OnSystemTick(SystemIRQ irq, in ThreadContextArch context)
+        {
+            Debug.Assert(_runningThread != null);
+            Debug.Assert(_runningThread.Next != null);
+            Debug.Assert(_readyThreads.First != null);
+
+            var nextThread = _runningThread.Next;
+            if (nextThread == null)
+                nextThread = _readyThreads.First;
+            _selectedThread = nextThread;
+        }
+
         private void IdleMain()
         {
             while (true) ;

+ 0 - 8
src/Native/arch/emulator/crt.cpp

@@ -5,14 +5,6 @@ using namespace natsu;
 using namespace System_Runtime::System;
 using namespace Chino_Chip_Emulator::Chino;
 
-void ChipControl::_s_Initialize()
-{
-    system(" ");
-
-    auto dev = make_object<Chip::Emulator::HAL::IO::Console>();
-    Chip::Emulator::HAL::IO::Console::Install(dev);
-}
-
 void ChipControl::_s_Write(gc_obj_ref<String> message)
 {
     WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), &message->_firstChar, message->_stringLength, nullptr, nullptr);

+ 115 - 9
src/Native/arch/emulator/schedule.cpp

@@ -1,10 +1,12 @@
 #include "Chino.Kernel.h"
 #include "win_utils.h"
 #include <Windows.h>
+#include <process.h>
 #include <wrl.h>
 
 using namespace natsu;
 using namespace System_Runtime::System;
+using namespace Chino_Kernel::Chino;
 using namespace Chino_Kernel::Chino::Threading;
 using namespace Chino_Chip_Emulator::Chino;
 using namespace Chino_Chip_Emulator::Chino::Chip;
@@ -12,34 +14,134 @@ using namespace Microsoft::WRL::Wrappers;
 
 namespace
 {
-bool g_interrupt_enabled = false;
+std::atomic<bool> g_interrupt_enabled(false);
+CRITICAL_SECTION g_interrupt_cs;
+Event g_interrupt_enabled_event(CreateEvent(nullptr, TRUE, FALSE, nullptr));
 TP_TIMER *g_system_timer;
 
+Semaphore g_interrupt_count(CreateSemaphore(nullptr, 0, 10240, nullptr));
+std::atomic<bool> g_system_timer_int(false);
+
+void suspend_thread(ThreadContextArch &context)
+{
+    auto handle = (HANDLE)context.NativeHandle._value;
+    SuspendThread(handle);
+    CONTEXT c { CONTEXT_ALL };
+    THROW_WIN32_IF_NOT(GetThreadContext(handle, &c));
+}
+
 void resume_thread(ThreadContextArch &context)
 {
     ResumeThread((HANDLE)context.NativeHandle._value);
 }
 
+void notify_interrupt()
+{
+    THROW_WIN32_IF_NOT(ReleaseSemaphore(g_interrupt_count.Get(), 1, NULL));
+}
+
 void system_timer_thunk(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_TIMER Timer)
 {
+    g_system_timer_int.store(true, std::memory_order_relaxed);
+    notify_interrupt();
 }
+
+void interrupt_sender_main(void *arg)
+{
+    while (true)
+    {
+        if (g_interrupt_enabled.load(std::memory_order_acquire))
+        {
+            if (WaitForSingleObject(g_interrupt_count.Get(), INFINITE) == WAIT_ABANDONED)
+                break;
+
+            {
+                auto leave = natsu::make_finally([&] { LeaveCriticalSection(&g_interrupt_cs); });
+                EnterCriticalSection(&g_interrupt_cs);
+
+                ThreadContextArch context;
+                // Suspend running thread
+                auto running_thread_entry = KernelServices::_s_get_Scheduler()->_runningThread;
+                if (running_thread_entry)
+                {
+                    auto running_thread = running_thread_entry->item->_Thread_k__BackingField;
+                    // Wait for suspended
+                    suspend_thread(running_thread->Context.Arch);
+                    context = running_thread->Context.Arch;
+                }
+
+                if (g_system_timer_int.exchange(false))
+                {
+                    IRQDispatcher::DispatchSystemIRQ(KernelServices::_s_get_IRQDispatcher(),
+                        SystemIRQ::from(SystemIRQ::SystemTick), context);
+                }
+            }
+        }
+        else
+        {
+            if (WaitForSingleObject(g_interrupt_enabled_event.Get(), INFINITE) == WAIT_ABANDONED)
+                break;
+        }
+    }
+}
+}
+
+void ChipControl::_s_Initialize()
+{
+    system(" ");
+
+    // Init interrupt lock
+    THROW_WIN32_IF_NOT(InitializeCriticalSectionEx(&g_interrupt_cs, 300, 0));
+    EnterCriticalSection(&g_interrupt_cs);
+    // Init interrupt sender thread
+    auto intr_thrd = _beginthread(interrupt_sender_main, 0, nullptr);
+    assert(intr_thrd);
+    assert(g_interrupt_enabled_event.IsValid());
+    assert(g_interrupt_count.IsValid());
+    THROW_IF_FAILED(SetThreadDescription((HANDLE)intr_thrd, L"Interrupt Sender"));
+
+    auto dev = make_object<Chip::Emulator::HAL::IO::Console>();
+    Chip::Emulator::HAL::IO::Console::Install(dev);
 }
 
 UIntPtr ChipControl::_s_DisableInterrupt()
 {
-    g_interrupt_enabled = false;
-    return g_interrupt_enabled;
+    if (g_interrupt_enabled.exchange(false))
+    {
+        EnterCriticalSection(&g_interrupt_cs);
+        THROW_WIN32_IF_NOT(ResetEvent(g_interrupt_enabled_event.Get()));
+    }
+
+    return 0;
 }
 
 UIntPtr ChipControl::_s_EnableInterrupt()
 {
-    g_interrupt_enabled = true;
-    return g_interrupt_enabled;
+    if (!g_interrupt_enabled.exchange(true))
+    {
+        LeaveCriticalSection(&g_interrupt_cs);
+        THROW_WIN32_IF_NOT(SetEvent(g_interrupt_enabled_event.Get()));
+    }
+
+    return 1;
 }
 
 void ChipControl::_s_RestoreInterrupt(UIntPtr state)
 {
-    g_interrupt_enabled = state;
+    auto old_state = g_interrupt_enabled.exchange(state, std::memory_order_release);
+    if (old_state != state)
+    {
+        if (state)
+        {
+            EnterCriticalSection(&g_interrupt_cs);
+            THROW_WIN32_IF_NOT(SetEvent(g_interrupt_enabled_event.Get()));
+        }
+        else
+        {
+            LeaveCriticalSection(&g_interrupt_cs);
+            THROW_WIN32_IF_NOT(ResetEvent(g_interrupt_enabled_event.Get()));
+        }
+    }
 }
 
 void ChipControl::_s_StartSchedule(gc_ref<ThreadContextArch> context)
@@ -51,10 +153,14 @@ void ChipControl::_s_StartSchedule(gc_ref<ThreadContextArch> context)
 
 void ChipControl::_s_SetupSystemTimer(TimeSpan timeSlice)
 {
+    FILETIME due_time = ticks_to_filetime(TimeSpan::get_Ticks(timeSlice));
     g_system_timer = CreateThreadpoolTimer(system_timer_thunk, nullptr, nullptr);
     THROW_WIN32_IF_NOT(g_system_timer);
+    SetThreadpoolTimer(g_system_timer, &due_time, (DWORD)TimeSpan::get_TotalMilliseconds(timeSlice), 0);
+}
 
-    LARGE_INTEGER due_time;
-    due_time.QuadPart = TimeSpan::get_Ticks(timeSlice);
-    //THROW_WIN32_IF_NOT(SetWaitableTimer(g_system_timer.Get(), &due_time, due_time.QuadPart, system_timer_thunk, nullptr, FALSE));
+void ChipControl::_s_RestoreContext(gc_ref<ThreadContextArch> context)
+{
+    // Run selected thread
+    resume_thread(*context);
 }

+ 14 - 0
src/Native/arch/emulator/win_utils.h

@@ -7,3 +7,17 @@
     {                                 \
         throw std::runtime_error(#x); \
     }
+
+#define THROW_IF_FAILED(x)            \
+    if (FAILED(x))                    \
+    {                                 \
+        throw std::runtime_error(#x); \
+    }
+
+inline FILETIME ticks_to_filetime(uint64_t ticks)
+{
+    ULARGE_INTEGER u;
+    u.QuadPart = ticks;
+    FILETIME ft { u.LowPart, u.HighPart };
+    return ft;
+}

+ 13 - 2
src/Native/natsu.runtime.h

@@ -3,6 +3,7 @@
 #include "natsu.typedef.h"
 #include <cmath>
 #include <limits>
+#include <optional>
 #include <utility>
 #if _MSC_VER
 #include <malloc.h>
@@ -221,13 +222,23 @@ public:
     {
     }
 
+    clr_finally(clr_finally &) = delete;
+    clr_finally &operator=(clr_finally &) = delete;
+
+    clr_finally(clr_finally &&other)
+        : call_(std::move(other.call_))
+    {
+        other.call_.reset();
+    }
+
     ~clr_finally()
     {
-        call_();
+        if (call_)
+            (*call_)();
     }
 
 private:
-    TCall call_;
+    std::optional<TCall> call_;
 };
 
 template <class TCall>

+ 26 - 6
src/Native/natsu.typedef.h

@@ -698,12 +698,16 @@ struct static_object
     UIntPtr(uintptr_t value) : _value((uintptr_t)value) {} \
     operator uintptr_t() const noexcept { return (uintptr_t)_value; }
 
-#define NATSU_ENUM_IMPL_BYTE(name) \
-    name &operator=(int32_t value) \
-    {                              \
-        value__ = value;           \
-        return *this;              \
-    }                              \
+#define NATSU_ENUM_IMPL_BYTE(name)  \
+    name &operator=(uint8_t value)  \
+    {                               \
+        value__ = value;            \
+        return *this;               \
+    }                               \
+    static name from(uint8_t value) \
+    {                               \
+        return name { value };      \
+    }                               \
     constexpr operator uint8_t() const noexcept { return value__; }
 
 #define NATSU_ENUM_IMPL_INT32(name) \
@@ -712,8 +716,24 @@ struct static_object
         value__ = value;            \
         return *this;               \
     }                               \
+    static name from(int32_t value) \
+    {                               \
+        return name { value };      \
+    }                               \
     constexpr operator int32_t() const noexcept { return value__; }
 
+#define NATSU_ENUM_IMPL_UINT32(name) \
+    name &operator=(uint32_t value)  \
+    {                                \
+        value__ = value;             \
+        return *this;                \
+    }                                \
+    static name from(uint32_t value) \
+    {                                \
+        return name { value };       \
+    }                                \
+    constexpr operator uint32_t() const noexcept { return value__; }
+
 #define NATSU_OBJECT_IMPL
 
 #define NATSU_PRIMITIVE_OPERATORS_IMPL

+ 16 - 9
src/Natsu.Compiler/Program.cs

@@ -16,18 +16,18 @@ namespace Natsu.Compiler
         {
             @"..\..\..\..\..\out\bin\netcoreapp3.0\Chino.Kernel.dll",
             @"..\..\..\..\..\out\bin\netcoreapp3.0\Chino.Core.dll",
-            @"..\..\..\..\..\out\bin\netcoreapp3.0\Chino.Chip.K210.dll",
+            //@"..\..\..\..\..\out\bin\netcoreapp3.0\Chino.Chip.K210.dll",
             @"..\..\..\..\..\out\bin\netcoreapp3.0\Chino.Chip.Emulator.dll",
             @"..\..\..\..\..\out\bin\netcoreapp3.0\System.Private.CoreLib.dll",
-            @"..\..\..\..\..\out\bin\netcoreapp3.0\System.Collections.dll",
-            @"..\..\..\..\..\out\bin\netcoreapp3.0\System.Memory.dll",
+            //@"..\..\..\..\..\out\bin\netcoreapp3.0\System.Collections.dll",
+            //@"..\..\..\..\..\out\bin\netcoreapp3.0\System.Memory.dll",
             @"..\..\..\..\..\out\bin\netcoreapp3.0\System.Runtime.dll",
-            @"..\..\..\..\..\out\bin\netcoreapp3.0\System.Runtime.Extensions.dll",
-            @"..\..\..\..\..\out\bin\netcoreapp3.0\System.Diagnostics.Debug.dll",
-            @"..\..\..\..\..\out\bin\netcoreapp3.0\System.Runtime.InteropServices.dll",
-            @"..\..\..\..\..\out\bin\netcoreapp3.0\System.Threading.dll",
-            @"..\..\..\..\..\out\bin\netcoreapp3.0\System.Threading.Thread.dll",
-            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), @".nuget\packages\bitfields\0.1.0\lib\netstandard1.0\BitFields.dll")
+            //@"..\..\..\..\..\out\bin\netcoreapp3.0\System.Runtime.Extensions.dll",
+            //@"..\..\..\..\..\out\bin\netcoreapp3.0\System.Diagnostics.Debug.dll",
+            //@"..\..\..\..\..\out\bin\netcoreapp3.0\System.Runtime.InteropServices.dll",
+            //@"..\..\..\..\..\out\bin\netcoreapp3.0\System.Threading.dll",
+            //@"..\..\..\..\..\out\bin\netcoreapp3.0\System.Threading.Thread.dll",
+            //Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), @".nuget\packages\bitfields\0.1.0\lib\netstandard1.0\BitFields.dll")
         };
 
         static void Main(string[] args)
@@ -1049,6 +1049,13 @@ namespace Natsu.Compiler
                         writer.Ident(ident + 1).WriteLine($"return result;");
                     writer.Ident(ident).WriteLine("}");
                 }
+                else if (method.Name == "BeginInvoke")
+                {
+                    writer.Ident(ident).WriteLine($"return natsu::null;");
+                }
+                else if (method.Name == "EndInvoke")
+                {
+                }
                 else
                 {
                     throw new NotSupportedException();

+ 16 - 0
src/System.Private.CoreLib/System/AsyncCallback.cs

@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Interface: AsyncCallbackDelegate
+**
+** Purpose: Type of callback for async operations
+**
+===========================================================*/
+
+namespace System
+{
+    public delegate void AsyncCallback(IAsyncResult ar);
+}

+ 30 - 0
src/System.Private.CoreLib/System/IAsyncResult.cs

@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Interface: IAsyncResult
+**
+** Purpose: Interface to encapsulate the results of an async
+**          operation
+**
+===========================================================*/
+
+using System;
+using System.Threading;
+
+namespace System
+{
+    public interface IAsyncResult
+    {
+        bool IsCompleted { get; }
+
+        //WaitHandle AsyncWaitHandle { get; }
+
+
+        object AsyncState { get; }
+
+        bool CompletedSynchronously { get; }
+    }
+}

+ 7 - 0
src/System.Runtime/TypeForwards.cs

@@ -29,6 +29,7 @@ using System.Text;
 [assembly: TypeForwardedTo(typeof(EventArgs))]
 [assembly: TypeForwardedTo(typeof(EventHandler))]
 [assembly: TypeForwardedTo(typeof(EventHandler<>))]
+[assembly: TypeForwardedTo(typeof(AsyncCallback))]
 [assembly: TypeForwardedTo(typeof(Action))]
 [assembly: TypeForwardedTo(typeof(Action<>))]
 [assembly: TypeForwardedTo(typeof(Action<,>))]
@@ -59,7 +60,13 @@ using System.Text;
 [assembly: TypeForwardedTo(typeof(Span<>))]
 [assembly: TypeForwardedTo(typeof(ReadOnlySpan<>))]
 [assembly: TypeForwardedTo(typeof(TimeSpan))]
+[assembly: TypeForwardedTo(typeof(IAsyncResult))]
 [assembly: TypeForwardedTo(typeof(IDisposable))]
 [assembly: TypeForwardedTo(typeof(ArgumentException))]
 [assembly: TypeForwardedTo(typeof(ArgumentNullException))]
 [assembly: TypeForwardedTo(typeof(ArgumentOutOfRangeException))]
+[assembly: TypeForwardedTo(typeof(NotImplementedException))]
+[assembly: TypeForwardedTo(typeof(IndexOutOfRangeException))]
+[assembly: TypeForwardedTo(typeof(InvalidCastException))]
+[assembly: TypeForwardedTo(typeof(InvalidOperationException))]
+[assembly: TypeForwardedTo(typeof(OutOfMemoryException))]