1 /**
2     Win32 Implementation for nulib.threading.internal.semaphore
3 
4     Copyright:
5         Copyright © 2025, Kitsunebi Games
6         Copyright © 2025, Inochi2D Project
7     
8     License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9     Authors:   Luna Nielsen
10 */
11 module nulib.win32.threading.semaphore;
12 import nulib.threading.internal.semaphore;
13 import nulib.win32.common;
14 import numem;
15 
16 /**
17     Native implementation of a semaphore.
18 */
19 class Win32Semaphore : NativeSemaphore {
20 private:
21 @nogc:
22     HANDLE handle_;
23     
24 public:
25 
26     /// Destructor
27     ~this() nothrow {
28         auto rc = CloseHandle(handle_);
29         assert(rc, "Failed to destroy semaphore!");
30     }
31 
32     /**
33         Constructs a new Win32 Semaphore.
34     */
35     this(uint count) nothrow {
36         this.handle_ = CreateSemaphoreA(null, count, int.max, null);
37         assert(handle_, "Failed to create semaphore!");
38     }
39 
40     /**
41         Signals the semaphore.
42 
43         Note:
44             Control is not transferred to the waiter.
45     */
46     override
47     void signal() nothrow @trusted {
48         cast(void)ReleaseSemaphore(handle_, 1, null);
49     }
50 
51     /**
52         Suspends the thread until the semaphore is signaled,
53         or the timeout is reached.
54 
55         Params:
56             timeout =   Timeout in miliseconds to block the 
57                         calling thread before giving up.
58 
59         Returns:
60             $(D true) if the semaphore was signaled in time,
61             $(D false) otherwise.
62     */
63     override
64     bool await(ulong timeout = 0) nothrow @trusted {
65         if (timeout == 0) {
66             return WaitForSingleObject(handle_, INFINITE) == WAIT_OBJECT_0;
67         }
68 
69         long timeLeft = timeout;
70         uint rc;
71         while(timeLeft > 0) {
72             rc = WaitForSingleObject(handle_, timeLeft >= uint.max ? uint.max-1 : cast(uint)timeLeft);
73             if(rc == WAIT_OBJECT_0)
74                 return true;
75 
76             timeLeft -= uint.max-1;
77         }
78         return false;
79     }
80 
81     /**
82         Checks if the semaphore is signalled then
83         awaits on it if is.
84 
85         Returns:
86             $(D true) if the semaphore was signalled,
87             $(D false) otherwise.
88     */
89     override
90     bool tryAwait() nothrow @trusted {
91         return WaitForSingleObject(handle_, 0) == WAIT_OBJECT_0;
92     }
93 }
94 
95 extern(C) export
96 NativeSemaphore _nu_semaphore_new(uint count) @trusted @nogc nothrow {
97     return nogc_new!Win32Semaphore(count);
98 }
99 
100 //
101 //          BINDINGS
102 //
103 extern(Windows) @nogc nothrow:
104 
105 extern HANDLE CreateSemaphoreA(void*, int, int, void*);
106 extern uint ReleaseSemaphore(HANDLE, int, int*);