Processes & Concurrency

RSS for tag

Discover how the operating system manages multiple applications and processes simultaneously, ensuring smooth multitasking performance.

Concurrency Documentation

Posts under Processes & Concurrency subtopic

Post

Replies

Boosts

Views

Activity

[MacOS] Accessing underlying pthread or mach thread of NSThread
Is the title possible ? I tried [[thread valueForKey:@"_private"] valueForKey:@"tid"] but the tid was not kvc compliant. private apis are alright because this is just for testing remote process thread creation. I already have a working method but it has hardcoded assembly so you can't do anything else. this question is mainly for Quinn (figured he may know something about this)
2
0
324
Feb ’25
mac 开发 com.apple.security.application-groups 问题
我在开发 Mac应用完成 后 通过Xcode 上传二进制文件的过程中, 出现了错误, 错误提示: App里面用到的 com.apple.security.application-groups 权限里面 有 group.*** 和 开发者组ID.*** 导致校验失败, 当我单独使用 group.xxx的时候, 我的程序会崩溃 , 因为里面用到了 MachPortRende 进程间通信问题, 这里默认了 开发者组ID.*** 这个路径, 错误详情: 在尝试启动 QuickFox 应用时,程序因权限问题而崩溃。具体的错误信息 bootstrap_check_in 组ID.xxxx.MachPortRendezvousServer.82392: Permission denied (1100) 显示,应用在尝试使用 Mach 端口进行进程间通信时,没有获得足够的权限, 因此 我需要您们的帮助, 如果单独用开发者组ID.*** 我们又没有权限 将数据写入 组ID.xxx里面的文件
1
0
117
Apr ’25
Check whether XPC remote proxy responds to selector, without causing exception and connection invalidation?
I have several processes maintaining NSXPConnection to an XPC service. The connections are bi-directional. Each side service and clients) of the connection exports an object, and an XPCInterface. The @protocols are different - to the service, and from the service to clients. So long as all the "clients" fully implement their "call-back" @protocol, there's no problem. All works fine. However - If a client does NOT implement a method in the "call back protocol", or completely neglects to export an object, or interface - and the service attempts to call back using the nonexistent method -- the XPC connection invalidates immediately. So far - expected behaviour. However, if I want the service to behave to the client a little like a "delegate" style -- and check first whether the client "respondsToSelector" or even - supports an interface BEFORE calling it, then this doesn't work. When my XPC service tries the following on a client connection: if (xpcConnection.remoteObjectInterface == nil) os_log_error(myXPCLog, "client has no remote interface); the condition is never met - i.e. the "remoteObjectInterface is never nil even when the client does NOT configure its NSXPCConnection with any incoming NSXPCInterface, and does not set an "exportedObject" Furthermore, the next check: if ([proxy respondsToSelector:@selector(downloadFiltersForCustomer:withReply:)]) { } will not only fail - but will drop the connection. The client side gets the invalidation with the following error: <NSXPCConnection: 0x600000b20000> connection to service with pid 2477 named com.proofpoint.ecd: received an undecodable message for proxy 1 (no exported object to receive message). Dropping message. I guess the "undecidable message" is the respondsToSelector - because the code doesn't get to attempt anything else afterwards, the connection drops. Is there a way to do this check "quietly", or suffering only "interruption", but without losing the connection,
3
0
759
Jan ’25
C program posix_spawn diskutil fails with error -69877
Hello, I am programming a CLI tool to partition USB disks. I am calling diskutil to do the work, but I am hitting issues with permissions, it seems. Here is a trial run of the same command running diskutil directly on the terminal vs running from my code: Calling diskutil directly (works as expected) % /usr/sbin/diskutil partitionDisk /dev/disk2 MBR Free\ Space gap 2048S fat32 f-fix 100353S Free\ Space tail 0 Started partitioning on disk2 Unmounting disk Creating the partition map Waiting for partitions to activate Formatting disk2s1 as MS-DOS (FAT32) with name f-fix 512 bytes per physical sector /dev/rdisk2s1: 98784 sectors in 98784 FAT32 clusters (512 bytes/cluster) bps=512 spc=1 res=32 nft=2 mid=0xf8 spt=32 hds=16 hid=2079 drv=0x80 bsec=100360 bspf=772 rdcl=2 infs=1 bkbs=6 Mounting disk Finished partitioning on disk2 /dev/disk2 (disk image): #: TYPE NAME SIZE IDENTIFIER 0: FDisk_partition_scheme +104.9 MB disk2 1: DOS_FAT_32 F-FIX 51.4 MB disk2s1 Calling diskutil programmatically (error -69877) % sudo ./f-fix DEBUG: /usr/sbin/diskutil partitionDisk /dev/disk2 MBR Free Space gap 2048S fat32 f-fix 100353S Free Space tail 0 Started partitioning on disk2 Unmounting disk Error: -69877: Couldn't open device (Is a disk in use by a storage system such as AppleRAID, CoreStorage, or APFS?) Failed to fix drive `/dev/disk2' Source Code The relevant code from my program is this: char *args[16]; int n = 0; args[n++] = "/usr/sbin/diskutil"; args[n++] = "partitionDisk"; args[n++] = (char *)disk; args[n++] = (char *)scheme; (...) args[n++] = NULL; char **parent_env = *_NSGetEnviron(); if (posix_spawnp(&pid, args[0], NULL, NULL, args, parent_env) != 0) return 1; if (waitpid(pid, &status, 0) < 0) return 1; return 0; Question Are there any system protections against running it like so? What could I be missing? Is this a Disk Arbitration issue?
1
0
128
May ’25
How to force cancel a task that doesn't need cleanup and doesn't check for cancellation?
How can you force cancel a task that doesn't need cleanup and doesn't check for cancellation? If this cannot be done, would this be a useful addition to Swift? Here is the situation: The async method doesn't check for cancellation since it is not doing anything repetively (for example in a loop). For example, the method may be doing "try JSONDecoder().decode(Dictionary<String, ...>.self, from: data)" where data is a large amount. The method doesn't need cleanup. I would like the force cancellation to throw an error. I am already handling errors for the async method. My intended situation if that the user request the async method to get some JSON encoded data, but since it is taking longer that they are willing to wait, they would tap a cancellation button that the app provides.
1
0
101
May ’25
BGAppRefreshTask Canceled Immediately by dasd in Network Extension
Dear Apple Support Team, My app, io.cylonix.sase, has a BGAppRefreshTask (io.cylonix.sase.ios.refresh) that is canceled by dasd ~9ms after submission from a Network Extension. Please help identify the cause and suggest a solution. App Details: App ID: io.cylonix.sase iOS Version: 17.1.1 (iPhone Xs Max) Network Extension: saseWgNetworkExtension with packet-tunnel-provider entitlement Use Case: VPN app; Network Extension records file receipts in shared group UserDefaults and schedules BGAppRefreshTask to wake the main app. App Usage: High (frequently used) System State: Sufficient resources (not low on battery or memory) Issue: The task is submitted but canceled immediately with priority 10. It has never run, so rate-limiting is not an issue. ` debug 22:09:37.952749-0700 dasd Best binding found for evaluator 0x16d541720: &lt;private&gt; debug 22:09:37.954483-0700 dasd Invoking selector backgroundTaskSchedulerPermittedIdentifiersWithContext:tableID:unitID:unitBytes: on &lt;LSApplicationRecord 0x724844650&gt; default 22:09:37.955563-0700 dasd CANCELED: bgRefresh-io.cylonix.sase.ios.refresh:ABDAFA at priority 10 &lt;private&gt;!
6
0
177
May ’25
Memory visibility issue regards to shared data with Dispatch Queue
I’m working with apple dispatch queue in C with the following design: multiple dispatch queues enqueue tasks into a shared context, and a dedicated dispatch queue (let’s call it dispatch queue A) processes these tasks. However, it seems this design has a memory visibility issue. Here’s a simplified version of my setup: I have a shared_context struct that holds: task_lis: a list that stores tasks to be prioritized and run — this list is only modified/processed by dispatch queue A (a serially dispatch queue), so I don't lock around it. cross_thread_tasks: a list that other queues push tasks into, protected by a lock. Other dispatch queues call a function schedule_task that locks and appends a new task to cross_thread_tasks call dispatch_after_f() to schedule a process_task() on dispatch queue A process_task() that processes the task_list and is repeatedly scheduled on dispatch queue A : Swaps cross_thread_tasks into a local list (with locking). Pushes the tasks into task_list. Runs tasks from task_list. Reschedules itself via dispatch_after_f(). Problem: Sometimes the tasks pushed from other threads don’t seem to show up in task_list when process_task() runs. The task_list appears to be missing them, as if the cross-thread tasks aren’t visible. However, if the process_task() is dispatched from the same thread the tasks originate, everything works fine. It seems to be a memory visibility or synchronization issue. Since I only lock around cross_thread_tasks, could it be that changes to task_list (even though modified on dispatch queue A only) are not being properly synchronized or visible across threads? My questions What’s the best practice to ensure shared context is consistently visible across threads when using dispatch queues? Is it mandatory to lock around all tasks? I would love to minimize/avoid lock if possible. Any guidance, debugging tips, or architectural suggestions would be appreciated! =============================== And here is pseudocode of my setup if it helps: struct shared_data { struct linked_list* task_list; } struct shared_context { struct shared_data *data; struct linked_list* cross_thread_tasks; struct thread_mutex* lock; // lock is used to protect cross_thread_tasks } static void s_process_task(void* shared_context){ struct linked_list* local_tasks; // lock and swap the cross_thread_tasks into a local linked list lock(shared_context->lock) swap(shared_context->cross_thread_tasks, local_tasks) unlock(shared_context->lock) // I didnt use lock to protect `shared_context->data` as they are only touched within dispatch queue A in this function. for (task : local_tasks) { linked_list_push(shared_context->data->task_list) } // If the `process_task()` block is dispatched from `schedule_task()` where the task is created, the `shared_context` will be able to access the task properly otherwise not. for (task : shared_context->data->task_list) { run_task_if_timestamp_is_now(task) } timestamp = get_next_timestamp(shared_context->data->task_list) dispatch_after_f(timestamp, dispatch_queueA, shared_context, process_task); } // On dispatch queue B static void schedule_task(struct task* task, void* shared_context) { lock(shared_context->lock) push(shared_context->cross_thread_tasks, task) unlock(shared_context->lock) timestamp = get_timestamp(task) // we only dispatch the task if the timestamp < 1 second. We did this to avoid the dispatch queue schedule the task too far ahead and prevent the shutdown process. Therefore, not all task will be dispatched from the thread it created. if(timestamp < 1 second) dispatch_after_f(timestamp, dispatch_queueA, shared_context, process_task); }
3
0
112
May ’25
Some issues and questions regarding the use of the BGContinuedProcessingTask API
Hi, I have been recently debugging the BGContinuedProcessingTask API and encountered some of the following issues. I hope you can provide some answers: First, let me explain my understanding of this API. I believe its purpose is to allow an app to trigger tasks that can be represented with progress indicators and require a certain amount of time to complete. After entering the background, these tasks can continue to be completed through the BGContinuedProcessingTask, preventing the system from terminating them before they are finished. In the launchHandler of the registration process, we only need to do a few things: Determine whether the actual business processing is still ongoing. Update the progress, title, and subtitle. Handle the expirationHandler. Set the task as completed. Here are some issues I encountered during my debugging process: After I called register and submit, the BGContinuedProcessingTask could not be triggered. The return values from my API calls were all normal. I tried different device models, and some could trigger the task normally, such as the 15 Pro Max and 12 Pro Max. However, there were also some models, such as the 17 Pro, 15 Pro, and 15, that could not trigger the task properly. Moreover, there was no additional error information to help locate the issue. The background task failed unexpectedly, but my app was still running normally. As I mentioned above, my launchHandler only retrieves the actual business status and updates it. If a background task fails unexpectedly while the app is still running normally, it can mislead users and degrade the user experience of the app. Others have also mentioned the issue of inconsistent behavior on devices that do not support Dynamic Island. On devices that support Dynamic Island, when a task is triggered in the foreground, the app does not immediately display a pop-up notification within the app. However, on devices that do not support Dynamic Island, the app directly displays a pop-up notification within the app, and this notification does not disappear when switching between different screens within the same app. The user needs to actively swipe up to dismiss it. I think this experience is too intrusive for users. I would like to know whether this will be maintained in the future or if there is a plan to fix it. On devices that do not support Dynamic Island, using the beta version 26.1 of the system, if the system is in dark mode but the app triggers a business interface in white, the pop-up notification will have the same color as the current page, making it difficult to read the content inside the pop-up. Users can actively stop background tasks by using the stop button, or the system can also stop tasks automatically when resources are insufficient or when a task is abnormal. However, according to the current API, all these actions are triggered through the expirationHandler. Currently, there is no way to distinguish whether the task was stopped by the user, by the system due to resource insufficiency, or due to an abnormal task. I would like to know whether there will be more information provided in the future to help distinguish these different scenarios. I believe that the user experience issues mentioned in points 2 and 3 are the most important. Please help to answer the questions and concerns above. Thank you!
7
0
283
Nov ’25
Re-enrolling a LaunchDaemon, does it require user auth?
I am building an app that uses the SMAppService to register a LaunchDaemon that is bundled with my .app. I've got a priming flow created which walks the user through approving the service so that it will start on login. However, I need to also be able to upgrade this background service if the user updates the app. To do this, I think I need to call unregisterAndReturnError and then registerAndReturnError. From my testing, this seems to work correctly, but I have a concern. Will the user ever be prompted to re-authorize the LaunchDaemon that I am registering? If so, under what circumstances will that happen, and what does it look like (so that I can guide the user through it)?
5
0
322
May ’25
XPC Service Installed Outside App Doesn't Set Responsible
On macOS 15.7.1 I'm trying to install an XPC service outside the app (Developer ID). It mostly seems to go ok, but when I set Launch Constraints on Responsible, AMFI complains of a violation, saying the service is responsible for itself, and fails to launch. Removing that constraint (or adding the service itself to the constraint) works fine. The service is an optional download, and installed to /Users/Shared with a LaunchAgent specifying the MachService. The service is correctly launched and seems to pass all codesigning, notarization, and other checks, but the Responsible isn't set to the "calling" app. Is this broken, or working as intended?
3
0
233
Nov ’25
macOS 14 XPC vs Foundation XPC
I'm looking into a newer XPC API available starting with macOS 14. Although it's declared as a low-level API I can't figure it how to specify code signing requirement using XPCListener and XPCSession. How do I connect it with xpc_listener_set_peer_code_signing_requirement and xpc_connection_set_peer_code_signing_requirement which require xpc_listener_t and xpc_connection_t respectively? Foundation XPC is declared as a high-level API and provides easy ways to specify code signing requirements on both ends of xpc. I'm confused with all these XPC APIs and their future: Newer really high-level XPCListener and XPCSession API (in low-level framework???) Low-level xpc_listener_t & xpc_connection_t -like API. Is it being replaced by newer XPCListener and XPCSession? How is it related to High-level Foundation XPC? Are NSXPCListener and NSXPCConnection going to be deprecated and replaced by XPCListener and XPCSession??
2
0
754
Aug ’25
Using protocols with XPC C API instead of dictionaries for sending and receiving messages
I have followed this post for creating a Launch Agent that provides an XPC service on macOS using Swift- post link - https://rderik.com/blog/creating-a-launch-agent-that-provides-an-xpc-service-on-macos/ In the swift code the interface of the XPC service is defined by protocols which makes the code nice and neat. I want to implement the XPC service using C APIs for XPC, and C APIs send and receive messages using dictionaries, which need manual handling with conditional statements. I want to know if its possible to go with the protocol based approach with C APIs.
2
0
521
Jan ’25
LaunchAgent can't connect to CloudKit daemon
For this code: let status = try await container.accountStatus() Seeing this error: 2025-05-08 15:32:00.945731-0500 localhost myAgent[2661]: (myDaemon.debug.dylib) [com.myDaemon.cli:networking] Error Domain=CKErrorDomain Code=6 "Error connecting to CloudKit daemon. This could happen for many reasons, for example a daemon exit, a device reboot, a race with the connection inactivity monitor, invalid entitlements, and more. Check the logs around this time to investigate the cause of this error." UserInfo={NSLocalizedDescription=Error connecting to CloudKit daemon. This could happen for many reasons, for example a daemon exit, a device reboot, a race with the connection inactivity monitor, invalid entitlements, and more. Check the logs around this time to investigate the cause of this error., CKRetryAfter=5, CKErrorDescription=Error connecting to CloudKit daemon. This could happen for many reasons, for example a daemon exit, a device reboot, a race with the connection inactivity monitor, invalid entitlements, and more. Check the logs around this time to investigate the cause of this error., NSUnderlyingError=0x600001bfc270 {Error Domain=NSCocoaErrorDomain Code=4099 UserInfo={NSDebugDescription= I initially started the this process as System Daemon to see what would happen (which obviously does not have CloudKit features). Then moved it back to /Library/LaunchAgents/ and can't get rid of that error. I see also following message from CloudKit daemon: Ignoring failed attempt to get container proxy for &lt;private&gt;: Error Domain=NSCocoaErrorDomain Code=4099 UserInfo={NSDebugDescription=&lt;private&gt;} Automatically retrying getting container proxy due to error for &lt;private&gt;: Error Domain=NSCocoaErrorDomain Code=4099 UserInfo={NSDebugDescription=&lt;private&gt;} XPC connection interrupted for &lt;private&gt; And this error for xpc service: [0x130e074b0] failed to do a bootstrap look-up: xpc_error=[3: No such process] If I start the same cli process directly from XCode, then it works just fine.
3
0
168
May ’25
Background Download Not Working in release builds- flutter_downloader
Issue: Background downloads using the flutter_downloader package work perfectly in debug mode and release mode when run directly from Xcode (plugged in). However, when I create an archive build and install the app separately (via TestFlight or direct IPA install), the background download stops working as soon as the app is minimized. ✅ What I’ve already done Info.plist <key>UIBackgroundModes</key> <array> <string>remote-notification</string> <string>fetch</string> <string>processing</string> <string>audio</string> <string>push-to-talk</string> </array> AppDelegate.swift import UIKit import Flutter import Firebase import flutter_downloader import BackgroundTasks @main @objc class AppDelegate: FlutterAppDelegate { static let backgroundChannel = "com.example.app/background_service" private var backgroundCompletionHandler: (() -> Void)? override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { FirebaseApp.configure() GeneratedPluginRegistrant.register(with: self) FlutterDownloaderPlugin.setPluginRegistrantCallback(registerPlugins) if #available(iOS 10.0, *) { UNUserNotificationCenter.current().delegate = self } if #available(iOS 13.0, *) { registerBackgroundTask() } return super.application(application, didFinishLaunchingWithOptions: launchOptions) } @available(iOS 13.0, *) private func registerBackgroundTask() { BGTaskScheduler.shared.register( forTaskWithIdentifier: "com.example.app.process_download_queue", using: nil ) { [weak self] task in guard let self = self else { return } self.handleDownloadQueueTask(task: task as! BGProcessingTask) } } @available(iOS 13.0, *) private func handleDownloadQueueTask(task: BGProcessingTask) { scheduleNextDownloadTask() let headlessEngine = FlutterEngine(name: "BackgroundTaskEngine", project: nil, allowHeadlessExecution: true) headlessEngine.run() let channel = FlutterMethodChannel( name: AppDelegate.backgroundChannel, binaryMessenger: headlessEngine.binaryMessenger ) task.expirationHandler = { channel.invokeMethod("backgroundTaskExpired", arguments: nil) } channel.invokeMethod("processNextInBackground", arguments: nil) { result in task.setTaskCompleted(success: (result as? Bool) ?? false) } } override func application( _ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void ) { self.backgroundCompletionHandler = completionHandler super.application(application, handleEventsForBackgroundURLSession: identifier, completionHandler: completionHandler) } override func applicationDidEnterBackground(_ application: UIApplication) { if #available(iOS 13.0, *) { scheduleNextDownloadTask() } } @available(iOS 10.0, *) override func userNotificationCenter( _ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void ) { if #available(iOS 14.0, *) { completionHandler([.list, .banner, .badge, .sound]) } else { completionHandler([.alert, .badge, .sound]) } } @available(iOS 10.0, *) override func userNotificationCenter( _ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void ) { completionHandler() } } // MARK: - Helper @available(iOS 13.0, *) func scheduleNextDownloadTask() { let request = BGProcessingTaskRequest(identifier: "com.example.app.process_download_queue") request.requiresNetworkConnectivity = true request.requiresExternalPower = false request.earliestBeginDate = Date(timeIntervalSinceNow: 60) do { try BGTaskScheduler.shared.submit(request) print("BGTask: Download queue processing task scheduled successfully.") } catch { print("BGTask: Could not schedule download queue task: \(error)") } } private func registerPlugins(registry: FlutterPluginRegistry) { if !registry.hasPlugin("FlutterDownloaderPlugin") { FlutterDownloaderPlugin.register(with: registry.registrar(forPlugin: "FlutterDownloaderPlugin")!) } } 🧩 Observations Background download works correctly when: The app is plugged in and run via Xcode (release/debug) It stops working when: The app is installed from an archived build (IPA/TestFlight) and minimized All entitlements and background modes are properly added. Provisioning profile includes required background modes. ❓Question Is there any known limitation or signing difference between Xcode run and archived release builds that could cause URLSession background tasks not to trigger? Has anyone faced a similar issue when using flutter_downloader on iOS 13+ with BGTaskScheduler or URLSession background configuration? Any help or working setup example for production/TestFlight would be appreciated.
1
0
85
Nov ’25
Feature Request: Reason for taskExpiration for BGContinuedProcessingTask
I've tuned my task to be decently resilient, but I found a few issues that caused it to expire regularly. excessive CPU usage -> I'm actually running it behind ReactNative, and I found an issue where I was still updating ReactNative and thus it was keeping it alive the entire time the task was running. Removing this update helped improve stability not updating progress frequently enough ( see https://developer.apple.com/forums/thread/809182?page=1#868247022) My feature request is, would it be possible to get a reason the task was expired in task.expirationHandler? That would be helpful for both the user and for debugging why the task was expired. Thanks!
2
0
149
4w