Search code examples
objective-cmacoslaunchdnice

How to programmatically run a command with low IO priority and high niceness value on OS X


Is there a way to basically call system(), but with a predefined niceness value (20) and low IO priority from Objective-C?

(The low IO priority setting I'm talking about is the one launchd has)

I'm trying to launch /usr/bin/purge from within my Objective-C program.

It would also be ideal for the method to be approved for the Mac App Store.


Solution

  • Edit: Fork and exec no more, since OSX can't really fork right. Single thread magic:

    setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE);
    system("nice -n 20 /usr/bin/purge");
    setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_DEFAULT);
    

    This can go anywhere, in a dispatch block if you want, or anywhere in your application. No fork in sight. Also, feel free to replace system with NSTask if you want to stay ObjCish.


    How about a good old forknexec:

    #include <unistd.h>
    #include <sys/resource.h>
    

    And:

    if(fork()) {
      /* Set IO priority */
      setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE);
      /*IO priority is inherited*/
      execl("nice", "-n", "20", "/usr/bin/purge");
    }
    

    Let's walk through this:

    • fork: Nothing to see here
    • setiopolicy_np: This is the place where we set IO priority (like launchd). Here are the arguments:

      • IOPOL_TYPE_DISK: We want to limit Disk I/O. There is no other option available anyway.
      • IOPOL_SCOPE_PROCESS: Affects this whole process
      • IOPOL_THROTTLE: This is the policy itself. Accouring to the Apple documentation, it specifies this:

      I/Os with THROTTLE policy are called THROTTLE I/Os. If a THROTTLE I/O request occurs within a small time window (usually a fraction of a second) of another NORMAL I/O request, the thread that issues the THROTTLE I/O is forced to sleep for a certain interval. This slows down the thread that issues the THROTTLE I/O so that NORMAL I/Os can utilize most of the disk I/O bandwidth. Furthermore, a NORMAL I/O request may bypass a previously issued THROTTLE I/O request in kernel or driver queues and be sent to the device first. In some circumstances, very large THROTTLE I/O requests will be broken into smaller requests which are then issued serially.

    I/O priority is inherited, and the nice part of the command sets the nice value.