update
This commit is contained in:
147
Pods/CocoaDebug/Sources/Monitor/_RunloopMonitor.m
generated
Normal file
147
Pods/CocoaDebug/Sources/Monitor/_RunloopMonitor.m
generated
Normal file
@@ -0,0 +1,147 @@
|
||||
//
|
||||
// Example
|
||||
// man
|
||||
//
|
||||
// Created by man 11/11/2018.
|
||||
// Copyright © 2020 man. All rights reserved.
|
||||
//
|
||||
|
||||
#import "_RunloopMonitor.h"
|
||||
#import "_BacktraceLogger.h"
|
||||
|
||||
// 定义延迟时间 毫秒
|
||||
static int64_t const OUT_TIME = 100 * NSEC_PER_MSEC;
|
||||
// before wait 的超时时间
|
||||
static NSTimeInterval const WAIT_TIME = 0.5;
|
||||
|
||||
@interface _RunloopMonitor () {
|
||||
@public
|
||||
CFRunLoopObserverRef observer;
|
||||
CFRunLoopActivity currentActivity;
|
||||
dispatch_semaphore_t semaphore;
|
||||
BOOL isMonitoring;
|
||||
}
|
||||
@end
|
||||
|
||||
static void runloopObserverCallback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
|
||||
//_RunloopMonitor * monitor = (__bridge _RunloopMonitor*)info;
|
||||
[_RunloopMonitor shared]->currentActivity = activity;
|
||||
|
||||
// switch (activity) {
|
||||
// case kCFRunLoopEntry:
|
||||
// NSLog(@"##### %@", @"kCFRunLoopEntry");
|
||||
// break;
|
||||
// case kCFRunLoopBeforeTimers:
|
||||
// NSLog(@"##### %@", @"kCFRunLoopBeforeTimers");
|
||||
// break;
|
||||
// case kCFRunLoopBeforeSources:
|
||||
// NSLog(@"##### %@", @"kCFRunLoopBeforeSources");
|
||||
// break;
|
||||
// case kCFRunLoopBeforeWaiting:
|
||||
// NSLog(@"##### %@", @"kCFRunLoopBeforeWaiting");
|
||||
// break;
|
||||
// case kCFRunLoopAfterWaiting:
|
||||
// NSLog(@"##### %@", @"kCFRunLoopAfterWaiting");
|
||||
// break;
|
||||
// case kCFRunLoopExit:
|
||||
// NSLog(@"##### %@", @"kCFRunLoopExit");
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
|
||||
dispatch_semaphore_t sema = [_RunloopMonitor shared]->semaphore;
|
||||
dispatch_semaphore_signal(sema);
|
||||
}
|
||||
|
||||
@implementation _RunloopMonitor
|
||||
|
||||
+ (instancetype)shared {
|
||||
static id ins = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
ins = [[super allocWithZone:NSDefaultMallocZone()] init];
|
||||
});
|
||||
return ins;
|
||||
}
|
||||
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
|
||||
return [self shared];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self endMonitor];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)beginMonitor {
|
||||
|
||||
if ([_RunloopMonitor shared]->isMonitoring) return;
|
||||
|
||||
[_RunloopMonitor shared]->isMonitoring = YES;
|
||||
|
||||
// 创建观察者
|
||||
CFRunLoopObserverContext context = {
|
||||
0,
|
||||
(__bridge void*)self,
|
||||
&CFRetain,
|
||||
&CFRelease,
|
||||
NULL
|
||||
};
|
||||
//static CFRunLoopObserverRef observer;
|
||||
observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, &runloopObserverCallback, &context);
|
||||
|
||||
// 观察主线程
|
||||
CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
|
||||
|
||||
// 在子线程中监控卡顿
|
||||
semaphore = dispatch_semaphore_create(0); //同步?
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
// 开启持续的loop来监控
|
||||
while ([_RunloopMonitor shared]->isMonitoring) {
|
||||
if ([_RunloopMonitor shared]->currentActivity == kCFRunLoopBeforeWaiting)
|
||||
{
|
||||
// 处理休眠前事件观测
|
||||
__block BOOL timeOut = YES;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
timeOut = NO; // timeOut任务
|
||||
});
|
||||
[NSThread sleepForTimeInterval:WAIT_TIME];
|
||||
// WAIT_TIME 时间后,如果 timeOut任务 任未执行, 则认为主线程前面的任务执行时间过长导致卡顿
|
||||
if (timeOut) {
|
||||
[_BacktraceLogger cocoadebug_logMain];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 处理 Timer,Source,唤醒后事件
|
||||
// 同步等待时间内,接收到信号result=0, 超时则继续往下执行并且result!=0
|
||||
long result = dispatch_semaphore_wait([_RunloopMonitor shared]->semaphore, dispatch_time(DISPATCH_TIME_NOW, OUT_TIME));
|
||||
if (result != 0) { // 超时
|
||||
if (![_RunloopMonitor shared]->observer) {
|
||||
[[_RunloopMonitor shared] endMonitor];
|
||||
continue;
|
||||
}
|
||||
if ([_RunloopMonitor shared]->currentActivity == kCFRunLoopBeforeSources ||
|
||||
[_RunloopMonitor shared]->currentActivity == kCFRunLoopAfterWaiting ||
|
||||
[_RunloopMonitor shared]->currentActivity == kCFRunLoopBeforeTimers) {
|
||||
|
||||
[_BacktraceLogger cocoadebug_logMain];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
- (void)endMonitor {
|
||||
if (!observer) return;
|
||||
if (!isMonitoring) return;
|
||||
isMonitoring = NO;
|
||||
|
||||
CFRunLoopRemoveObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
|
||||
CFRelease(observer);
|
||||
observer = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user