|
3 | 3 | // PlayTools |
4 | 4 | // |
5 | 5 |
|
| 6 | +#include <Foundation/Foundation.h> |
6 | 7 | #include <errno.h> |
7 | 8 | #include <sys/sysctl.h> |
8 | 9 |
|
@@ -211,10 +212,72 @@ static OSStatus pt_SecItemDelete(CFDictionaryRef query) { |
211 | 212 | DYLD_INTERPOSE(pt_SecItemUpdate, SecItemUpdate) |
212 | 213 | DYLD_INTERPOSE(pt_SecItemDelete, SecItemDelete) |
213 | 214 |
|
| 215 | +static NSMutableDictionary *thread_sleep_counters = nil; |
| 216 | +static NSMutableDictionary *last_sleep_attempts = nil; |
| 217 | +static dispatch_once_t thread_sleep_once; |
| 218 | +static NSLock *thread_sleep_lock = nil; |
| 219 | + |
| 220 | +static int pt_usleep(useconds_t time) { |
| 221 | + dispatch_once(&thread_sleep_once, ^{ |
| 222 | + thread_sleep_counters = [NSMutableDictionary dictionary]; |
| 223 | + last_sleep_attempts = [NSMutableDictionary dictionary]; |
| 224 | + thread_sleep_lock = [[NSLock alloc] init]; |
| 225 | + [thread_sleep_lock lock]; |
| 226 | + }); |
| 227 | + |
| 228 | + if ([[PlaySettings shared] blockSleepSpamming]) { |
| 229 | + int thread_id = pthread_mach_thread_np(pthread_self()); |
| 230 | + NSNumber *threadKey = @(thread_id); |
| 231 | + |
| 232 | + int thread_sleep_counter = [thread_sleep_counters[threadKey] intValue]; |
| 233 | + int last_sleep_attempt = [last_sleep_attempts[threadKey] intValue]; |
| 234 | + |
| 235 | + if (time == 100000) { |
| 236 | + int timestamp = (int)[[NSDate date] timeIntervalSince1970]; |
| 237 | + // If it sleeps too fast, increase counter |
| 238 | + if (timestamp - last_sleep_attempt < 2) { |
| 239 | + thread_sleep_counter++; |
| 240 | + } else { |
| 241 | + thread_sleep_counter = 1; |
| 242 | + } |
| 243 | + last_sleep_attempt = timestamp; |
| 244 | + thread_sleep_counters[threadKey] = @(thread_sleep_counter); |
| 245 | + last_sleep_attempts[threadKey] = @(last_sleep_attempt); |
| 246 | + |
| 247 | + } |
| 248 | + |
| 249 | + if (thread_sleep_counter > 100) { |
| 250 | + // Stop this thread from spamming usleep calls |
| 251 | + NSLog(@"[PC] Thread %i exceeded usleep limit. Seem sus, stopping this " |
| 252 | + @"thread FOREVER", |
| 253 | + thread_id); |
| 254 | + |
| 255 | + [thread_sleep_lock lock]; |
| 256 | + [thread_sleep_lock unlock]; |
| 257 | + |
| 258 | + return 0; |
| 259 | + } |
| 260 | + } |
| 261 | + |
| 262 | + return usleep(time); |
| 263 | +} |
| 264 | + |
| 265 | +DYLD_INTERPOSE(pt_usleep, usleep) |
| 266 | + |
214 | 267 | @implementation PlayLoader |
215 | 268 |
|
216 | 269 | static void __attribute__((constructor)) initialize(void) { |
217 | 270 | [PlayCover launch]; |
| 271 | + |
| 272 | + if ([[PlaySettings shared] blockSleepSpamming]) { |
| 273 | + // Add an observer so we can unlock threads on app termination |
| 274 | + [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillTerminateNotification |
| 275 | + object:nil |
| 276 | + queue:[NSOperationQueue mainQueue] |
| 277 | + usingBlock:^(NSNotification * _Nonnull note) { |
| 278 | + [thread_sleep_lock unlock]; |
| 279 | + }]; |
| 280 | + } |
218 | 281 | } |
219 | 282 |
|
220 | 283 | @end |
0 commit comments