9#if defined(Q_OS_VISIONOS)
10#include "qiosswiftintegration.h"
13#include <QtCore/qprocessordetection.h>
14#include <QtCore/private/qcoreapplication_p.h>
15#include <QtCore/private/qsystemerror_p.h>
16#include <QtCore/private/qthread_p.h>
18#include <qpa/qwindowsysteminterface.h>
20#import <Foundation/NSArray.h>
21#import <Foundation/NSString.h>
22#import <Foundation/NSProcessInfo.h>
23#import <Foundation/NSThread.h>
24#import <Foundation/NSNotification.h>
26#import <UIKit/UIApplication.h>
32#define qAlignDown(val, align) val & ~(align - 1
)
33#define qAlignUp(val, align) qAlignDown(val + (align - 1
), align)
38using namespace QT_PREPEND_NAMESPACE(QtPrivate);
41
42
43
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
86 rlimit stackLimit = {0, 0};
87 rlim_t originalStackSize = 0;
94 static size_t computeSize(size_t requestedSize)
100 size_t stackSize =
qAlignUp(requestedSize, 4 * kBytesPerKiloByte);
103 stackSize = qMax(16 * kBytesPerKiloByte, stackSize);
109 stackSize = qMin(stackSize, ((1024 - 64) * kBytesPerKiloByte));
112 if (Q_UNLIKELY(stackSize > originalStackSize))
113 qFatal(
"Unexpectedly exceeded stack limit");
118 void adopt(
void* memory, size_t size)
120 uintptr_t memoryStart = uintptr_t(memory);
128 if (mprotect((
void*)memoryGuardStart,
kPageSize, PROT_READ))
129 qWarning() <<
"Failed to add memory guard:" << strerror(errno);
132 limit = memoryGuardStart + kPageSize;
138 base =
qAlignDown(memoryStart + size, kPageSize);
143 return base && limit;
151 static const int kScribblePattern;
155 memset_pattern4((
void*)limit, &kScribblePattern, size());
160 uintptr_t highWaterMark = limit;
161 for (; highWaterMark < base; highWaterMark += 4) {
162 if (memcmp((
void*)highWaterMark, &kScribblePattern, 4))
166 qDebug(
"main() used roughly %lu bytes of stack space", (base - highWaterMark));
170 const int Stack::kScribblePattern = 0xfafafafa;
174 jmp_buf processEventEnterJumpPoint;
175 jmp_buf processEventExitJumpPoint;
177 bool applicationAboutToTerminate =
false;
178 jmp_buf applicationWillTerminateJumpPoint;
180 bool debugStackUsage =
false;
183 QAppleLogActivity UIApplicationMain;
184 QAppleLogActivity applicationDidFinishLaunching;
187 static bool s_isQtApplication =
false;
189 void updateStackLimit()
191 qCDebug(lcEventDispatcher) <<
"Updating RLIMIT_STACK soft limit from"
192 << originalStackSize <<
"to" << userMainStack.size();
194 stackLimit.rlim_cur = userMainStack.size();
195 if (setrlimit(RLIMIT_STACK, &stackLimit) != 0) {
196 qCWarning(lcEventDispatcher) <<
"Failed to update RLIMIT_STACK soft limit"
197 << QSystemError::stdString();
201 void restoreStackLimit()
203 qCDebug(lcEventDispatcher) <<
"Restoring RLIMIT_STACK soft limit from"
204 << stackLimit.rlim_cur <<
"back to" << originalStackSize;
206 stackLimit.rlim_cur = originalStackSize;
207 if (setrlimit(RLIMIT_STACK, &stackLimit) != 0) {
208 qCWarning(lcEventDispatcher) <<
"Failed to update RLIMIT_STACK soft limit"
209 << QSystemError::stdString();
216 s_isQtApplication =
true;
219 if (Q_UNLIKELY(getrlimit(RLIMIT_STACK, &stackLimit) != 0))
220 qFatal(
"Failed to get stack limits");
222 originalStackSize = stackLimit.rlim_cur;
224 size_t defaultStackSize = 512 * kBytesPerKiloByte;
226 uint requestedStackSize = qMax(0, infoPlistValue(@
"QtRunLoopIntegrationStackSize", defaultStackSize));
228 if (infoPlistValue(@
"QtRunLoopIntegrationDisableSeparateStack",
false))
229 requestedStackSize = 0;
232#if Q_CC_CLANG >= 1800
233 QT_WARNING_DISABLE_CLANG(
"-Wvla-cxx-extension")
237 char reservedStack[Stack::computeSize(requestedStackSize)];
240 if (
sizeof(reservedStack) > 0) {
241 userMainStack.adopt(reservedStack,
sizeof(reservedStack));
243 if (infoPlistValue(@
"QtRunLoopIntegrationDebugStackUsage",
false)) {
244 debugStackUsage =
true;
245 userMainStack.scribble();
246 qDebug(
"Effective stack size is %lu bytes", userMainStack.size());
250 logActivity.UIApplicationMain = QT_APPLE_LOG_ACTIVITY(
251 lcEventDispatcher().isDebugEnabled(),
"UIApplicationMain").enter();
253#if defined(Q_OS_VISIONOS)
256 qCDebug(lcEventDispatcher) <<
"Starting Swift app";
257 QIOSIntegrationPluginSwift::runSwiftAppMain();
260 qCDebug(lcEventDispatcher) <<
"Running UIApplicationMain";
261 return UIApplicationMain(argc, argv, nil, NSStringFromClass([QIOSApplicationDelegate
class]));
276 NSArray<NSString *> *arguments = [[NSProcessInfo processInfo] arguments];
277 int argc = arguments.count;
278 char **argv =
new char*[argc];
280 for (
int i = 0; i < argc; ++i) {
281 NSString *arg = [arguments objectAtIndex:i];
283 NSStringEncoding cStringEncoding = [NSString defaultCStringEncoding];
284 unsigned int bufferSize = [arg lengthOfBytesUsingEncoding:cStringEncoding] + 1;
285 argv[i] =
reinterpret_cast<
char *>(malloc(bufferSize));
287 if (Q_UNLIKELY(![arg getCString:argv[i] maxLength:bufferSize encoding:cStringEncoding]))
288 qFatal(
"Could not convert argv[%d] to C string", i);
293 int main(
int argc,
char *argv[]);
295 int exitCode =
main(argc
, argv
);
298 logActivity.applicationDidFinishLaunching.enter();
299 qCDebug(lcEventDispatcher) <<
"Returned from main with exit code " << exitCode;
301#if TARGET_OS_SIMULATOR
302 if (qEnvironmentVariableIntegerValue(
"QT_RUNNING_VIA_TEST_RUNNER")) {
305 QFile exitCodeFile(QDir::tempPath() +
"/qt_exit_code.txt");
306 if (exitCodeFile.open(QIODevice::WriteOnly | QIODevice::Text))
307 exitCodeFile.write(QByteArray::number(exitCode));
309 qCWarning(lcEventDispatcher) <<
"Failed to write exit code to" << exitCodeFile.fileName();
313 if (Q_UNLIKELY(debugStackUsage))
314 userMainStack.printUsage();
318 logActivity.applicationDidFinishLaunching.leave();
320 if (applicationAboutToTerminate)
332static bool rootLevelRunLoopIntegration()
334 return userMainStack.isValid();
337@interface QIOSApplicationStateTracker : NSObject
340@implementation QIOSApplicationStateTracker
344 [[NSNotificationCenter defaultCenter]
346 selector:@selector(applicationDidFinishLaunching:)
347 name:UIApplicationDidFinishLaunchingNotification
350 [[NSNotificationCenter defaultCenter]
352 selector:@selector(applicationWillTerminate)
353 name:UIApplicationWillTerminateNotification
357#if defined(Q_PROCESSOR_X86)
358# define FUNCTION_CALL_ALIGNMENT 16
359# if defined(Q_PROCESSOR_X86_32)
360# define SET_STACK_POINTER "mov %0, %%esp"
361# elif defined(Q_PROCESSOR_X86_64)
362# define SET_STACK_POINTER "movq %0, %%rsp"
364#elif defined(Q_PROCESSOR_ARM)
366# define FUNCTION_CALL_ALIGNMENT 4
367# define SET_STACK_POINTER "mov sp, %0"
369# error "Unknown processor family"
372+ (
void)applicationDidFinishLaunching:(NSNotification *)notification
374 logActivity.applicationDidFinishLaunching = QT_APPLE_LOG_ACTIVITY_WITH_PARENT(
375 lcEventDispatcher().isDebugEnabled(),
"applicationDidFinishLaunching", logActivity.UIApplicationMain).enter();
377 qCDebug(lcEventDispatcher) <<
"Application launched with options" << notification.userInfo;
379 if (!isQtApplication())
382 if (!rootLevelRunLoopIntegration()) {
386 qCDebug(lcEventDispatcher) <<
"Scheduling main() on next run-loop pass";
387 CFRunLoopTimerRef userMainTimer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault,
388 CFAbsoluteTimeGetCurrent(), 0, 0, 0, ^(CFRunLoopTimerRef) { user_main_trampoline(); });
389 CFRunLoopAddTimer(CFRunLoopGetMain(), userMainTimer, kCFRunLoopCommonModes);
390 CFRelease(userMainTimer);
394 switch (setjmp(processEventEnterJumpPoint)) {
395 case kJumpPointSetSuccessfully: {
396 qCDebug(lcEventDispatcher) <<
"Running main() on separate stack";
397 QT_APPLE_SCOPED_LOG_ACTIVITY(lcEventDispatcher().isDebugEnabled(),
"main()");
403 __asm__ __volatile__(
406 :
"r" (
qAlignDown(userMainStack.base, FUNCTION_CALL_ALIGNMENT))
409 user_main_trampoline();
414 case kJumpedFromEventDispatcherProcessEvents:
417 logActivity.UIApplicationMain.enter();
418 qCDebug(lcEventDispatcher) <<
"↳ Jumped from processEvents due to exec";
420 if (Q_UNLIKELY(debugStackUsage))
421 userMainStack.printUsage();
427 qFatal(
"Unexpected jump result in event loop integration");
434static const char kApplicationWillTerminateExitCode =
char(SIGTERM | 0x80);
436+ (
void)applicationWillTerminate
438 QAppleLogActivity applicationWillTerminateActivity = QT_APPLE_LOG_ACTIVITY_WITH_PARENT(
439 lcEventDispatcher().isDebugEnabled(),
"applicationWillTerminate", logActivity.UIApplicationMain).enter();
440 qCDebug(lcEventDispatcher) <<
"Application about to be terminated by iOS";
442 if (!isQtApplication())
445 if (!rootLevelRunLoopIntegration())
457 applicationAboutToTerminate =
true;
458 switch (setjmp(applicationWillTerminateJumpPoint)) {
459 case kJumpPointSetSuccessfully:
460 qCDebug(lcEventDispatcher) <<
"Exiting qApp with SIGTERM exit code";
461 qApp->exit(kApplicationWillTerminateExitCode);
466 qCDebug(lcEventDispatcher) <<
"Manually triggering return from event loop exec";
467 applicationWillTerminateActivity.leave();
468 static_cast<QIOSJumpingEventDispatcher *>(qApp->eventDispatcher())->interruptEventLoopExec();
470 case kJumpedFromUserMainTrampoline:
471 applicationWillTerminateActivity.enter();
473 qCDebug(lcEventDispatcher) <<
"kJumpedFromUserMainTrampoline, allowing iOS to terminate";
474 applicationWillTerminateActivity.leave();
477 qFatal(
"Unexpected jump result in event loop integration");
486QIOSEventDispatcher *QIOSEventDispatcher::create()
488 if (isQtApplication() && rootLevelRunLoopIntegration())
489 return new QIOSJumpingEventDispatcher;
491 return new QIOSEventDispatcher;
494QIOSEventDispatcher::QIOSEventDispatcher(QObject *parent)
495 : QEventDispatcherCoreFoundation(parent)
498 QWindowSystemInterface::setSynchronousWindowSystemEvents(
true);
501bool QIOSEventDispatcher::isQtApplication()
503 return s_isQtApplication;
507
508
509
510
511bool QIOSEventDispatcher::processPostedEvents()
515 if (!QEventDispatcherCoreFoundation::processPostedEvents())
518 QT_APPLE_SCOPED_LOG_ACTIVITY(lcEventDispatcher().isDebugEnabled(),
"sendWindowSystemEvents");
519 QEventLoop::ProcessEventsFlags flags
520 = QEventLoop::ProcessEventsFlags(m_processEvents.flags.loadRelaxed());
521 qCDebug(lcEventDispatcher) <<
"Sending window system events for" << flags;
522 QWindowSystemInterface::sendWindowSystemEvents(flags);
527QIOSJumpingEventDispatcher::QIOSJumpingEventDispatcher(QObject *parent)
528 : QIOSEventDispatcher(parent)
529 , m_processEventLevel(0)
530 , m_runLoopExitObserver(
this, &QIOSJumpingEventDispatcher::handleRunLoopExit, kCFRunLoopExit)
534bool __attribute__((returns_twice)) QIOSJumpingEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
536 if (applicationAboutToTerminate) {
537 qCDebug(lcEventDispatcher) <<
"Detected QEventLoop exec after application termination";
539 qApp->exit(kApplicationWillTerminateExitCode);
543 if (!m_processEventLevel && (flags & QEventLoop::EventLoopExec)) {
544 QT_APPLE_SCOPED_LOG_ACTIVITY(lcEventDispatcher().isDebugEnabled(),
"processEvents");
545 qCDebug(lcEventDispatcher) <<
"Processing events with flags" << flags;
547 ++m_processEventLevel;
549 m_runLoopExitObserver.addToMode(kCFRunLoopCommonModes);
553 switch (setjmp(processEventExitJumpPoint)) {
554 case kJumpPointSetSuccessfully:
555 qCDebug(lcEventDispatcher) <<
"QEventLoop exec detected, jumping back to system runloop ↵";
556 longjmp(processEventEnterJumpPoint, kJumpedFromEventDispatcherProcessEvents);
558 case kJumpedFromEventLoopExecInterrupt:
563 qCDebug(lcEventDispatcher) <<
"⇢ System runloop exited, returning with eventsProcessed = true";
567 qFatal(
"Unexpected jump result in event loop integration");
573 ++m_processEventLevel;
574 bool processedEvents = QEventDispatcherCoreFoundation::processEvents(flags);
575 --m_processEventLevel;
577 return processedEvents;
580void QIOSJumpingEventDispatcher::handleRunLoopExit(CFRunLoopActivity activity)
583 Q_ASSERT(activity == kCFRunLoopExit);
585 if (m_processEventLevel == 1 && !currentEventLoop()->isRunning())
586 interruptEventLoopExec();
589void QIOSJumpingEventDispatcher::interruptEventLoopExec()
591 Q_ASSERT(m_processEventLevel == 1);
593 --m_processEventLevel;
595 m_runLoopExitObserver.removeFromMode(kCFRunLoopCommonModes);
600 switch (setjmp(processEventEnterJumpPoint)) {
601 case kJumpPointSetSuccessfully:
602 qCDebug(lcEventDispatcher) <<
"Jumping into processEvents due to system runloop exit ⇢";
603 logActivity.UIApplicationMain.leave();
604 longjmp(processEventExitJumpPoint, kJumpedFromEventLoopExecInterrupt);
606 case kJumpedFromEventDispatcherProcessEvents:
608 logActivity.UIApplicationMain.enter();
609 qCDebug(lcEventDispatcher) <<
"↳ Jumped from processEvents due to re-exec";
613 qFatal(
"Unexpected jump result in event loop integration");
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 void __attribute__((noinline, noreturn)) user_main_trampoline()
@ kJumpedFromUserMainTrampoline
@ kJumpedFromEventLoopExecInterrupt
@ kJumpedFromEventDispatcherProcessEvents
@ kJumpPointSetSuccessfully
int main(int argc, char *argv[])
[ctor_close]