I am trying to adapt C code, measuring pre/after main time, so it could be accessed from Swift with SC on. But nothing can silent compiler warning, indicating this code is not safe. I've tried every combination of @MainActor/nonisolated(unsafe)/@unchecked Sendable. Any solution/workaround? I am open to consider other solutions to measure pre/after main
Swift code
import Foundation
@MainActor
final class ApplicationLaunchTimeWrapper {
static let shared = ApplicationLaunchTimeWrapper()
private var pointer: UnsafeMutablePointer<ApplicationLaunchTimeType> {
//Reference to var 'ApplicationLaunchTime' is not concurrency-safe because it involves shared mutable state
UnsafeMutablePointer<ApplicationLaunchTimeType>(mutating: &ApplicationLaunchTime)
}
var preMainLaunchTime: CFTimeInterval {
pointer.pointee.preMainLaunchTime
}
var afterMainLaunchTime: CFTimeInterval {
pointer.pointee.afterMainLaunchTime
}
func measurePreMainLaunchTime() {
pointer.pointee.measurePreMainLaunchTime?()
}
func measureAfterMainLaunchTime() {
pointer.pointee.measureAfterMainLaunchTime?()
}
}
C/objc code
#ifndef ApplicationLaunchTime_h
#define ApplicationLaunchTime_h
#import <Foundation/Foundation.h>
@import ApplicantServices;
struct ApplicationLaunchTimeType {
CFTimeInterval preMainLaunchTime;
CFTimeInterval afterMainLaunchTime;
CFTimeInterval timeAtMain;
void (*measurePreMainLaunchTime)(void);
void (*measureAfterMainLaunchTime)(void);
};
extern struct ApplicationLaunchTimeType ApplicationLaunchTime[1];
#endif /* ApplicationLaunchTime_h */
#import <Foundation/Foundation.h>
#import <sys/sysctl.h>
#import "ApplicationLaunchTime.h"
static CFTimeInterval timeIntervalFromTimeval(const struct timeval time) {
return time.tv_sec + time.tv_usec / 1e6;
}
static CFTimeInterval processStartTime(void) {
const size_t namesLength = 4;
int names[namesLength] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()};
struct kinfo_proc processInfo;
size_t processInfoLength = sizeof(processInfo);
sysctl(names, namesLength, &processInfo, &processInfoLength, NULL, 0);
struct timeval processStartTime = processInfo.kp_proc.p_un.__p_starttime;
return timeIntervalFromTimeval(processStartTime);
}
static void measurePreMainLaunchTime(void) {
struct timeval currentTime;
gettimeofday(¤tTime, NULL);
ApplicationLaunchTime->timeAtMain = timeIntervalFromTimeval(currentTime);
ApplicationLaunchTime->preMainLaunchTime = ApplicationLaunchTime->timeAtMain - processStartTime();
}
static void measureAfterMainLaunchTime(void) {
struct timeval currentTime;
gettimeofday(¤tTime, NULL);
CFTimeInterval currentTimeInterval = timeIntervalFromTimeval(currentTime);
ApplicationLaunchTime->afterMainLaunchTime = currentTimeInterval - ApplicationLaunchTime->timeAtMain;
}
struct ApplicationLaunchTimeType ApplicationLaunchTime[1] = {
{
.preMainLaunchTime = -DBL_MAX,
.afterMainLaunchTime = -DBL_MAX,
.timeAtMain = -DBL_MAX,
.measurePreMainLaunchTime = measurePreMainLaunchTime,
.measureAfterMainLaunchTime = measureAfterMainLaunchTime
}
};
#importand@importin the C code? It's certainly not standard C. It looks like you might have meant the#importto be#include, but I have no idea what to make of@import ApplicantServices. Or is that not supposed to be C any longer (making the "C code" heading misleading)?