1 // =================================
  2 // Copyright (c) 2024 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 using System.Threading;
  8 
  9 namespace System.Threading.Fibers
 10 {
 11     public delegate void FiberFunction(void* param);
 12 
 13     internal class FiberData
 14     {
 15         public FiberData(const FiberFunction& function_void* param_) : function(function_)param(param_)
 16         {
 17         }
 18         public inline FiberFunction Function() const
 19         {
 20             return function;
 21         }
 22         public inline void* Param() const
 23         {
 24             return param;
 25         }
 26         private FiberFunction function;
 27         private void* param;
 28     }
 29 
 30     public class Fiber
 31     {
 32         public Fiber() : handle(null)main(true)
 33         {
 34             handle = RtmConvertThreadToFiber(null);
 35         }
 36         public Fiber(const FiberFunction& function) : this(cast<ulong>(1024u) * 1024ufunctionnull)
 37         {
 38         }
 39         public Fiber(const FiberFunction& functionvoid* param) : this(cast<ulong>(1024u) * 1024ufunctionparam)
 40         {
 41         }
 42         public Fiber(ulong stackSizeconst FiberFunction& function) : this(stackSizefunctionnull)
 43         {
 44         }
 45         public Fiber(ulong stackSizeconst FiberFunction& functionvoid* param) : handle(null)main(false)
 46         {
 47             FiberRunFunction runFiber = RunFiber;
 48             void* startAddress = cast<void*>(runFiber);
 49             handle = RtmCreateFiber(stackSizestartAddressnew FiberData(functionparam));
 50         }
 51         [nodiscard]
 52         public Result<bool> SwitchTo()
 53         {
 54             if (handle != null)
 55             {
 56                 RtmSwitchToFiber(handle);
 57             }
 58             else
 59             {
 60                 string errorMessage = "could not switch to this fiber: handle is null";
 61                 int errorId = AllocateError(errorMessage);
 62                 return Result<bool>(ErrorId(errorId));
 63             }
 64             return Result<bool>(true);
 65         }
 66         public suppress Fiber(const Fiber&);
 67         public suppress void operator=(const Fiber&);
 68         public Fiber(Fiber&& that) : handle(that.handle)main(that.main)
 69         {
 70             that.handle = null;
 71             that.main = false;
 72         }
 73         public default void operator=(Fiber&& that);
 74         public ~Fiber()
 75         {
 76             if (handle != null)
 77             {
 78                 if (!main)
 79                 {
 80                     RtmDeleteFiber(handle);
 81                 }
 82             }
 83         }
 84         public inline void* Handle() const
 85         {
 86             return handle;
 87         }
 88         public static Fiber FromCurrentThread()
 89         {
 90             return Fiber();
 91         }
 92         private void* handle;
 93         private bool main;
 94     }
 95 
 96     [nodiscard]
 97     public Result<bool> SwitchToFiber(const Fiber& fiber)
 98     {
 99         return fiber.SwitchTo();
100     }
101 
102     internal delegate void FiberRunFunction();
103 
104     internal void RunFiber()
105     {
106         void* data = RtmGetFiberData();
107         UniquePtr<FiberData> fiberData(cast<FiberData*>(data));
108         FiberFunction function = fiberData->Function();
109         void* param = fiberData->Param();
110         function(param);
111     }