33// PlayTools
44//
55
6+ #include < Foundation/Foundation.h>
67#include < errno.h>
78#include < sys/sysctl.h>
89
@@ -230,11 +231,60 @@ static int pt_unlink(char const* path) {
230231 return unlink (ue_fix_filename (path));
231232}
232233
234+ static NSMutableDictionary *thread_sleep_counters = nil ;
235+ static NSMutableDictionary *last_sleep_attempts = nil ;
236+ static dispatch_once_t thread_sleep_once;
237+ static NSLock *thread_sleep_lock = nil ;
238+
239+ static int pt_usleep (useconds_t time) {
240+ dispatch_once (&thread_sleep_once, ^{
241+ thread_sleep_counters = [NSMutableDictionary dictionary ];
242+ last_sleep_attempts = [NSMutableDictionary dictionary ];
243+ thread_sleep_lock = [[NSLock alloc ] init ];
244+ [thread_sleep_lock lock ];
245+ });
246+
247+ int thread_id = pthread_mach_thread_np (pthread_self ());
248+ NSNumber *threadKey = @(thread_id);
249+
250+ int thread_sleep_counter = [thread_sleep_counters[threadKey] intValue ];
251+ int last_sleep_attempt = [last_sleep_attempts[threadKey] intValue ];
252+
253+ if (time == 100000 ) {
254+ int timestamp = (int )[[NSDate date ] timeIntervalSince1970 ];
255+ // If it sleeps too fast, increase counter
256+ if (timestamp - last_sleep_attempt < 2 ) {
257+ thread_sleep_counter++;
258+ } else {
259+ thread_sleep_counter = 1 ;
260+ }
261+ last_sleep_attempt = timestamp;
262+ thread_sleep_counters[threadKey] = @(thread_sleep_counter);
263+ last_sleep_attempts[threadKey] = @(last_sleep_attempt);
264+
265+ }
266+
267+ if (thread_sleep_counter > 100 ) {
268+ // Stop this thread from spamming usleep calls
269+ NSLog (@" [PC] Thread %i exceeded usleep limit. Seem sus, stopping this "
270+ @" thread FOREVER" ,
271+ thread_id);
272+
273+ [thread_sleep_lock lock ];
274+ [thread_sleep_lock unlock ];
275+
276+ return 0 ;
277+ }
278+
279+ return usleep (time);
280+ }
281+
233282DYLD_INTERPOSE (pt_open, open)
234283DYLD_INTERPOSE(pt_stat, stat)
235284DYLD_INTERPOSE(pt_access, access)
236285DYLD_INTERPOSE(pt_rename, rename)
237286DYLD_INTERPOSE(pt_unlink, unlink)
287+ DYLD_INTERPOSE(pt_usleep, usleep)
238288
239289@implementation PlayLoader
240290
@@ -250,6 +300,14 @@ static void __attribute__((constructor)) initialize(void) {
250300 if (ue_status == 2 ) {
251301 [PlayKeychain debugLogger: [NSString stringWithFormat: @" UnrealEngine Hooked" ]];
252302 }
303+
304+ // Add an observer so we can unlock threads on app termination
305+ [[NSNotificationCenter defaultCenter ] addObserverForName: UIApplicationWillTerminateNotification
306+ object: nil
307+ queue: [NSOperationQueue mainQueue ]
308+ usingBlock: ^(NSNotification * _Nonnull note) {
309+ [thread_sleep_lock unlock ];
310+ }];
253311}
254312
255313@end
0 commit comments