The Future of Init, Part IIb: OS X Launchd

28 Oct '05 - 01:08 by benr

First and foremost, I must thank Mr. Nathan 'RbdPngn' Ingersoll, Enlightenment Core Developer and father of the Enlightenment Widget Library the EFL official widget toolkit, for trusting me enough to give me root access on his beloved Mac running Tiger. Without access to his system and the ability to experiement I wouldn't have been able to produce this entry.

First released with Mac OS X 10.4 (aka: Tiger), launchd was introduced as a full init replacement to dramatically change the way the system was managed and introduce a whole new way of thinking about the job of init. In prior releases the old BSD rc system was used, supplimented with SystemStarter, which we discussed last time around. But SystemStarter didn't go nearly far enough, it was a system that was better than SysV init (/etc/init.d/, /etc/rc2.d/, etc) but simply isn't a robust and full featured system capable of taking over init's job.

Launchd is said to be "one daemon to rule them all", but that statement doesn't go far enough to convey a sense of what it really is. Yes, as a true init replacement it runs as PID1, called by the kernel as part of the boot proccess, but there is more too it than that. The beauty of launchd is that its the first init system that really was designed in a wholistic manner, considering the various needs of a UNIX system and solving a variety of them at once. But how?

Typically we think of an init system as the thing that starts up proccess when the system starts and shuts them down when it reboots or powers off. To some degree init can manage these processes via methods like inittab respawn. Newer systems add even more control by leveraging a daemon to watch proccesses and restart them if they fail, but lets think about this in a diffrent way entirely. Instead of thinking about managing services lets think of the init system as a basic sort of job schedualer. What other types of things on a UNIX system might fall into the job schedualer category? Inetd does, it starts a daemon when requested and then shuts it down when its not. And both cron and at are job schedualers too. These 3 diffrent tools (init, inetd, and cron/at) can be thought of as very similar things, except that init starts things once and lets the run for long periods of time, inetd fires things on demand, and cron/at fire things on schedualed intervals. They aren't so diffrent. This is what Apple had in mind when it created launchd. Launchd can take these tools that we typically think of as very diffrent and bring them together.

Some of the chief benifits of pulling together so many elements of the system together is that you need only one daemon instead of 3+, you enable centralized control and management, and you eliminate the headache of all these diffrent tools implementation details. Look no further than the configuration files, init has rc scripts, SystemStarter has its XML and scripts, cron has crontabs, inetd has its own config files, so on and so forth. Thanks to launchd you don't have to spread things across the system in diffren config files that act completely diffrently and consolidate to a single tool.

Configuring launchd is very similar to SystemStarter. Within /System/Library/LaunchDaemons are a variety of plist's, one per service. These plists are fundimentally similar to those used by SystemStarter. Have a look at the ftp.plist:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>Disabled</key>
        <true/>

        <key>Label</key>
        <string>com.apple.ftpd</string>
        <key>Program</key>
        <string>/usr/libexec/ftpd</string>

        <key>ProgramArguments</key>
        <array>
                <string>ftpd</string>
                <string>-l</string>

        </array>
        <key>inetdCompatibility</key>
        <dict>
                <key>Wait</key>
                <false/>

        </dict>
        <key>Sockets</key>
        <dict>
                <key>Listeners</key>
                <dict>

                        <key>SockServiceName</key>
                        <string>ftp</string>
                        <key>Bonjour</key>
                        <true/>

                </dict>
        </dict>
</dict>
</plist>

You can see that the XML plist contains a dictionary made up of key/value pairs. Disabled, true. Program, /usr/libexec/ftpd. You notice that there isn't a reference to a script containing start/stop/restart scripts similar to SystemStarter though. In fact, on the Tiger system that I looked at none of the launchd plists referenced scripts. As of the Tiger release of OS X SystemStarter and launchd co-exist, so services that need more than a single command to start are still handled by SystemStarter, but this is said to change in the future.

Another think you'll notice about the plist above is that its an inetd service. Whereas SystemStarter provided an OnDemand key, here we see syntax similar to that found in inetd configs.

In order to use a launchd service you must load its configuration using the launchctl command. Once the configuration (plist) is loaded we can use the same tool to list loaded services:

  $ sudo launchctl load -w /System/Library/LaunchDaemons/ntalk.plist
  $ sudo launchctl list
   ....
  com.apple.ntalkd

Notice that I'm passing the -w argument to launchctl, in my testing this was required. The -w flag removes the disabled key from the service, thus starting the service when it was loaded. If you don't use -w you'll get a "nothing found to load" error.

One aspect of launchd that I had to get used to was that the output of launchctl was based on your uid. Notice that when I list the services as a user (benr) I see nothing, but when I do it again with sudo (root) I see all the running services:


speedy:/System/Library/LaunchDaemons benr$ launchctl list
speedy:/System/Library/LaunchDaemons benr$ sudo launchctl list
com.apple.KernelEventAgent
com.apple.mDNSResponder
com.apple.nibindd
com.apple.periodic-daily
com.apple.periodic-monthly
com.apple.periodic-weekly
com.apple.portmap
com.apple.syslogd
com.vix.cron
org.postfix.master
org.xinetd.xinetd
com.openssh.sshd

One of the kool things about launchctl is that it can be used as a shell. This has its benifits:


launchd% help
usage: launchctl 
        load            Load configuration files and/or directories
        unload          Unload configuration files and/or directories
        start           Start specified jobs
        stop            Stop specified jobs
        list            List jobs and information about jobs
        setenv          Set an environmental variable in launchd
        unsetenv        Unset an environmental variable in launchd
        getenv          Get an environmental variable from launchd
        export          Export shell settings from launchd
        limit           View and adjust launchd resource limits
        stdout          Redirect launchd's standard out to the given path
        stderr          Redirect launchd's standard error to the given path
        shutdown        Prepare for system shutdown
        reloadttys      Reload /etc/ttys
        getrusage       Get resource usage statistics from launchd
        log             Adjust the logging level or mask of launchd
        umask           Change launchd's umask
        help            This help output

But perhaps my favorite feature of launchd is its ability to manage the resource usage of itself and its children. Have a look at the limits:


speedy:/System/Library/LaunchDaemons benr$ sudo launchctl limit
        cpu         unlimited      unlimited
        filesize    unlimited      unlimited
        data        6291456        unlimited
        stack       8388608        67108864
        core        0              unlimited
        rss         unlimited      unlimited
        memlock     unlimited      unlimited
        maxproc     100            532
        maxfiles    256            unlimited

These limits can be set globally or changed in the plist per service. Using launchctl we view the resource usage thus far by both launchd itself and its children like so:


launchd% getrusage children
        42.164101       user time used
        89.070940       system time used
        0               max resident set size
        0               shared text memory size
        0               unshared data size
        0               unshared stack size
        0               page reclaims
        0               page faults
        0               swaps
        46847           block input operations
        40149           block output operations
        27457           messages sent
        11113           messages received
        652             signals received
        113062          voluntary context switches
        0               involuntary context switches

The resource controls aren't nearly as advanced as Solaris's but they are better integrated. Currently there is not way to specify resource control within an SMF manifest, but perhaps something we'll have soon.

One thing that puzzled me was launchd's supposed replacment of cron, because launchd actually has a plist for Vixie-CRON. Why? Perhaps its a modified verson of it, but I found no evidence of that. I did play with at a bit but it didn't work properly. Theoretically I should have been able to schedual a job using at and then used launchctl list to see it queued to run. I didn't, but I didn't have enough time to really investigate.

All in all, launchd has an exceptional scope. Its bold and its forward looking. It certainly isn't as well rounded from an administrative point of view as InitNG or SMF but its got some definate possibliities that the others don't. Tiger was just the debut, what we really need to watch for is what happens in Mac OS X 10.5... will SystemStart go away? Will we actually see launchd be the one stop shop that it was meant to be? All signs that I see lead to "it should" right now, but we won't know for sure untill it arrives (or someone sends me a beta).

I want to point out that one of the chief advantages of launchd is supposed to be its API. Launchd is said to give the programmer unsurpased control in code, unlike they've ever had before. Certainly on a GUI driven platform like OS X this is of utmost importance. But that discussion is beyond the scope of this document, so I'll leave you to fend on your own.

For more information about launchd check out the following resources:


- - C O M M E N T S - -

Hope you come back soon!!

marhta (Email) (URL) - 12 June '06 - 21:57

Holla and Happy Thanksgiving.

bobbie (Email) (URL) - 13 June '06 - 00:10

Follow your dreams, you can reach your goals.

jillian (Email) (URL) - 13 June '06 - 01:06

Your pictures are great.

laurette (Email) (URL) - 14 June '06 - 02:19

Personal information





Remember your information?
Comment

Small print: All html tags except <b> and <i> will be removed from your comment. You can make links by just typing the url or mail-address.


^M