aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Horizon/Sdk/OsTypes/OsEvent.cs
blob: 8efe614f2dc0e77f9f5e8746b97b98dee1a30399 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
using System;
using System.Collections.Generic;
using System.Threading;

namespace Ryujinx.Horizon.Sdk.OsTypes
{
    static partial class Os
    {
        public static void InitializeEvent(out EventType evnt, bool signaled, EventClearMode clearMode)
        {
            evnt = new EventType
            {
                MultiWaitHolders = new LinkedList<MultiWaitHolderBase>(),
                Signaled = signaled,
                InitiallySignaled = signaled,
                ClearMode = clearMode,
                State = InitializationState.Initialized,
                Lock = new object(),
            };
        }

        public static void FinalizeEvent(ref EventType evnt)
        {
            evnt.State = InitializationState.NotInitialized;
        }

        public static void WaitEvent(ref EventType evnt)
        {
            lock (evnt.Lock)
            {
                ulong currentCounter = evnt.BroadcastCounter;

                while (!evnt.Signaled)
                {
                    if (currentCounter != evnt.BroadcastCounter)
                    {
                        break;
                    }

                    Monitor.Wait(evnt.Lock);
                }

                if (evnt.ClearMode == EventClearMode.AutoClear)
                {
                    evnt.Signaled = false;
                }
            }
        }

        public static bool TryWaitEvent(ref EventType evnt)
        {
            lock (evnt.Lock)
            {
                bool signaled = evnt.Signaled;

                if (evnt.ClearMode == EventClearMode.AutoClear)
                {
                    evnt.Signaled = false;
                }

                return signaled;
            }
        }

        public static bool TimedWaitEvent(ref EventType evnt, TimeSpan timeout)
        {
            lock (evnt.Lock)
            {
                ulong currentCounter = evnt.BroadcastCounter;

                while (!evnt.Signaled)
                {
                    if (currentCounter != evnt.BroadcastCounter)
                    {
                        break;
                    }

                    bool wasSignaledInTime = Monitor.Wait(evnt.Lock, timeout);
                    if (!wasSignaledInTime)
                    {
                        return false;
                    }
                }

                if (evnt.ClearMode == EventClearMode.AutoClear)
                {
                    evnt.Signaled = false;
                }
            }

            return true;
        }

        public static void SignalEvent(ref EventType evnt)
        {
            lock (evnt.Lock)
            {
                if (evnt.Signaled)
                {
                    return;
                }

                evnt.Signaled = true;

                if (evnt.ClearMode == EventClearMode.ManualClear)
                {
                    evnt.BroadcastCounter++;
                    Monitor.PulseAll(evnt.Lock);
                }
                else
                {
                    Monitor.Pulse(evnt.Lock);
                }

                foreach (MultiWaitHolderBase holder in evnt.MultiWaitHolders)
                {
                    holder.GetMultiWait().NotifyAndWakeUpThread(holder);
                }
            }
        }

        public static void ClearEvent(ref EventType evnt)
        {
            lock (evnt.Lock)
            {
                evnt.Signaled = false;
            }
        }
    }
}