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]));
274extern "C" int main(
int argc,
char *argv[]);
278 NSArray<NSString *> *arguments = [[NSProcessInfo processInfo] arguments];
279 int argc = arguments.count;
280 char **argv =
new char*[argc];
282 for (
int i = 0; i < argc; ++i) {
283 NSString *arg = [arguments objectAtIndex:i];
285 NSStringEncoding cStringEncoding = [NSString defaultCStringEncoding];
286 unsigned int bufferSize = [arg lengthOfBytesUsingEncoding:cStringEncoding] + 1;
287 argv[i] =
reinterpret_cast<
char *>(malloc(bufferSize));
289 if (Q_UNLIKELY(![arg getCString:argv[i] maxLength:bufferSize encoding:cStringEncoding]))
290 qFatal(
"Could not convert argv[%d] to C string", i);
295 int exitCode =
main(argc
, argv
);
298 logActivity.applicationDidFinishLaunching.enter();
299 qCDebug(lcEventDispatcher) <<
"Returned from main with exit code " << exitCode;
301 if (Q_UNLIKELY(debugStackUsage))
302 userMainStack.printUsage();
306 logActivity.applicationDidFinishLaunching.leave();
308 if (applicationAboutToTerminate)
322 return userMainStack.isValid();
325@interface QIOSApplicationStateTracker : NSObject
328@implementation QIOSApplicationStateTracker
332 [[NSNotificationCenter defaultCenter]
334 selector:@selector(applicationDidFinishLaunching:)
335 name:UIApplicationDidFinishLaunchingNotification
338 [[NSNotificationCenter defaultCenter]
340 selector:@selector(applicationWillTerminate)
341 name:UIApplicationWillTerminateNotification
345#if defined(Q_PROCESSOR_X86)
346# define FUNCTION_CALL_ALIGNMENT 16
347# if defined(Q_PROCESSOR_X86_32)
348# define SET_STACK_POINTER "mov %0, %%esp"
349# elif defined(Q_PROCESSOR_X86_64)
350# define SET_STACK_POINTER "movq %0, %%rsp"
352#elif defined(Q_PROCESSOR_ARM)
354# define FUNCTION_CALL_ALIGNMENT 4
355# define SET_STACK_POINTER "mov sp, %0"
357# error "Unknown processor family"
360+ (
void)applicationDidFinishLaunching:(NSNotification *)notification
362 logActivity.applicationDidFinishLaunching = QT_APPLE_LOG_ACTIVITY_WITH_PARENT(
363 lcEventDispatcher().isDebugEnabled(),
"applicationDidFinishLaunching", logActivity.UIApplicationMain).enter();
365 qCDebug(lcEventDispatcher) <<
"Application launched with options" << notification.userInfo;
367 if (!isQtApplication())
370 if (!rootLevelRunLoopIntegration()) {
374 qCDebug(lcEventDispatcher) <<
"Scheduling main() on next run-loop pass";
375 CFRunLoopTimerRef userMainTimer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault,
376 CFAbsoluteTimeGetCurrent(), 0, 0, 0, ^(CFRunLoopTimerRef) { user_main_trampoline(); });
377 CFRunLoopAddTimer(CFRunLoopGetMain(), userMainTimer, kCFRunLoopCommonModes);
378 CFRelease(userMainTimer);
382 switch (setjmp(processEventEnterJumpPoint)) {
383 case kJumpPointSetSuccessfully: {
384 qCDebug(lcEventDispatcher) <<
"Running main() on separate stack";
385 QT_APPLE_SCOPED_LOG_ACTIVITY(lcEventDispatcher().isDebugEnabled(),
"main()");
391 __asm__ __volatile__(
394 :
"r" (
qAlignDown(userMainStack.base, FUNCTION_CALL_ALIGNMENT))
397 user_main_trampoline();
402 case kJumpedFromEventDispatcherProcessEvents:
405 logActivity.UIApplicationMain.enter();
406 qCDebug(lcEventDispatcher) <<
"↳ Jumped from processEvents due to exec";
408 if (Q_UNLIKELY(debugStackUsage))
409 userMainStack.printUsage();
415 qFatal(
"Unexpected jump result in event loop integration");
424+ (
void)applicationWillTerminate
426 QAppleLogActivity applicationWillTerminateActivity = QT_APPLE_LOG_ACTIVITY_WITH_PARENT(
427 lcEventDispatcher().isDebugEnabled(),
"applicationWillTerminate", logActivity.UIApplicationMain).enter();
428 qCDebug(lcEventDispatcher) <<
"Application about to be terminated by iOS";
430 if (!isQtApplication())
433 if (!rootLevelRunLoopIntegration())
445 applicationAboutToTerminate =
true;
446 switch (setjmp(applicationWillTerminateJumpPoint)) {
447 case kJumpPointSetSuccessfully:
448 qCDebug(lcEventDispatcher) <<
"Exiting qApp with SIGTERM exit code";
449 qApp->exit(kApplicationWillTerminateExitCode);
454 qCDebug(lcEventDispatcher) <<
"Manually triggering return from event loop exec";
455 applicationWillTerminateActivity.leave();
456 static_cast<QIOSJumpingEventDispatcher *>(qApp->eventDispatcher())->interruptEventLoopExec();
458 case kJumpedFromUserMainTrampoline:
459 applicationWillTerminateActivity.enter();
461 qCDebug(lcEventDispatcher) <<
"kJumpedFromUserMainTrampoline, allowing iOS to terminate";
462 applicationWillTerminateActivity.leave();
465 qFatal(
"Unexpected jump result in event loop integration");
474QIOSEventDispatcher *QIOSEventDispatcher::create()
476 if (isQtApplication() && rootLevelRunLoopIntegration())
477 return new QIOSJumpingEventDispatcher;
479 return new QIOSEventDispatcher;
482QIOSEventDispatcher::QIOSEventDispatcher(QObject *parent)
483 : QEventDispatcherCoreFoundation(parent)
486 QWindowSystemInterface::setSynchronousWindowSystemEvents(
true);
489bool QIOSEventDispatcher::isQtApplication()
491 return s_isQtApplication;
495
496
497
498
499bool QIOSEventDispatcher::processPostedEvents()
503 if (!QEventDispatcherCoreFoundation::processPostedEvents())
506 QT_APPLE_SCOPED_LOG_ACTIVITY(lcEventDispatcher().isDebugEnabled(),
"sendWindowSystemEvents");
507 QEventLoop::ProcessEventsFlags flags
508 = QEventLoop::ProcessEventsFlags(m_processEvents.flags.loadRelaxed());
509 qCDebug(lcEventDispatcher) <<
"Sending window system events for" << flags;
510 QWindowSystemInterface::sendWindowSystemEvents(flags);
516 : QIOSEventDispatcher(parent)
517 , m_processEventLevel(0)
518 , m_runLoopExitObserver(
this, &QIOSJumpingEventDispatcher::handleRunLoopExit, kCFRunLoopExit)
524 if (applicationAboutToTerminate) {
525 qCDebug(lcEventDispatcher) <<
"Detected QEventLoop exec after application termination";
527 qApp->exit(kApplicationWillTerminateExitCode);
531 if (!m_processEventLevel && (flags & QEventLoop::EventLoopExec)) {
532 QT_APPLE_SCOPED_LOG_ACTIVITY(lcEventDispatcher().isDebugEnabled(),
"processEvents");
533 qCDebug(lcEventDispatcher) <<
"Processing events with flags" << flags;
535 ++m_processEventLevel;
537 m_runLoopExitObserver.addToMode(kCFRunLoopCommonModes);
541 switch (setjmp(processEventExitJumpPoint)) {
542 case kJumpPointSetSuccessfully:
543 qCDebug(lcEventDispatcher) <<
"QEventLoop exec detected, jumping back to system runloop ↵";
546 case kJumpedFromEventLoopExecInterrupt:
551 qCDebug(lcEventDispatcher) <<
"⇢ System runloop exited, returning with eventsProcessed = true";
555 qFatal(
"Unexpected jump result in event loop integration");
561 ++m_processEventLevel;
562 bool processedEvents = QEventDispatcherCoreFoundation::processEvents(flags);
563 --m_processEventLevel;
565 return processedEvents;
571 Q_ASSERT(activity == kCFRunLoopExit);
573 if (m_processEventLevel == 1 && !currentEventLoop()->isRunning())
579 Q_ASSERT(m_processEventLevel == 1);
581 --m_processEventLevel;
583 m_runLoopExitObserver.removeFromMode(kCFRunLoopCommonModes);
588 switch (setjmp(processEventEnterJumpPoint)) {
589 case kJumpPointSetSuccessfully:
590 qCDebug(lcEventDispatcher) <<
"Jumping into processEvents due to system runloop exit ⇢";
591 logActivity.UIApplicationMain.leave();
596 logActivity.UIApplicationMain.enter();
597 qCDebug(lcEventDispatcher) <<
"↳ Jumped from processEvents due to re-exec";
601 qFatal(
"Unexpected jump result in event loop integration");
void interruptEventLoopExec()
void handleRunLoopExit(CFRunLoopActivity activity)
int main(int argc, char *argv[])
[ctor_close]
static const size_t kBytesPerKiloByte
#define qAlignUp(val, align)
#define qAlignDown(val, align)
bool __attribute__((returns_twice)) QIOSJumpingEventDispatcher
int qt_main_wrapper(int argc, char *argv[])
static const long kPageSize
static void __attribute__((noinline, noreturn)) user_main_trampoline()
static const char kApplicationWillTerminateExitCode
@ kJumpedFromUserMainTrampoline
@ kJumpedFromEventLoopExecInterrupt
@ kJumpedFromEventDispatcherProcessEvents
@ kJumpPointSetSuccessfully
static bool rootLevelRunLoopIntegration()