If you are developing daemons to run on Mac OS X version 10.4 and later, it is highly recommended that you design your daemons to be launchd
-compliant. Using launchd
provides better performance and flexibility for daemons. It also improves the ability of administrators to manage the daemons running on a given system.
If you are running per-user background processes for Mac OS X v10.4 and later, launchd
is also the preferred way to start these processes. These per-user processes are referred to as user agents. A user agent is essentially identical to a daemon, but is specific to a given logged-in user and executes only while that user is logged in.
Unless otherwise noted, for the purposes of this chapter, the terms “daemon” and “agent” can be used interchangeably. Thus, the term “daemon” is used generically in this section to encompass both system-level daemons and user agents except where otherwise noted.
There are four ways to launch daemons using launchd
. The preferred method is on-demand launching, but launchd
can launch daemons that run continuously, and can replace inetd
for launching inetd
-style daemons. This chapter describes these three methods.
In addition, launchd
can start jobs at timed intervals much like cron
jobs. This is described in “Timed Jobs Using launchd.”
The launchd Startup Process
Daemon Requirements
Creating a Launchd Property List File
Deciding When to Shut Down
Special Dependencies
Non-Launch-on-Demand Daemons
For More Information
After the system is booted and the kernel is running, launchd
is run to finish the system initialization. As part of that initialization, it goes through the following steps:
It loads the parameters for each launch-on-demand system-level daemon from the property list files found in /System/Library/LaunchDaemons/
and /Library/LaunchDaemons/
.
It registers the sockets and file descriptors requested by those daemons.
It launches any daemons that requested to be running all the time.
As requests for a particular service arrive, it launches the corresponding daemon and passes the request to it.
When the system shuts down, it sends a SIGTERM
signal to all of the daemons that it started.
The process for per-user agents is similar. When a user logs in, a per-user launchd
is started. It does the following:
It loads the parameters for each launch-on-demand user agent from the property list files found in /System/Library/LaunchAgents
, /Library/LaunchAgents
, and the user’s individual Library/LaunchAgents
directory.
It registers the sockets and file descriptors requested by those daemons.
It launches any daemons that requested to be running all the time.
As requests for a particular service arrive, it launches the corresponding daemon and passes the request to it.
When the user logs out, it sends a SIGTERM
signal to all of the user agents that it started.
Because launchd
registers the sockets and file descriptors used by all daemons before it launches any of them, daemons can be launched in any order. If a request comes in for a daemon that is not yet running, the requesting process is suspended until the target daemon finishes launching and responds.
If a daemon does not receive any requests over a specific period of time, it can choose to shut itself down and release the resources it holds. When this happens, launchd
monitors the shutdown and makes a note to launch the daemon again when future requests arrive.
Important: If your daemon shuts down too quickly after being launched, launchd
may think it has crashed. Daemons that continue this behavior may be suspended and not launched again when future requests arrive. To avoid this behavior, do not shut down for at least 10 seconds after launch.
If you are looking to implement a daemon that supports launchd
, there are some behaviors with which you should be familiar. Creating daemons to run under launchd
is actually simpler than in previous versions of Mac OS X. The reason is that many tasks normally implemented in your daemon code are now handled automatically by launchd
.
Note: The following sections describe only the changes you must make to your daemons to support launchd
. The overall process for creating daemons is not covered.
To support launchd
, you must obey the following guidelines when writing your daemon code:
You must provide a property list with some basic launch-on-demand criteria for your daemon. See “Creating a Launchd Property List File.”
You must not fork your process and have the parent process exit.
You must not daemonize your process. This includes calling the daemon
function, calling fork
followed by exec
, or calling fork
followed by exit
. If you do, launchd
thinks your process has died. Depending on your property list key settings, launchd
will either keep trying to relaunch your process until it gives up (with a “respawning too fast” error message) or will be unable to restart it if it really does die.
Your daemon and its property list file must be owned by the root user (except for agents, which may be owned by the logged-in user), and must not be group writable or other writable.
Although they are normally part of the daemon creation process, it is worth emphasizing that forking and exiting the parent process and calling the daemon
function must be avoided if you want to support launchd
. The launchd
program configures your daemon to run as a daemon before your code is ever called, so these steps are unnecessary. In addition, calling them interferes with the ability of launchd
to launch your daemon on demand.
To support launchd
, it is recommended that you obey the following guidelines when writing your daemon code:
Wait until your daemon is fully initialized before attempting to process requests. Your daemon should always provide a reasonable response (as opposed to an error) when processing requests.
Register the sockets and file descriptors used by your daemon in your launchd
configuration property list file.
Check in with launchd
as part of your daemon initialization using the routines in launch.h
.
During checkin, get the launch dictionary from launchd
, extract its contents, store those contents locally, and get rid of the dictionary. Caching the dictionary locally and accessing it frequently could hurt performance.
Provide a handler to catch the SIGTERM
signal.
In addition to the preceding list, the following is a list of things it is recommended you do not do in your code:
Do not set the user or group ID for your daemon. Include the UserName
, UID
, GroupName
, or GID
keys in your daemon’s configuration property list instead.
Do not set the working directory. Include the WorkingDirectory
key in your daemon’s configuration property list instead.
Do not call chroot
to change the root directory. Include the RootDirectory
key in your daemon’s configuration property list instead.
Do not call setsid
to create a new session.
Do not close any stray file descriptors.
Do not change stdio
to point to /dev/null
. Include the StandardOutPath
or StandardErrorPath
keys in your daemon’s configuration property list file instead.
Do not set up resource limits with setrusage
.
Do not set the daemon priority with setpriority
Although many of the preceding behaviors may be standard tasks for daemons to perform, they are not recommended when running under launchd
. The reason is that launchd
configures the operating environment for the daemons that it manages. Changing this environment could interfere with the normal operation of your daemon.
To run under launchd
, you must provide a configuration property list file for your daemon. This file contains information about your daemon, including the list of sockets or file descriptors it uses to process requests. Specifying this information in a property list file lets launchd
register the corresponding file descriptors and launch your daemon only after a request arrives for your daemon’s services. Table 1 lists the required and recommended keys for all daemons.
Depending on the needs of your daemon, you would also include other keys in your configuration property list file. For example, if your daemon monitors a well-known port (those listed in /etc/services
), you would add a Sockets
entry that looks like this:
<key>Sockets</key> <dict> <key>Listeners</key> <dict> <key>SockServiceName</key> <string>bootps</string> <key>SockType</key> <string>dgram</string> <key>SockFamily</key> <string>IPv4</string> </dict> </dict> |
Note that the string for SockServiceName
typically comes from the leftmost column in /etc/services
. The SockType
is one of dgram
(UDP) or stream
(TCP/IP).
If you need to pass a port number that is not listed in the well-known ports list, the format is basically the same, except the string contains a number instead of a name. For example:
<key>SockServiceName</key> |
<string>23</string> |
You can also pass additional keys to further configure your daemon. For a list of sample configuration property lists, look at the files in /System/Library/LaunchDaemons/
. These files are used to configure many daemons that run on Mac OS X.
For additional information about the keys you can specify in your configuration property list file, see the man
page for launchd.plist
.
If you do not expect your daemon to handle many requests, you might want to shut it down after a predetermined amount of idle time, rather than continue running. Although a well-written daemon does not consume any CPU resources, it still consumes memory and could be paged out during periods of intense memory use.
The timing of when to shut down is different for each daemon and depends on several factors, including:
The number and frequency of requests it receives
The time it takes to launch the daemon
The time it takes to shut down the daemon
The need to retain state information
If your daemon does not receive frequent requests and can be launched and shut down quickly, you might prefer to shut it down rather than wait for it to be paged out to disk. Paging memory to disk, and subsequently reading it back, incurs two disk operations. If you do not need the data stored in memory, your daemon can shut down and avoid the step of writing memory to disk.
While launchd
takes care of dependencies between daemons, in some cases, your daemon may depend on other system functionality that cannot be addressed in this manner. This section describes many of these special cases and how to handle them.
If your daemon depends on the availability of a mounted volume (whether local or remote), you can determine the status of that volume using the disk arbitration framework. This is documented in Disk Arbitration Framework Reference.
If your daemon requires that a certain kernel extension be loaded prior to executing, you have two options: load it yourself, or wait for it to be loaded.
The daemon may manually request that an extension be loaded. To do this, run kextload
with the appropriate arguments using exec
or variants thereof.
Note: The kextload
executable must be run as root in order to load extensions into the kernel. For security reasons, it is not a setuid executable. This means that your daemon must either be running as the root user or must include a helper binary that is setuid root in order to use kextload
to load a kernel extension.
Your daemon may wait for a kernel service to be available. To do this, you should first register for service change notification using the functions described in IOKitLib
. This header is part of the I/O Kit Framework, which is further documented in I/O Kit Framework Reference.
After registering for these notifications, you should check to see if the service is already available. By doing this after registering for notifications, you avoid waiting forever if the service becomes available between checking for availability and registering for the notification.
Note: In order for your kernel extension to be detected in a useful way, it must publish a node in the I/O registry to advertise the availability of its service. For I/O Kit drivers, this is usually handled by the I/O Kit family.
For other kernel extensions, you must explicitly register the service by publishing a nub, which must be an instance ofIOService
.For more information about I/O Kit services and matching, see I/O Kit Fundamentals, I/O Kit Framework Reference (user space reference), and Kernel Framework Reference (kernel space reference).
If your daemon depends on the network being available with a valid outgoing route, this cannot be handled with dependencies because network interfaces can come and go at any time in Mac OS X. To solve this problem, you should use the network reachability functionality in the system configuration framework. This is documented in System Configuration Programming Guidelines and System Configuration Framework Reference.
If your daemon has a dependency on a non-launchd daemon, you must take additional care to ensure that your daemon works correctly if that non-launchd daemon has not started when your daemon is started. The best way to do this is to include a loop at start time that checks to see if the non-launchd daemon is running, and if not, sleeps for several seconds before checking again.
Be sure to set up handlers for SIGTERM
prior to this loop to ensure that you are able to properly shut down if the daemon you rely on never becomes available.
In general, a daemon should not care whether a user is logged in, and user agents should be used to provide per-user functionality. However, in some cases, this may be useful.
To determine what user is logged in at the console, you can use the system configuration framework to register for login and logout notifications, as described in Technical Q&A QA1133.
While most daemons should generally be run on demand, it can sometimes be useful to run a daemon continuously.
In Mac OS X v10.3 and earlier, the preferred facility for launching a daemon was a startup item. If you need to support versions of Mac OS X prior to v10.4, you should use a startup item. This is described in “Creating a Startup Item.”
In Mac OS X v10.4 and later, the preferred facility for launching daemons is launchd
. To create a non-on-demand launchd
daemon, you need to add some additional keys to your daemon’s launchd property list file:
OnDemand—set this to false
. This will tell launchd
that your daemon is not designed for on-demand launching.
RunAtLoad—set this to true
. This will cause your daemon to be launched as soon as launchd starts. Because of the nature of on-demand facilities for things like networking, any dependencies will automatically be launched as needed to support your daemon.
Important: Before using launchd
to launch any daemon (on-demand or otherwise), you should read about the requirements for a launchd
daemon in “Daemon Requirements.”
In particular, your daemon must not daemonize itself (fork
and exit). If it does, launchd
will interpret this as a failed launch and will repeatedly try to respawn it before eventually giving up.
The manual pages for launchd
and launchd.plist
are the two best sources for information about launchd
.
In addition, you can find a source daemon accompanying the launchd
source code (available from http://www.macosforge.org/). This daemon is also provided from the ADC reference library as the SampleD sample code project.
Finally, many Apple-provided daemons support launchd
. Their property list files can be found in /System/Library/LaunchDaemons
. Some of these daemons are also available as open source from http://www.opensource.apple.com/ or http://www.macosforge.org/.
© 2003, 2008 Apple Inc. All Rights Reserved. (Last updated: 2008-11-19)