What can nanoscale drift do in exactly 10 seconds on Mac OS X 10.9

Part of my program needs to sleep for 10 milliseconds. I usually use boost lib for this, but it sometimes sleeps for 10010 milliseconds, so I tried replacing




struct timespec a;
a.tv_sec  = 0;
a.tv_nsec = read_delay_ms * 1000000;
int rc = nanosleep( &a, NULL );


Unsurprisingly, nanosleep usage also sometimes drops off in 10010 milliseconds (sleep_for is implemented using nanosleep () on mac).

My program is complex, so I could not create a small example that illustrates the problem, I am working on it. Here are some highlights:

  • This is a python extension written in C ++ using boost :: python as a bridge

  • Uses boost :: threads for asynchrony tasks using boost :: asio

The problem is only visible on Mac OS X 10.9. This is not visible on Mac OS X 10.8 and below, not Linux, win, iOS, and Android.

To find a bug in my code activate lib or sys functions, any help or suggestions are more welcome.


source to share

2 answers

App Nap is most likely the reason for this. It was introduced in 10.9 and is already known for causing such surprises.


It has three new methods for temporarily disabling Nap app: beginActivityWithOptions:reason:

, endActivity:

, performActivityWithOptions:reason:block:


You can also disable it by writing a boolean YES in NSAppSleepDisabled

the default user of your application domain.



Here is a software solution, written in C, that will compile and run on both old and newer versions of OS X (i.e. you don't need 10.9 or work in Objective C to compile this).

Call osx_latencycritical_start()

at the beginning of your program, or at least before critical synchronization operations begin. Call osx_latencycritical_end()

if your code no longer does time-critical work.

(The code is recursive, but not thread safe. I am hosting this code on a public domain.)

#if defined(__APPLE__)

# include <objc/runtime.h>
# include <objc/message.h>
# include <objc/objc-runtime.h>

/* Globals */
static int osx_latencycritical_count = 0;
static id osx_latencycritical_activity = nil;

/* Tell App Nap that this is latency critical */
void osx_latencycritical_start() {
    Class pic;      /* Process info class */
    SEL pisl;       /* Process info selector */
    SEL bawo;       /* Begin Activity With Options selector */
    id pi;          /* Process info */
    id str;         /* Reason string */

    if (osx_latencycritical_count++ != 0)

    /* Avoid triggering an exception when run on older OS X */
    if ((pic = (Class)objc_getClass("NSProcessInfo")) == nil)

    if (class_getClassMethod(pic, (pisl = sel_getUid("processInfo"))) == NULL)

    if (class_getInstanceMethod(pic,
          (bawo = sel_getUid("beginActivityWithOptions:reason:"))) == NULL)

    /* Get the process instance */
    if ((pi = objc_msgSend((id)pic, pisl)) == nil)

    /* Create a reason string */
    str = objc_msgSend(objc_getClass("NSString"), sel_getUid("alloc"));
    str = objc_msgSend(str, sel_getUid("initWithUTF8String:"), "Timing Crititcal");

    /* Start activity that tells App Nap to mind its own business: */
    /* NSActivityUserInitiatedAllowingIdleSystemSleep */
    /* | NSActivityLatencyCritical */
    osx_latencycritical_activity = objc_msgSend(pi, bawo,
                    0x00FFFFFFULL | 0xFF00000000ULL, str);

/* Done with latency critical */
void osx_latencycritical_end() {
    if (osx_latencycritical_count > 0) {
        if (osx_latencycritical_count == 0
         && osx_latencycritical_activity != nil) {
            osx_latencycritical_activity = nil;

#endif /* __APPLE__ */




All Articles