1717#include < ntstatus.h>
1818#endif
1919
20+ static std::atomic<uint32_t > g_keSetEventGeneration;
21+
22+ static void NotifyWaitForMultipleObjects ()
23+ {
24+ ++g_keSetEventGeneration;
25+ g_keSetEventGeneration.notify_all ();
26+ }
27+
28+ #ifdef UNLEASHED_RECOMP_IOS
29+ static uint32_t GetGuestLinkRegisterForLog ()
30+ {
31+ #ifndef PPC_CONFIG_SKIP_LR
32+ if (auto * ctx = GetPPCContext ())
33+ return uint32_t (ctx->lr );
34+ #endif
35+
36+ return 0 ;
37+ }
38+
39+ static bool ShouldLogKernelWait (uint32_t count)
40+ {
41+ return count <= 128 || (count % 512 ) == 0 ;
42+ }
43+
44+ static const char * GetDispatcherTypeName (uint32_t type)
45+ {
46+ switch (type)
47+ {
48+ case 0 :
49+ return " NotificationEvent" ;
50+ case 1 :
51+ return " SynchronizationEvent" ;
52+ case 5 :
53+ return " Semaphore" ;
54+ default :
55+ return " Unknown" ;
56+ }
57+ }
58+
59+ static void LogKernelWait (const char * name, uint32_t object, uint32_t timeout, int64_t rawTimeout, uint32_t type, uint32_t signalState, uint32_t extra = 0 )
60+ {
61+ static std::atomic<uint32_t > s_waitLogCount;
62+ const uint32_t count = ++s_waitLogCount;
63+ if (!ShouldLogKernelWait (count))
64+ return ;
65+
66+ LOGFN (" iOS wait #{} {} object=0x{:08X} type={}({}) signal={} timeout={} rawTimeout={} extra={} lr=0x{:08X} thread=0x{:08X}" ,
67+ count,
68+ name,
69+ object,
70+ GetDispatcherTypeName (type),
71+ type,
72+ signalState,
73+ timeout,
74+ rawTimeout,
75+ extra,
76+ GetGuestLinkRegisterForLog (),
77+ GuestThread::GetCurrentThreadId ());
78+ }
79+
80+ #endif
81+
2082struct Event final : KernelObject, HostObject<XKEVENT >
2183{
2284 bool manualReset;
@@ -83,6 +145,8 @@ struct Event final : KernelObject, HostObject<XKEVENT>
83145 else
84146 signaled.notify_one ();
85147
148+ NotifyWaitForMultipleObjects ();
149+
86150 return TRUE ;
87151 }
88152
@@ -93,8 +157,6 @@ struct Event final : KernelObject, HostObject<XKEVENT>
93157 }
94158};
95159
96- static std::atomic<uint32_t > g_keSetEventGeneration;
97-
98160struct Semaphore final : KernelObject, HostObject<XKSEMAPHORE >
99161{
100162 std::atomic<uint32_t > count;
@@ -158,9 +220,44 @@ struct Semaphore final : KernelObject, HostObject<XKSEMAPHORE>
158220
159221 count += releaseCount;
160222 count.notify_all ();
223+ NotifyWaitForMultipleObjects ();
161224 }
162225};
163226
227+ #ifdef UNLEASHED_RECOMP_IOS
228+ static const char * GetKernelObjectName (KernelObject* object)
229+ {
230+ if (dynamic_cast <Event*>(object) != nullptr )
231+ return " Event" ;
232+
233+ if (dynamic_cast <Semaphore*>(object) != nullptr )
234+ return " Semaphore" ;
235+
236+ if (dynamic_cast <GuestThreadHandle*>(object) != nullptr )
237+ return " GuestThread" ;
238+
239+ return " KernelObject" ;
240+ }
241+
242+ static void LogKernelHandleWait (const char * name, uint32_t handle, KernelObject* object, uint32_t timeout, int64_t rawTimeout)
243+ {
244+ static std::atomic<uint32_t > s_handleWaitLogCount;
245+ const uint32_t count = ++s_handleWaitLogCount;
246+ if (!ShouldLogKernelWait (count))
247+ return ;
248+
249+ LOGFN (" iOS handle wait #{} {} handle=0x{:08X} objectType={} timeout={} rawTimeout={} lr=0x{:08X} thread=0x{:08X}" ,
250+ count,
251+ name,
252+ handle,
253+ GetKernelObjectName (object),
254+ timeout,
255+ rawTimeout,
256+ GetGuestLinkRegisterForLog (),
257+ GuestThread::GetCurrentThreadId ());
258+ }
259+ #endif
260+
164261inline void CloseKernelObject (XDISPATCHER_HEADER & header)
165262{
166263 if (header.WaitListHead .Flink != OBJECT_SIGNATURE )
@@ -408,7 +505,11 @@ uint32_t NtWaitForSingleObjectEx(uint32_t Handle, uint32_t WaitMode, uint32_t Al
408505
409506 if (IsKernelObject (Handle))
410507 {
411- return GetKernelObject (Handle)->Wait (timeout);
508+ auto * object = GetKernelObject (Handle);
509+ #ifdef UNLEASHED_RECOMP_IOS
510+ LogKernelHandleWait (" NtWaitForSingleObjectEx" , Handle, object, timeout, Timeout ? int64_t (*Timeout) : 0 );
511+ #endif
512+ return object->Wait (timeout);
412513 }
413514 else
414515 {
@@ -569,6 +670,21 @@ uint32_t KeDelayExecutionThread(uint32_t WaitMode, bool Alertable, be<int64_t>*
569670
570671 uint32_t timeout = GuestTimeoutToMilliseconds (Timeout);
571672
673+ #ifdef UNLEASHED_RECOMP_IOS
674+ static std::atomic<uint32_t > s_delayLogCount;
675+ const uint32_t delayLogCount = ++s_delayLogCount;
676+ if (timeout == INFINITE || timeout >= 500 || delayLogCount <= 16 )
677+ {
678+ LOGFN (" iOS delay #{} timeout={} rawTimeout={} waitMode={} lr=0x{:08X} thread=0x{:08X}" ,
679+ delayLogCount,
680+ timeout,
681+ Timeout ? int64_t (*Timeout) : 0 ,
682+ WaitMode,
683+ GetGuestLinkRegisterForLog (),
684+ GuestThread::GetCurrentThreadId ());
685+ }
686+ #endif
687+
572688#ifdef _WIN32
573689 Sleep (timeout);
574690#else
@@ -999,9 +1115,6 @@ bool KeSetEvent(XKEVENT* pEvent, uint32_t Increment, bool Wait)
9991115{
10001116 bool result = QueryKernelObject<Event>(*pEvent)->Set ();
10011117
1002- ++g_keSetEventGeneration;
1003- g_keSetEventGeneration.notify_all ();
1004-
10051118 return result;
10061119}
10071120
@@ -1015,6 +1128,15 @@ uint32_t KeWaitForSingleObject(XDISPATCHER_HEADER* Object, uint32_t WaitReason,
10151128 const uint32_t timeout = GuestTimeoutToMilliseconds (Timeout);
10161129 assert (timeout == INFINITE );
10171130
1131+ #ifdef UNLEASHED_RECOMP_IOS
1132+ LogKernelWait (" KeWaitForSingleObject" ,
1133+ g_memory.MapVirtual (Object),
1134+ timeout,
1135+ Timeout ? int64_t (*Timeout) : 0 ,
1136+ Object->Type ,
1137+ Object->SignalState );
1138+ #endif
1139+
10181140 switch (Object->Type )
10191141 {
10201142 case 0 :
@@ -1325,6 +1447,12 @@ uint32_t NtResumeThread(GuestThreadHandle* hThread, uint32_t* suspendCount)
13251447
13261448uint32_t NtSetEvent (Event* handle, uint32_t * previousState)
13271449{
1450+ #ifdef UNLEASHED_RECOMP_IOS
1451+ LOGFN (" iOS NtSetEvent handle=0x{:08X} lr=0x{:08X} thread=0x{:08X}" ,
1452+ g_memory.MapVirtual (handle),
1453+ GetGuestLinkRegisterForLog (),
1454+ GuestThread::GetCurrentThreadId ());
1455+ #endif
13281456 handle->Set ();
13291457 return 0 ;
13301458}
@@ -1506,6 +1634,17 @@ uint32_t KeWaitForMultipleObjects(uint32_t Count, xpointer<XDISPATCHER_HEADER>*
15061634 const uint64_t timeout = GuestTimeoutToMilliseconds (Timeout);
15071635 assert (timeout == INFINITE );
15081636
1637+ #ifdef UNLEASHED_RECOMP_IOS
1638+ auto * firstObject = Count > 0 ? Objects[0 ].get () : nullptr ;
1639+ LogKernelWait (" KeWaitForMultipleObjects" ,
1640+ firstObject != nullptr ? g_memory.MapVirtual (firstObject) : 0 ,
1641+ uint32_t (timeout),
1642+ Timeout ? int64_t (*Timeout) : 0 ,
1643+ firstObject != nullptr ? firstObject->Type : 0xFFFFFFFF ,
1644+ firstObject != nullptr ? uint32_t (firstObject->SignalState ) : 0 ,
1645+ (Count << 8 ) | WaitType);
1646+ #endif
1647+
15091648 if (WaitType == 0 ) // Wait all
15101649 {
15111650 for (size_t i = 0 ; i < Count; i++)
0 commit comments