kqueue NOTE_EXIT doesn't work - objective-c

I am trying to use Apple's example of using kqueue but the callback is never called unless I start observing the kqueue after the process starts. But the lifetime of the process is short and i need the code to work if the process starts before or after I start observing it.

What if you send the process a SIGSTOP immediately after starting it, and then SIGCONT after setting up the kqueue?
If you're using fork and exec directly, you could have the child send itself SIGSTOP (using raise(3)) and have the parent send it SIGCONT.

Related

GPUImage gpus_ReturnNotPermittedKillClient crash using GPUImageFilter

I'm using GPUImageFilter in a chain, and most of the time it works OK. I've recently come across a few random crashes that match the symptoms in this github issue (albeit I'm using GPUImageFilter not live capture or video). I'm trying to find a suitable method that can ensure I've cleared the frame buffer and any other GPUImage-related activities in willResignActive.
Currently I have:
[[GPUImageContext sharedFramebufferCache] purgeAllUnassignedFramebuffers];
Is this sufficient? Should I use something else instead/in addition to?
As indicated there, seeing gpus_ReturnNotPermittedKillClient in a stack trace almost always is due to OpenGL ES operations being performed while your application is in the background or is just about to go to the background.
To deal with this, you need to guarantee that all GPUImage-related work is finished before your application heads to the background. You'll want to listen for delegate notifications that your application is heading to the background, and make sure all processing is complete before that delegate callback exits. The suggestion there by henryl is one way to ensure this. Add the following near the end of your delegate callback:
runSynchronouslyOnVideoProcessingQueue(^{
// Do some operation
});
What that will do is inject a synchronous block into the video processing pipeline (which runs on a background queue). Your delegate callback will block the main thread at that point until this block has a chance to execute, guaranteeing that all processing blocks before it have finished. That will make sure all pending operations are done (assuming you don't add new ones) before your application heads to the background.
There is a slight chance of this introducing a deadlock in your application, but I don't think any of my code in the processing pipeline calls back into the main queue. You might want to watch out for that, because if I do still have something in there that does that, this will lock your application. That internal code would need to be fixed if so.

Understanding the Objective-C event loop

How can I log every message sent in a single iteration of the Objective-C event loop?
I want to further my understanding of the Objective-C runtime and thought this would be a good start.
These functions will cause all messages to be logged to a file in /tmp, based on the PID of the process. Good on simulator, but not on an iDevice.
// Start logging all messages
instrumentObjcMessageSends(YES);
// Stop logging all messages
instrumentObjcMessageSends(NO);
The CFRunLoopObserver opaque type should do exactly what you want. It is
a general means to receive callbacks at different points within a running run loop.
Use the activity argument to its creation function to specify when you want your observer serviced. For your case, this will probably be either kCFRunLoopEntry or kCFRunLoopExit.
You can get the CFRunLoopRef from the current NSRunLoop, [[NSRunLoop currentRunLoop] getCFRunLoop], or by using CFRunLoopGetCurrent().

Cancel thread with read() operation on serial port

in my Cocoa project, I communicate with a device connected to a serial port. Now, I am waiting for the serial device to send a particular message of some bytes. For the read operation (and the reaction for once the desired message has been received), I created a new thread. On user request, I want to be able to cancel the thread.
As Apple suggests in the docs, I added a flag to the thread dictionary, periodically check if the flag has been set and if so, call [NSThread exit]. This works fine.
Now, the thread may be stuck waiting for the serial device to finally send the 12 byte message. The read call looks like this:
numBytes = read(fileDescriptor, buffer, 12);
Once the thread starts reading from the device, but no data comes in, I can set the flag to tell the thread to finish, but the thread is not going to read the flag unless it finally received at least 12 bytes of data and continues processing.
Is there a way to kill a thread that currently performs a read operation on a serial device?
Edit for clarification:
I do not insist in creating a separate thread for the I/O operations with the serial device. If there is a way to encapsulate the operations such that I am able to "kill" them if the user presses a cancel button, I am perfectly happy.
I am developing a Cocoa application for desktop Mac OS X, so no restrictions regarding mobile devices and their capabilities apply.
A workaround would be to make the read function return immediately if there are no bytes to read. How can I do this?
Use select or poll with a timeout to detect when the descriptor is ready for reading.
Set the timeout to (say) half a second and call it in a loop while checking to see if your thread should exit.
Asynchronous thread cancellation is almost always a bad idea. Try to stick with event-driven interfaces (and, if necessary, timeouts).
This is exactly what the pthread_cancel interface was designed for. You'll want to wrap the block with read in pthread_cleanup_push and pthread_cleanup_pop in order that you can safely clean up if the thread is cancelled, and also disable cancellation (with pthread_setcancelstate) in other code that runs in this thread that you don't want to be cancellable. This can be a pain if proper cleanup would involve multiple call frames; it essentially forces you to use pthread_cleanup_push at every call level and structure your thread code like C++ or Java with try/catch style exception handling.
An alternative approach would be to install a signal handler for an otherwise-unused signal (like SIGUSR1 or one of the realtime signals) without the SA_RESTART flag, so that it interrupts syscalls with EINTR. The signal handler itself can be a complete no-op; the only purpose of it is to interrupt things. Then you can use pthread_kill to interrupt the read (or any other syscall) in a particular thread. This has the advantage that you don't have to switch your code to using C++/Java-type idioms. You can handle the EINTR error by checking a flag (indicating whether the thread was requested to abort) and resume the read if the flag is not set, or return an error code that causes the caller to clean up and eventually pthread_exit.
If you do use interrupting signal handlers, make sure all your syscalls that can return EINTR are wrapped in loops that retry (or check the abort flag and optionally retry) on EINTR. Otherwise things can break badly.

Detecting whether a process starts and finishes with notifications in cocoa

I was wondering if there was a way that I could get notifications of when a system process from /usr/sbin starts and finishes. Is it possible to attach NSTask to the running process without launching a new one? Preferably without polling please :!
For UI process you can use NSRunningApplication. You can observe the "terminated" property to know when it finishes. You can listen to NSWorkspaceWillLaunchApplicationNotification to know when an application will be launched.
Since you're not running a UI application the above probably won't work. You'll have to use more low level BSD calls. Here's an example of how you can know when an process terminates:
https://developer.apple.com/library/content/technotes/tn2050/_index.html#//apple_ref/doc/uid/DTS10003081-CH1-SUBSECTION10
Good luck!

Cocoa Distributed Objects, Long Polling, launchd and "Not Responding" in Activity Monitor

Scenario:
I have a Distributed-objects-based IPC between a mac application and a launchd daemon (written with Foundation classes). Since I had issues before regarding asynchronous messaging (e.g. I have a registerClient: on the server's root object and whenever there's an event the server's root object notifies / calls a method in the client's proxy object), I did long-polling which meant that the client "harvests" lists of events / notifications from the daemon. This "harvest" is done through a server object method call, which then returns an NSArray instance.
It works pretty well, until for a few seconds, the server object's process (launched thru launchd) starts being labeled red with the "(Not responding)" tag beside it (inside Activity Monitor). Like I said, functionally, it works well, but we just want to get rid of this "Not responding" label.
How can I prevent this "Not responding" tag?
FYI, I already did launchd-based processes before and this is the first time I did long-polling. Also, I tried NSSocketPortNameServer-based connections and also NSSocketPort-based ones. They didn't have this problem. Locking wasn't also an issue 'coz the locks used were only NSCondition's and we logged and debugged the program and it seems like the only locking "issue" is on the harvesting part, which actually, functionally works. Also, client-process is written in PyObjC while server process was written using ObjC.
Thanks in advance.
Sample the process to find out what it's doing or waiting on.
Peter's correct in the approach, though you may be able to figure it out through simple inspection. "Not responding" means that you're not processing events on your event queue for at least 5 seconds (used to be 2 seconds, but they upped it in 10.4). For a UI process, this would create a spinning wait cursor, but for a non-UI process, you're not seeing the effects as easily.
If this is a runloop-based program, it means you're probably doing something with a blocking (synchronous) operation that should be done with the run loop and a callback (async). Alternately, you need a second thread to process your blocking operations so your mainthread can continue to respond to events.
My problem was actually the call for getting a process's PID using the signature FNDR... that part caused the "Not responding" error and it never was the locks or the long-polling part. Sorry about this guys. But thank God I already found the answer.