1 // =================================
  2 // Copyright (c) 2025 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 using System.IO;
  8 
  9 namespace System.Threading
 10 {
 11     public enum ConditionVariableStatus : int
 12     {
 13         timeout = 0, no_timeout = 1
 14     }
 15 
 16     public delegate bool Predicate(void* arg);
 17     public class delegate bool PredicateMethod(void* arg);
 18 
 19     public class ConditionVariable
 20     {
 21         public ConditionVariable() : nativeHandle(RtmAllocateConditionVariable())
 22         {
 23         }
 24         public ~ConditionVariable()
 25         {
 26             if (nativeHandle != null)
 27             {
 28                 RtmFreeConditionVariable(nativeHandle);
 29             }
 30         }
 31         suppress ConditionVariable(const ConditionVariable&);
 32         suppress void operator=(ConditionVariable&);
 33         public ConditionVariable(ConditionVariable&& that) : nativeHandle(that.nativeHandle)
 34         {
 35             that.nativeHandle = null;
 36         }
 37         public void operator=(ConditionVariable&& that)
 38         {
 39             Swap(nativeHandle, that.nativeHandle);
 40         }
 41         [nodiscard]
 42         public Result<bool> NotifyOne()
 43         {
 44             int errorId = 0;
 45             bool result = RtmNotifyOne(nativeHandle, errorId);
 46             if (errorId > 0)
 47             {
 48                 return Result<bool>(ErrorId(errorId));
 49             }
 50             return Result<bool>(true);
 51         }
 52         [nodiscard]
 53         public Result<bool> NotifyAll()
 54         {
 55             int errorId = 0;
 56             bool result = RtmNotifyAll(nativeHandle, errorId);
 57             if (errorId > 0)
 58             {
 59                 return Result<bool>(ErrorId(errorId));
 60             }
 61             return Result<bool>(true);
 62         }
 63         [nodiscard]
 64         public Result<bool> Wait(RecursiveMutex& mtx)
 65         {
 66             int errorId = 0;
 67             bool result = RtmWaitConditionVariable(nativeHandle, mtx.NativeHandle(), errorId);
 68             if (errorId > 0)
 69             {
 70                 return Result<bool>(ErrorId(errorId));
 71             }
 72             return Result<bool>(true);
 73         }
 74         [nodiscard]
 75         public Result<ConditionVariableStatus> WaitFor(RecursiveMutex& mtx, const Duration& duration)
 76         {
 77             int errorId = 0;
 78             int result = RtmWaitConditionVariableDuration(nativeHandle, mtx.NativeHandle(), duration.Rep(), errorId);
 79             if (errorId > 0)
 80             {
 81                 return Result<ConditionVariableStatus>(ErrorId(errorId));
 82             }
 83             return Result<ConditionVariableStatus>(cast<ConditionVariableStatus>(result));
 84         }
 85         [nodiscard]
 86         public Result<ConditionVariableStatus> WaitUntil(RecursiveMutex& mtx, const TimePoint& tp)
 87         {
 88             Duration duration = tp - Now();
 89             return WaitFor(mtx, duration);
 90         }
 91         [nodiscard]
 92         public Result<bool> Wait(RecursiveMutex& mtx, Predicate predicate, void* arg)
 93         {
 94             while (!predicate(arg))
 95             {
 96                 auto result = Wait(mtx);
 97                 if (result.Error())
 98                 {
 99                     return result;
100                 }
101             }
102             return Result<bool>(true);
103         }
104         [nodiscard]
105         public Result<bool> WaitFor(RecursiveMutex& mtx, Predicate predicate, void* arg, const Duration& duration)
106         {
107             while (!predicate(arg))
108             {
109                 auto result = WaitFor(mtx, duration);
110                 if (result.Error())
111                 {
112                     return Result<bool>(ErrorId(result.GetErrorId()));
113                 }
114                 if (result.Value() == ConditionVariableStatus.timeout)
115                 {
116                     return predicate(arg);
117                 }
118             }
119             return Result<bool>(true);
120         }
121         [nodiscard]
122         public Result<bool> WaitUntil(RecursiveMutex& mtx, Predicate predicate, void* arg, const TimePoint& tp)
123         {
124             Duration duration = tp - Now();
125             return WaitFor(mtx, predicate, arg, duration);
126         }
127         [nodiscard]
128         public Result<bool> Wait(RecursiveMutex& mtx, PredicateMethod predicateMethod, void* arg)
129         {
130             while (!predicateMethod(arg))
131             {
132                 auto result = Wait(mtx);
133                 if (result.Error())
134                 {
135                     return result;
136                 }
137             }
138             return Result<bool>(true);
139         }
140         [nodiscard]
141         public Result<bool> WaitFor(RecursiveMutex& mtx, PredicateMethod predicateMethod, void* arg, const Duration& duration)
142         {
143             while (!predicateMethod(arg))
144             {
145                 auto result = WaitFor(mtx, duration);
146                 if (result.Error())
147                 {
148                     return Result<bool>(ErrorId(result.GetErrorId()));
149                 }
150                 if (result.Value() == ConditionVariableStatus.timeout)
151                 {
152                     return predicateMethod(arg);
153                 }
154             }
155             return Result<bool>(true);
156         }
157         [nodiscard]
158         public Result<bool> WaitUntil(RecursiveMutex& mtx, PredicateMethod predicateMethod, void* arg, const TimePoint& tp)
159         {
160             Duration duration = tp - Now();
161             return WaitFor(mtx, predicateMethod, arg, duration);
162         }
163         private void* nativeHandle;
164     }