I want to be notified right before a process exits on OSX so that I can gather statistics about the process before it dies. (Example specifics: I want to aggregate CPU usage for processes that have many child processes that spawn and die quickly, but use large amounts of CPU. When sampling CPU usage via things like proc_pidinfo
, processes that are born and die at rates similar to my sampling rate do not get adequately captured in my aggregate statistics. I would like to be notified when processes die so that I can sum up their total user and system time.
So far, the approach that has seemed like it will work the best has been to use libdtrace
, but I can't figure out how to set a probe for process exit using the dtrace
command, much less set up libdtrace
from a C program. Any tips on setting such a dtrace probe as well as tutorials on how to use libdtrace
would be greatly appreciated.
EDIT:
Alright, following the advice of a few commenters, I have managed to create a program that uses libdtrace and reliably triggers off of a process' exit. This is great, but unfortunately I can't seem to get the PID of the process that is exiting. It seems that calling printf()
in my D program and trying to format integers is badly broken. Specifically, if I run this program which is supposed to print out the name and PID of a process right as it's exiting, it fails miserably. It prints some other integer, and indeed that integer is printed no matter what I try to output. If I change the D program from
syscall::*exit*:entry {
printf(\"%s %d\\n\", execname, curpsinfo->pr_pid);
};
To just
syscall::*exit*:entry {
printf(\"%d\\n\", 100);
};
It just prints out the first three digits of the mystery integer. Note that the process names are correct, it's just the integer -> string conversion that is failing, I believe. Running the main dtrace
program with the above D programs works properly, but I want to integrate this into a C program that I have already written a lot into, and piping subcommand outputs into that program isn't really the way I want to move forward.
Help on how to get either the buffered output from libdtrace
to work properly, or alternatively to get the PID as an integer rather than a string would be great.
There is an Apple technical note for this subject.
TN2050 Observing Process Lifetimes Without Polling
For monitoring an arbitrary process, this guide suggests kqueues
.
We can obtain PIDs of running processes by this way [unable to detect application running with another user (via switch user) or this way [Programmatically check if a process is running on Mac.
Listing 8 Using kqueues to monitor a specific process
static pid_t gTargetPID = -1;
// We assume that some other code sets up gTargetPID.
- (IBAction)testNoteExit:(id)sender
{
FILE * f;
int kq;
struct kevent changes;
CFFileDescriptorContext context = { 0, self, NULL, NULL, NULL };
CFRunLoopSourceRef rls;
// Create the kqueue and set it up to watch for SIGCHLD. Use the
// new-in-10.5 EV_RECEIPT flag to ensure that we get what we expect.
kq = kqueue();
EV_SET(&changes, gTargetPID, EVFILT_PROC, EV_ADD | EV_RECEIPT, NOTE_EXIT, 0, NULL);
(void) kevent(kq, &changes, 1, &changes, 1, NULL);
// Wrap the kqueue in a CFFileDescriptor (new in Mac OS X 10.5!). Then
// create a run-loop source from the CFFileDescriptor and add that to the
// runloop.
noteExitKQueueRef = CFFileDescriptorCreate(NULL, kq, true, NoteExitKQueueCallback, &context);
rls = CFFileDescriptorCreateRunLoopSource(NULL, noteExitKQueueRef, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
CFFileDescriptorEnableCallBacks(noteExitKQueueRef, kCFFileDescriptorReadCallBack);
// Execution continues in NoteExitKQueueCallback, below.
}
static void NoteExitKQueueCallback(
CFFileDescriptorRef f,
CFOptionFlags callBackTypes,
void * info
)
{
struct kevent event;
(void) kevent( CFFileDescriptorGetNativeDescriptor(f), NULL, 0, &event, 1, NULL);
NSLog(@"terminated %d", (int) (pid_t) event.ident);
// You've been notified!
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With