<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>mikeash.com pyblog/friday-qa-2011-04-01-signal-handling.html comments</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>mikeash.com Recent Comments</description><lastBuildDate>Sun, 10 May 2026 04:30:25 GMT</lastBuildDate><generator>PyRSS2Gen-1.0.0</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Amitai Hoze - 2016-03-03 17:13:42</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>Hi, can I use kqueue or GCD to perform non "async-signal-safe" code when my iOS app crashes (e.g. on SIGILL, or SIGTRAP)? Namely, I want to open a dialer using &lt;code&gt;[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel://1111111"]];&lt;/code&gt;, is that at all possible?</description><guid isPermaLink="true">4ab93bad7e883f027d401ec312e5c3f8</guid><pubDate>Thu, 03 Mar 2016 17:13:42 GMT</pubDate></item><item><title>vb - 2015-01-06 21:52:17</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>Mike, sorry for commenting on old post.
&lt;br /&gt;
&lt;br /&gt;Is there any way to obtain siginfo_t when handling signal with kqueue?
&lt;br /&gt;With epoll on signalfd (Linux) its just as simple as read signalfd_siginfo from fd on which signal is received.</description><guid isPermaLink="true">56abfacc1c84853c50e9370261ab0aea</guid><pubDate>Tue, 06 Jan 2015 21:52:17 GMT</pubDate></item><item><title>Michael Hecht - 2014-05-20 17:59:43</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>Akos, we do something similar. But instead of running leaks at app termination, we run it in response to a specific scripting command in our app's scripting language. This allows us to (optionally) run leaks after each test in a test stream. If a leak is found, we terminate our app which causes the testing driver to capture the leak report and restart on the next test.
&lt;br /&gt;
&lt;br /&gt;I do it using system(). Here's the code:
&lt;br /&gt;&lt;code&gt;
&lt;br /&gt;#define LEAKS_LOG&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;"~/Library/Logs/DiagnosticReports/JMP-LeaksReport.txt"
&lt;br /&gt;void hostDebugLeaks()
&lt;br /&gt;{
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/*
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;This function is called from JSL via the
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Debug( Leaks );
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;command.
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;It works best if you have launched JMP with the symbol MallocStackLogging set to 1,
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;like so:
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MallocStackLogging=1 ./JMP.app/Contents/MacOS/JMP
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If leaks are found, this function writes a leaks report to ~/Library/Logs/
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DiagnosticReports/JMP-leaks.log. JMP is then exited.
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;This can be used with the TestBot in leaks detection mode. In this mode, TestBot will
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;launch JMP with MallocStackLogging enabled, then run the UT Framework with
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_utDailyBuild=1 and _utLeaks=1. This causes UT Framework to check for leaks after
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;running each unit test. If a leak is found, JMP exits and TestBot captures the leaks
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;report for the leaking test. Then JMP is restarted and the test stream resumes on the
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;following test.
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; */
&lt;br /&gt;
&lt;br /&gt;#if 0
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Debugging - force a leak
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int * leaky = new int[42];
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;leaky = 0;
&lt;br /&gt;#endif
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Run the 'leaks' command on our process; capture output; look for magic "no leaks" string
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;JString leaksCmd( "leaks ^PID 2&amp;gt;&amp;amp;1 | tee ^LOG | grep \": 0 leaks for 0 total leaked bytes.\"" );
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;leaksCmd.replace( "^PID", getpid()).replace( "^LOG", LEAKS_LOG );
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int status = system( leaksCmd.value());
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// If status is 0, it means the magic "no leaks" string was found, so we don't have any leaks.
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Delete the log file and return.
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if( status == 0 ) {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;JString rmLogCmd( "rm -f ^LOG" );
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rmLogCmd.replace( "^LOG", LEAKS_LOG );
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;system( rmLogCmd.value());
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// We have a leak; leave the log file intact and force JMP to exit
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NSLog( @"Leaks detected; exiting" );
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;exit( EXIT_FAILURE );
&lt;br /&gt;}
&lt;br /&gt;&lt;/code&gt;
&lt;br /&gt;I'm sure you can ignore/interpret the parts that are specific to our internal libraries.
&lt;br /&gt;
&lt;br /&gt;Prior to Mavericks, the system() call would hang for us occasionally, because of a crash in leaks as you describe. I had the opportunity to discuss it with an Apple engineer at WWDC a few years back and he thought he knew what the problem was. I submitted a radar and it is apparently now fixed.
&lt;br /&gt;
&lt;br /&gt;Rather than having our app clean up the call stack in the captured leak report as your code does, we have the testing driver ("TestBot" in the above comment) do it. It's a perl script and the cleanup code looks like this:
&lt;br /&gt;&lt;code&gt;
&lt;br /&gt;sub process_leaks_report {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;my( $file ) = @_;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return unless -e $file;
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;my $modified = 0;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;my $contents = '';
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;open( LOG_FILE_IN, '&amp;lt;', $file ) || die "Cannot open $file: $!";
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while( &amp;lt;LOG_FILE_IN&amp;gt; ) {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;chomp;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if( s/^(\s*Call stack: .*?:) \| // ) {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$contents .= "$1\n\t\t";
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$contents .= join( "\n\t\t", reverse split( / \| /, $_ ));
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$contents .= "\n";
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;++$modified;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$contents .= "$_\n";
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;close( LOG_FILE_IN );
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if( $modified ) {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;open( LOG_FILE_OUT, '&amp;gt;', $file ) || die "Cannot create $file: $!";
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print LOG_FILE_OUT $contents;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;close( LOG_FILE_OUT );
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;}
&lt;br /&gt;&lt;/code&gt;
&lt;br /&gt;What interests me is your exclusion of setWindowsMenu:. I see that leak too. Have you reported it? Have you done any further investigation on it?</description><guid isPermaLink="true">5d94c4e1861958cf663e0a40267dbd35</guid><pubDate>Tue, 20 May 2014 17:59:43 GMT</pubDate></item><item><title>Akos - 2014-02-12 08:21:00</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>Thanks, Mike. We are already sending the output to a temporary file. Unfortunately that approach still hangs in pclose when 'leaks' crashes:
&lt;br /&gt;
&lt;br /&gt;#0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0x00007fff83fb96ac in wait4 ()
&lt;br /&gt;#1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0x00007fff86afd894 in pclose ()
&lt;br /&gt;#2&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0x00000001149a409d in DetectLeaks at /Users/asomorjai/Work/DevMain.8/Sources/GSRoot/GSRootDLL/LeakDetectorMac.mm:1442
&lt;br /&gt;#3&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0x000000011476a25f in GSTermImage at /Users/asomorjai/Work/DevMain.8/Sources/GSRoot/GSRootDLL/GSRootMain.cpp:161
&lt;br /&gt;#4&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0x00007fff86af1525 in __cxa_finalize ()
&lt;br /&gt;#5&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0x00007fff86af368b in exit ()
&lt;br /&gt;#6&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0x000000010000403b in start ()
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;Here's the actual code; it runs on the main thread:
&lt;br /&gt;
&lt;br /&gt;extern "C" void DetectLeaks (void)
&lt;br /&gt;{
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (!NeedsLeaks ())
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return;
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;signal (SIGCHLD, SIG_DFL);
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pid_t&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;myPid = getpid ();
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;char&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s[2048], fn[128];
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sprintf (fn, "/tmp/leaks_%d.txt", myPid);
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sprintf (s, "leaks -exclude \"-[NSApplication(NSWindowsMenu) setWindowsMenu:]\" %d &amp;gt; %s\n", myPid, fn);
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf ("%s\n", s);
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FILE *fp = popen (s, "r");
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (fp != nullptr) {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pclose (fp);
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fp = fopen (fn, "r");
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (fp != nullptr) {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SInt32 bytesRead = 1;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while (bytesRead &amp;gt; 0) {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;char buffer [1024];
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bytesRead = fread (buffer, sizeof (char), sizeof (buffer) - 1, fp);
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;buffer[bytesRead] = '\0';
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (char *p = buffer; *p != '\0'; p++) {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (*p == '|')
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*p = '\n';
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf ("%s", buffer);
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fclose (fp);
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;}
&lt;br /&gt;
&lt;br /&gt;How can I detect that 'leaks' has finished/crashed, if —for some reason— I don't get the SIGCHLD signal? Or how can I detect where the SIGCHLD is delivered?
&lt;br /&gt;
&lt;br /&gt;Thanks, Akos</description><guid isPermaLink="true">8b145de8eafd749f653b75180f310eab</guid><pubDate>Wed, 12 Feb 2014 08:21:00 GMT</pubDate></item><item><title>mikeash - 2014-02-12 03:52:06</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>This is a guess, so please don't take it as basic truth.
&lt;br /&gt;
&lt;br /&gt;I &lt;i&gt;think&lt;/i&gt; that leaks will pause your process, at least occasionally, while doing its analysis in order to capture a consistent snapshot of it.
&lt;br /&gt;
&lt;br /&gt;If that's the case, then you end up with a deadlock. Leaks is writing into a pipe that's drained by your process. But your process is paused by leaks, so it can't drain the pipe. If the pipe fills up, leaks will block waiting for you to drain it, but if your process is still paused, you'll never drain it.
&lt;br /&gt;
&lt;br /&gt;A simple workaround would be to have leaks write its data into a file instead of a pipe. Your app can then read out of the file when it's done. You can do this with popen by just tacking on &amp;gt; somefile to the command, or with NSTask by setting its stdout to an NSFileHandle.</description><guid isPermaLink="true">9d7b3b39fd6715de707e5597104585a6</guid><pubDate>Wed, 12 Feb 2014 03:52:06 GMT</pubDate></item><item><title>Akos - 2014-02-11 17:51:02</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>May I ask a question?
&lt;br /&gt;
&lt;br /&gt;We are trying to detect memory leaks when quitting our OS X application by calling 'leaks' on our own process. In some cases 'leaks' crashes or hangs, which stalls our app (in a freed/wait4). For some reason I can't catch the SIGCHLD signal in our process.
&lt;br /&gt;
&lt;br /&gt;The leak detection process is called in the termination function, registered with atexit(). The leak detection in its simplest form uses popen/fread/pclose, but I have tried also other approaches, from kevent, GCD, pthreads, and NSPipe. None of them seems to work, I always hang somewhere (wait4, kevent, sigsuspend_nocancel).
&lt;br /&gt;
&lt;br /&gt;I'd appreciate any pointers where I might go wrong; I'm sure it's my inability to capture some important point.
&lt;br /&gt;
&lt;br /&gt;Thanks a lot,
&lt;br /&gt;
&lt;br /&gt;Akos (asomorjai at graphisoft.com)</description><guid isPermaLink="true">0690c25813680205131f7138ef6ef096</guid><pubDate>Tue, 11 Feb 2014 17:51:02 GMT</pubDate></item><item><title>mikeash - 2014-01-24 15:34:19</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>I imagine you're right, but note that memcpy is not nearly as simple as it might appear. On OS X, for example, if you're copying enough memory (greater than 40kB or so, last I checked) and the arguments are nicely aligned, it will actually skip the copy altogether and instead use mach virtual memory calls to "copy" the memory without doing any actual copies.</description><guid isPermaLink="true">cdf59733954fc0023b8136ac18c62b6b</guid><pubDate>Fri, 24 Jan 2014 15:34:19 GMT</pubDate></item><item><title>Yuhong Bao - 2014-01-10 07:53:40</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>"Finally, the list ends with this amusing note: "...and perhaps some others." "Perhaps" is not a nice word to run into in this sort of documentation."
&lt;br /&gt;I think this is referring to memcpy(), memset(), and similar functions that are simple enough that they are pretty much always async signal safe.</description><guid isPermaLink="true">c71059ae5e1a6475f2d61fb23932a8fa</guid><pubDate>Fri, 10 Jan 2014 07:53:40 GMT</pubDate></item><item><title>arwyn - 2011-04-03 20:25:31</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>Mike, you missed pointing out the ensuing hilarity of reentrancy and recursive locks when used with signal handlers.
&lt;br /&gt;
&lt;br /&gt;At best they provide absolutely no protection what-so-ever because they are run on the same thread and just work. Which is typically what the misguided programmer thinks they wanted.
&lt;br /&gt;
&lt;br /&gt;At worst they hang in the spin lock portion of the locking/unlocking primitive, unless it's entirely atomic implemented via a single CAS (most aren't). Which is just like with a regular lock, but with a such a small deadlock window that most programmer's don't catch them for years.
&lt;br /&gt;</description><guid isPermaLink="true">1380e2939ef6ac5a5ad67b0a8544d807</guid><pubDate>Sun, 03 Apr 2011 20:25:31 GMT</pubDate></item><item><title>arwyn - 2011-04-03 20:15:12</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>Dave -- a race condition in "set a bit" style signal handling would be a bug, not an inherent problem with the method. It's pretty easy to do it safely and race condition free, like so:
&lt;br /&gt;
&lt;br /&gt;signal handler:
&lt;br /&gt;do {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;old_bits = gSignalBits;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new_bits = old_bits | (1 &amp;lt;&amp;lt; signum);
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (old_bits == new_bits)
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return;
&lt;br /&gt;} while(!CAS(new_bits,old_bits,&amp;amp;gSignalBits));
&lt;br /&gt;nonblocking_write(fd,1);
&lt;br /&gt;
&lt;br /&gt;threaded signal dispatcher:
&lt;br /&gt;while(1)
&lt;br /&gt;{
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;do {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bits = gSignalBits;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while(!CAS(bits,0,&amp;amp;gSignalBits));
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (bits == 0)
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;blocking_read(fd,1);
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ((bits &amp;amp; DO_SOMETHING_BIT) != 0)
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;do_something();
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;}</description><guid isPermaLink="true">5eedddbf9a09bb6db4abac9780874f4f</guid><pubDate>Sun, 03 Apr 2011 20:15:12 GMT</pubDate></item><item><title>mikeash - 2011-04-02 14:53:06</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>If you really want to write a signal handler, take advantage of the fact that &lt;code&gt;write()&lt;/code&gt; is a safe call to make from one. Create a pipe, stick the read end into your event system, and write a byte to the write end to signal. Make sure the pipe is nonblocking, though, otherwise you could be in serious trouble.
&lt;br /&gt;
&lt;br /&gt;Of course there's no real reason to do that rather than using the built-in facilities which take care of the difficult parts for you.</description><guid isPermaLink="true">ee5782637e16a671ed5b25b98bbf8e8e</guid><pubDate>Sat, 02 Apr 2011 14:53:06 GMT</pubDate></item><item><title>Dave Zarzycki - 2011-04-02 14:10:13</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>Allen -- there are two problems with the "set a bit" style of signal handling.
&lt;br /&gt;
&lt;br /&gt;1) Race conditions. For example:
&lt;br /&gt;
&lt;br /&gt;if (bit) do_something();
&lt;br /&gt;// signal fires
&lt;br /&gt;r = select();
&lt;br /&gt;// select doesn't return -1 with errno == EINTR in this case like one would expect. Therefore: the bit isn't noticed and acted upon until the next FD becomes readable/writable, which may be a long time
&lt;br /&gt;
&lt;br /&gt;This is why pselect() was later invented, so that one might control when the signals fire. The availability of pselect() doesn't help a developer though if they're using a system provided event loop technology rather than rolling their own. This is one of may reasons why facilities like GCD exist.
&lt;br /&gt;
&lt;br /&gt;2) The vast majority of app and library code doesn't check for errno being equal to EINTR after an error and retry. That is why when we were designing GCD, we blocked all of the maskable signals from being delivered on GCD threads.</description><guid isPermaLink="true">44b06398e629778a2a51355d055fba0d</guid><pubDate>Sat, 02 Apr 2011 14:10:13 GMT</pubDate></item><item><title>Allen Brunson - 2011-04-02 13:57:08</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>Given all the constraints, I've always written raw signal handlers to do nothing but set a flag, which is then noticed in some other part of the program, which takes action there. Can you think of any cases where that won't work?</description><guid isPermaLink="true">8c9f61b0b192095f519b4375d639971a</guid><pubDate>Sat, 02 Apr 2011 13:57:08 GMT</pubDate></item><item><title>mikeash - 2011-04-01 21:50:44</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>That's a good question. The short version is, "reentrant" is a general concept, and "async-signal-safe" applies it to the specific case of signal handlers.
&lt;br /&gt;
&lt;br /&gt;Reentrancy doesn't necessarily have to apply to interrupts. For example, you'll find a note in the Cocoa documentation that NSNotificationCenter is reentrant. That most certainly does not mean that you can call it from a signal handler! Instead, what this means is that you can safely reenter NSNotificationCenter by calling into it from code which is in turn being called by NSNotificationCenter because of a posted notification.
&lt;br /&gt;
&lt;br /&gt;That sort of reentrancy is much more useful (it's a good idea for almost any code with callbacks) and much easier to achieve (just make sure you're in a clean state and not holding any locks when you call the callback).
&lt;br /&gt;
&lt;br /&gt;In the context of signal handling they're really the same, but in general not entirely.</description><guid isPermaLink="true">2352c71c57ebee4d86c929e2a4d83024</guid><pubDate>Fri, 01 Apr 2011 21:50:44 GMT</pubDate></item><item><title>Gwynne Raskind - 2011-04-01 21:24:15</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>Is there a difference, practically or conceptually, between "reentrant" and the even bigger mouthful "async-signal-safe"?</description><guid isPermaLink="true">fcbd3ea68c50fd17cf626736016242df</guid><pubDate>Fri, 01 Apr 2011 21:24:15 GMT</pubDate></item><item><title>Dave Zarzycki - 2011-04-01 20:51:30</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>One more thing:
&lt;br /&gt;
&lt;br /&gt;4) Keep in mind that setting SIGCHLD to SIG_IGN has standards defined side effects. Namely, one cannot call the wait*() family of APIs against child processes when SIGCHLD is ignored.</description><guid isPermaLink="true">764964ff35aa53fa1408c5bd625f8453</guid><pubDate>Fri, 01 Apr 2011 20:51:30 GMT</pubDate></item><item><title>Dave Zarzycki - 2011-04-01 20:40:58</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>1) App developers should call signal(SIGPIPE, SIG_IGN) at the top of main() and library developers should defensively/politely set SO_NOSIGPIPE via setsockopt(). Why? Because network connectivity problems can cause SIGPIPE to be sent to your process instead of the more reasonable "read() returns -1 and errno equal EPIPE" error.
&lt;br /&gt;
&lt;br /&gt;2) Always remember to backup and restore the previous signal mask if one uses pthread_sigmask() or sigprocmask(). As a general rule, one cannot assume that one's caller hasn't also fiddled with the mask.
&lt;br /&gt;
&lt;br /&gt;3) Library writers should never install real signals handlers via signal() or sigaction(). The kernel only supports one handler and therefore that is the right of the app, not libraries. Libraries should use technologies like GCD or kqueues directly (if one must).</description><guid isPermaLink="true">e255c94cee98b583e5236605a83baa01</guid><pubDate>Fri, 01 Apr 2011 20:40:58 GMT</pubDate></item><item><title>Kentzo - 2011-04-01 18:41:41</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>It's important to say that there are two signals which cannot be handled: SIGKILL and SIGSTOP.</description><guid isPermaLink="true">0894bdace177bf2514ad7821c84a311c</guid><pubDate>Fri, 01 Apr 2011 18:41:41 GMT</pubDate></item><item><title>mikeash - 2011-04-01 16:43:00</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>That's a good one indeed. I prefer not having a dedicated thread whenever possible, but that does look like a decent way to go.</description><guid isPermaLink="true">9944974f6b8604d0dd2bdcabacb0e42c</guid><pubDate>Fri, 01 Apr 2011 16:43:00 GMT</pubDate></item><item><title>Jens Ayton - 2011-04-01 16:34:34</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2011-04-01-signal-handling.html#comments</link><description>There’s another option: sigwait() on a dedicated thread. It’s as simple as anything involving “dedicated thread”, and cross-platform.</description><guid isPermaLink="true">cedcc2302dc1ef6f570258b2d0054f99</guid><pubDate>Fri, 01 Apr 2011 16:34:34 GMT</pubDate></item></channel></rss>
