5#include <QtCore/qprocessordetection.h>
6#include <QtCore/qminmax.h>
7#include <QtCore/qdebug.h>
8#include <QtCore/qfile.h>
9#include <QtCore/qdir.h>
10#include <QtCore/qloggingcategory.h>
11#include <QtCore/private/qcoreapplication_p.h>
12#include <QtCore/private/qsystemerror_p.h>
13#include <QtCore/private/qthread_p.h>
14#include <QtCore/private/qcore_mac_p.h>
15#include <QtCore/private/qiosrunloopintegration_p.h>
16#include <QtCore/private/qeventdispatcher_cf_p.h>
18#import <Foundation/NSArray.h>
19#import <Foundation/NSString.h>
20#import <Foundation/NSProcessInfo.h>
21#import <Foundation/NSThread.h>
22#import <Foundation/NSNotification.h>
24#import <UIKit/UIApplication.h>
25#import <UIKit/UISceneSession.h>
27#if defined(Q_OS_VISIONOS)
28extern "C" void runSwiftAppMain();
35#define qAlignDown(val, align) val & ~(align - 1
)
36#define qAlignUp(val, align) qAlignDown(val + (align - 1
), align)
41using namespace QT_PREPEND_NAMESPACE(QtPrivate);
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
89 rlimit stackLimit = {0, 0};
90 rlim_t originalStackSize = 0;
97 static size_t computeSize(size_t requestedSize)
103 size_t stackSize =
qAlignUp(requestedSize, 4 * kBytesPerKiloByte);
106 stackSize = qMax(16 * kBytesPerKiloByte, stackSize);
112 stackSize = qMin(stackSize, ((1024 - 64) * kBytesPerKiloByte));
115 if (Q_UNLIKELY(stackSize > originalStackSize))
116 qFatal(
"Unexpectedly exceeded stack limit");
121 void adopt(
void* memory, size_t size)
123 uintptr_t memoryStart = uintptr_t(memory);
131 if (mprotect((
void*)memoryGuardStart,
kPageSize, PROT_READ))
132 qWarning() <<
"Failed to add memory guard:" << strerror(errno);
135 limit = memoryGuardStart + kPageSize;
141 base =
qAlignDown(memoryStart + size, kPageSize);
146 return base && limit;
154 static const int kScribblePattern;
158 memset_pattern4((
void*)limit, &kScribblePattern, size());
163 uintptr_t highWaterMark = limit;
164 for (; highWaterMark < base; highWaterMark += 4) {
165 if (memcmp((
void*)highWaterMark, &kScribblePattern, 4))
169 qDebug(
"main() used roughly %lu bytes of stack space", (base - highWaterMark));
173 const int Stack::kScribblePattern = 0xfafafafa;
177 jmp_buf processEventEnterJumpPoint;
178 jmp_buf processEventExitJumpPoint;
180 bool applicationAboutToTerminate =
false;
181 jmp_buf applicationWillTerminateJumpPoint;
183 bool debugStackUsage =
false;
186 QAppleLogActivity UIApplicationMain;
187 QAppleLogActivity applicationDidFinishLaunching;
190 void updateStackLimit()
192 qCDebug(lcEventDispatcher) <<
"Updating RLIMIT_STACK soft limit from"
193 << originalStackSize <<
"to" << userMainStack.size();
195 stackLimit.rlim_cur = userMainStack.size();
196 if (setrlimit(RLIMIT_STACK, &stackLimit) != 0) {
197 qCWarning(lcEventDispatcher) <<
"Failed to update RLIMIT_STACK soft limit"
198 << QSystemError::stdString();
202 void restoreStackLimit()
204 qCDebug(lcEventDispatcher) <<
"Restoring RLIMIT_STACK soft limit from"
205 << stackLimit.rlim_cur <<
"back to" << originalStackSize;
207 stackLimit.rlim_cur = originalStackSize;
208 if (setrlimit(RLIMIT_STACK, &stackLimit) != 0) {
209 qCWarning(lcEventDispatcher) <<
"Failed to update RLIMIT_STACK soft limit"
210 << QSystemError::stdString();
217 static NSBundle *bundle = [NSBundle mainBundle];
218 NSNumber* value = [bundle objectForInfoDictionaryKey:key];
219 return value ? [value intValue] : defaultValue;
223
224
225
226
227
228@interface QIOSDynamicSceneDelegate : UIResponder <UIApplicationDelegate>
231@implementation QIOSDynamicSceneDelegate
232- (UISceneConfiguration *)application:(UIApplication *)application
233 configurationForConnectingSceneSession:(UISceneSession *)session
234 options:(UISceneConnectionOptions *)options
238 return session.configuration;
245 if (Q_UNLIKELY(getrlimit(RLIMIT_STACK, &stackLimit) != 0))
246 qFatal(
"Failed to get stack limits");
248 originalStackSize = stackLimit.rlim_cur;
250 size_t defaultStackSize = 512 * kBytesPerKiloByte;
252 uint requestedStackSize = qMax(0, infoPlistValue(@
"QtRunLoopIntegrationStackSize", defaultStackSize));
254 if (infoPlistValue(@
"QtRunLoopIntegrationDisableSeparateStack",
false))
255 requestedStackSize = 0;
258#if Q_CC_CLANG >= 1800
259 QT_WARNING_DISABLE_CLANG(
"-Wvla-cxx-extension")
263 char reservedStack[Stack::computeSize(requestedStackSize)];
266 if (
sizeof(reservedStack) > 0) {
267 userMainStack.adopt(reservedStack,
sizeof(reservedStack));
269 if (infoPlistValue(@
"QtRunLoopIntegrationDebugStackUsage",
false)) {
270 debugStackUsage =
true;
271 userMainStack.scribble();
272 qDebug(
"Effective stack size is %lu bytes", userMainStack.size());
276 logActivity.UIApplicationMain = QT_APPLE_LOG_ACTIVITY(
277 lcEventDispatcher().isDebugEnabled(),
"UIApplicationMain").enter();
279#if defined(Q_OS_VISIONOS)
282 qCDebug(lcEventDispatcher) <<
"Starting Swift app";
286 qCDebug(lcEventDispatcher) <<
"Running UIApplicationMain";
287 return UIApplicationMain(argc, argv, nil,
288 NSStringFromClass(QIOSDynamicSceneDelegate.
class));
303 NSArray<NSString *> *arguments = [[NSProcessInfo processInfo] arguments];
304 int argc = arguments.count;
305 char **argv =
new char*[argc];
307 for (
int i = 0; i < argc; ++i) {
308 NSString *arg = [arguments objectAtIndex:i];
310 NSStringEncoding cStringEncoding = [NSString defaultCStringEncoding];
311 unsigned int bufferSize = [arg lengthOfBytesUsingEncoding:cStringEncoding] + 1;
312 argv[i] =
reinterpret_cast<
char *>(malloc(bufferSize));
314 if (Q_UNLIKELY(![arg getCString:argv[i] maxLength:bufferSize encoding:cStringEncoding]))
315 qFatal(
"Could not convert argv[%d] to C string", i);
320 static const bool isRunningViaTestRunner =
321 qEnvironmentVariableIsSet(
"QT_RUNNING_VIA_TEST_RUNNER");
323 if (isRunningViaTestRunner) {
324 qCDebug(lcEventDispatcher) <<
"Overriding working directory for test runner";
325 QDir::temp().mkdir(
"testrunner");
326 QDir::setCurrent(QDir::temp().filePath(
"testrunner"));
331 QDir::setCurrent(QString::fromNSString(NSBundle.mainBundle.bundlePath));
334 int main(
int argc,
char *argv[]);
336 int exitCode =
main(argc
, argv
);
339 logActivity.applicationDidFinishLaunching.enter();
340 qCDebug(lcEventDispatcher) <<
"Returned from main with exit code " << exitCode;
342 if (isRunningViaTestRunner) {
345 QFile exitCodeFile(QDir::tempPath() +
"/qt_exit_code.txt");
346 if (exitCodeFile.open(QIODevice::WriteOnly | QIODevice::Text))
347 exitCodeFile.write(QByteArray::number(exitCode));
349 qCWarning(lcEventDispatcher) <<
"Failed to write exit code to" << exitCodeFile.fileName();
352 if (Q_UNLIKELY(debugStackUsage))
353 userMainStack.printUsage();
357 logActivity.applicationDidFinishLaunching.leave();
359 if (applicationAboutToTerminate)
369void registerApplicationLifecycleCallbacks()
371 [[NSNotificationCenter defaultCenter]
372 addObserver:UIApplication.
class
373 selector:@selector(qt_applicationDidFinishLaunching:)
374 name:UIApplicationDidFinishLaunchingNotification
377 [[NSNotificationCenter defaultCenter]
378 addObserver:UIApplication.
class
379 selector:@selector(qt_applicationWillTerminate)
380 name:UIApplicationWillTerminateNotification
383Q_CONSTRUCTOR_FUNCTION(registerApplicationLifecycleCallbacks)
385@implementation UIApplication (QtRunLoopIntegration)
387+ (
bool)qt_rootLevelRunLoopIntegration
391 return userMainStack.isValid();
394+ (
void)qt_applicationDidFinishLaunching:(NSNotification *)notification
396 logActivity.applicationDidFinishLaunching = QT_APPLE_LOG_ACTIVITY_WITH_PARENT(
397 lcEventDispatcher().isDebugEnabled(),
"applicationDidFinishLaunching", logActivity.UIApplicationMain).enter();
399 qCDebug(lcEventDispatcher) <<
"Application launched with options" << notification.userInfo;
401 if (![self qt_rootLevelRunLoopIntegration]) {
405 qCDebug(lcEventDispatcher) <<
"Scheduling main() on next run-loop pass";
406 CFRunLoopTimerRef userMainTimer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault,
407 CFAbsoluteTimeGetCurrent(), 0, 0, 0, ^(CFRunLoopTimerRef) { user_main_trampoline(); });
408 CFRunLoopAddTimer(CFRunLoopGetMain(), userMainTimer, kCFRunLoopCommonModes);
409 CFRelease(userMainTimer);
413 switch (setjmp(processEventEnterJumpPoint)) {
414 case kJumpPointSetSuccessfully: {
415 qCDebug(lcEventDispatcher) <<
"Running main() on separate stack";
416 QT_APPLE_SCOPED_LOG_ACTIVITY(lcEventDispatcher().isDebugEnabled(),
"main()");
418#if defined(Q_PROCESSOR_X86)
419# define FUNCTION_CALL_ALIGNMENT 16
420# if defined(Q_PROCESSOR_X86_32)
421# define SET_STACK_POINTER "mov %0, %%esp"
422# elif defined(Q_PROCESSOR_X86_64)
423# define SET_STACK_POINTER "movq %0, %%rsp"
425#elif defined(Q_PROCESSOR_ARM)
427# define FUNCTION_CALL_ALIGNMENT 4
428# define SET_STACK_POINTER "mov sp, %0"
430# error "Unknown processor family"
437 __asm__ __volatile__(
440 :
"r" (
qAlignDown(userMainStack.base, FUNCTION_CALL_ALIGNMENT))
443 user_main_trampoline();
448 case kJumpedFromEventDispatcherProcessEvents:
451 logActivity.UIApplicationMain.enter();
452 qCDebug(lcEventDispatcher) <<
"↳ Jumped from processEvents due to exec";
454 if (Q_UNLIKELY(debugStackUsage))
455 userMainStack.printUsage();
461 qFatal(
"Unexpected jump result in event loop integration");
465+ (
bool)qt_eventDispatcherEnteredProcessEvents
469 switch (setjmp(processEventExitJumpPoint)) {
470 case kJumpPointSetSuccessfully:
471 qCDebug(lcEventDispatcher) <<
"QEventLoop exec detected, jumping back to system runloop ↵";
472 longjmp(processEventEnterJumpPoint, kJumpedFromEventDispatcherProcessEvents);
474 case kJumpedFromEventLoopExecInterrupt:
479 qCDebug(lcEventDispatcher) <<
"⇢ System runloop exited, returning with eventsProcessed = true";
483 qFatal(
"Unexpected jump result in event loop integration");
489+ (
void)qt_eventDispatcherInterruptEventLoopExec
494 switch (setjmp(processEventEnterJumpPoint)) {
495 case kJumpPointSetSuccessfully:
496 qCDebug(lcEventDispatcher) <<
"Jumping into processEvents due to system runloop exit ⇢";
497 logActivity.UIApplicationMain.leave();
498 longjmp(processEventExitJumpPoint, kJumpedFromEventLoopExecInterrupt);
500 case kJumpedFromEventDispatcherProcessEvents:
502 logActivity.UIApplicationMain.enter();
503 qCDebug(lcEventDispatcher) <<
"↳ Jumped from processEvents due to re-exec";
507 qFatal(
"Unexpected jump result in event loop integration");
511+ (
void)qt_applicationWillTerminate
513 QAppleLogActivity applicationWillTerminateActivity = QT_APPLE_LOG_ACTIVITY_WITH_PARENT(
514 lcEventDispatcher().isDebugEnabled(),
"applicationWillTerminate", logActivity.UIApplicationMain).enter();
515 qCDebug(lcEventDispatcher) <<
"Application about to be terminated by iOS";
517 if (![self qt_rootLevelRunLoopIntegration])
529 applicationAboutToTerminate =
true;
530 switch (setjmp(applicationWillTerminateJumpPoint)) {
531 case kJumpPointSetSuccessfully:
532 qCDebug(lcEventDispatcher) <<
"Exiting qApp with SIGTERM exit code";
533 qApp->exit([self qt_applicationWillTerminateExitCode]);
538 qCDebug(lcEventDispatcher) <<
"Manually triggering return from event loop exec";
539 applicationWillTerminateActivity.leave();
540 [self qt_eventDispatcherInterruptEventLoopExec];
542 case kJumpedFromUserMainTrampoline:
543 applicationWillTerminateActivity.enter();
545 qCDebug(lcEventDispatcher) <<
"kJumpedFromUserMainTrampoline, allowing iOS to terminate";
546 applicationWillTerminateActivity.leave();
549 qFatal(
"Unexpected jump result in event loop integration");
553+ (
bool)qt_applicationAboutToTerminate
555 return applicationAboutToTerminate;
558+ (
char)qt_applicationWillTerminateExitCode
563 return char(SIGTERM | 0x80);
static const size_t kBytesPerKiloByte
#define qAlignUp(val, align)
#define qAlignDown(val, align)
int qt_main_wrapper(int argc, char *argv[])
static const long kPageSize
static int infoPlistValue(NSString *key, int defaultValue)
static void __attribute__((noinline, noreturn)) user_main_trampoline()
@ kJumpedFromUserMainTrampoline
@ kJumpedFromEventLoopExecInterrupt
@ kJumpedFromEventDispatcherProcessEvents
@ kJumpPointSetSuccessfully
int main(int argc, char *argv[])
[ctor_close]