Создание демонов запуска и агентов
При разработке демонов для работы OS X, он настоятельно рекомендован это, Вы разрабатываете своих демонов, чтобы быть launchd
совместимый. Используя launchd
обеспечивает лучшую производительность и гибкость для демонов. Это также улучшает возможность администраторов управлять демонами, работающими на данной системе.
Если Вы выполняете фоновые процессы в расчете на пользователя для OS X, launchd
также предпочтительный способ запустить эти процессы. Эти процессы в расчете на пользователя упоминаются как агенты пользователя. Агент пользователя является чрезвычайно идентичным демону, но является определенным для данного, вошел в систему пользователь и выполняется только, в то время как зарегистрирован тот пользователь.
Если не указано иное, в целях этой главы, термины «демон» и «агент» могут быть использованы взаимозаменяемо. Таким образом термин «демон» используется в общем в этом разделе для затрагивания и демонов системного уровня и агентов пользователя кроме, где иначе отмечено.
Существует четыре способа запустить демонов, использующих launchd
. Предпочтительный метод по требованию запускается, но launchd
может запустить демонов, которые работают постоянно и могут заменить inetd
для запуска inetd
- демоны стиля. Кроме того, launchd
может запустить задания в синхронизированных интервалах.
Несмотря на то, что launchd
поддержки не запускают по требованию демонов, это использование не рекомендуется. launchd
демон был разработан для устранения необходимости упорядочивания зависимости среди демонов. Если Вы не делаете своего демона, запускаются по требованию, необходимо будет обработать эти зависимости в другом отношении, такой как при помощи устаревшего механизма элемента запуска.
Запуск Пользовательских Демонов Используя launchd
С введением launchd
в OS X v10.4, усилие было приложено для улучшения, шаги должны были запустить и поддержать демонов. Что launchd
обеспечивает ремень безопасности для запуска Вашего демона по мере необходимости. К клиентским программам порт, представляющий службу Вашего демона, всегда доступен и готов обработать запросы. В действительности демон может или может не работать. Когда клиент отправляет запрос к порту, launchd
вероятно, придется запустить демона так, чтобы это могло обработать запрос. После того, как запущенный, демон может продолжать работать или завершить работу себя для высвобождения памяти и ресурсов, которые она содержит. Если демон завершает работу себя, launchd
еще раз перезапуски это по мере необходимости для обработки запросов.
В дополнение к функции запуска по требованию, launchd
предоставляет следующие преимущества разработчикам демона:
Упрощает процесс создания демона путем обработки многой из стандартной работы по дому обслуживания, обычно связанной с запуском демона.
Предоставляет системным администраторам центральное место для управления демонами в системе.
Поддержки
inetd
- демоны стиля.Устраняет основную причину для рабочих демонов как корень. Поскольку
launchd
выполнения как корень, это может создать TCP/IP с низким номером, слушают сокеты и передают их демону.Упрощает обработку ошибок и управление зависимостью для коммуникации междемона. Поскольку демоны запускаются по требованию, коммуникационные запросы не перестали работать, если не запускается демон. Они просто задерживаются, пока демон не может запустить и обработать их.
Процесс Запуска launchd
После того, как система загружается, и ядро работает, launchd
выполняется для окончания системной инициализации. Как часть той инициализации, это проходит через следующие шаги:
Это загружает параметры для каждого демона системного уровня запуска по требованию от файлов списка свойств, найденных в
/System/Library/LaunchDaemons/
и/Library/LaunchDaemons/
.Это регистрирует сокеты и дескрипторы файлов, которые требуют те демоны.
Это запускает любых демонов, запросивших работать все время.
Когда запросы на определенную службу поступают, она запускает соответствующего демона и передает запрос ему.
Когда система закрывается, она отправляет a
SIGTERM
сигнализируйте всем демонам, что это запустилось.
Процесс для агентов в расчете на пользователя подобен. Когда пользователь входит в систему, в расчете на пользователя launchd
запускается. Это делает следующее:
Это загружает параметры для каждого агента пользователя запуска по требованию от файлов списка свойств, найденных в
/System/Library/LaunchAgents
,/Library/LaunchAgents
, и частное лицо пользователяLibrary/LaunchAgents
каталог.Это регистрирует сокеты и дескрипторы файлов, которые требуют те агенты пользователя.
Это запускает любые агенты пользователя, запросившие работать все время.
Когда запросы на определенную службу поступают, она запускает соответствующий агент пользователя и передает запрос ему.
Когда пользователь выходит из системы, это отправляет a
SIGTERM
сигнализируйте ко всем агентам пользователя, что это запустилось.
Поскольку launchd
регистрирует сокеты и дескрипторы файлов, используемые всеми демонами, прежде чем это запустит любой из них, демоны могут быть запущены в любом порядке. Если запрос наталкивается на демона, еще не работающего, процесс запроса приостановлен, пока целевой демон не заканчивает запускаться и отвечает.
Если демон не получает запросов за определенный промежуток времени, он может принять решение завершить работу себя и высвободить средства, которые он содержит. Когда это происходит, launchd
когда будущие запросы поступают, контролирует завершение работы и записывает для запуска демона снова.
Создание launchd Файла Списка свойств
Работать под launchd
, необходимо предоставить файл списка свойств конфигурации демону. Этот файл содержит информацию о Вашем демоне, включая список сокетов или дескрипторов файлов, которые это использует для обработки запросов. Указание этой информации в файле списка свойств позволяет launchd
зарегистрируйте соответствующие дескрипторы файлов и запустите Вашего демона только после того, как запрос поступит для служб Вашего демона. Таблица 5-1 перечисляет требуемые и рекомендуемые ключи для всех демонов.
Файл списка свойств структурирован то же и для демонов и для агентов. Вы указываете, описывает ли это демона или агент каталогом, в который Вы помещаете его. Файлы списка свойств, описывающие демонов, установлены в /Library/LaunchDaemons
, и те, которые описывают агенты, установлены в /Library/LaunchAgents
или в LaunchAgents
подкаталог отдельного пользователя Library
каталог. (Надлежащее расположение для исполнимых программ, которые Вы запускаете от своего задания, /usr/local/libexec
.)
Запись “Привет Мир!” Задание launchd
Следующий простой пример запускается, демон назвал hello
, передача world
как отдельный аргумент, и дает launchd команду сохранять выполнение задания:
<?xml version="1.0" encoding="UTF-8"?> |
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
<plist version="1.0"> |
<dict> |
<key>Label</key> |
<string>com.example.hello</string> |
<key>ProgramArguments</key> |
<array> |
<string>hello</string> |
<string>world</string> |
</array> |
<key>KeepAlive</key> |
<true/> |
</dict> |
</plist> |
В этом примере существует три ключа в высокоуровневом словаре. Первое Label
, который однозначно определяет задание. когда. Второе ProgramArguments
который имеет значение массива строк, представляющих маркируемые параметры и программу для выполнения. Третий и заключительный ключ KeepAlive
который указывает, что это задание должно работать в любом случае, а не поведение запуска по требованию по умолчанию, таким образом, launchd должен всегда пытаться сохранить это выполнение задания.
Слушание на сокетах
Можно также включать другие ключи файле списка свойств конфигурации. Например, если Ваш демон контролирует стандартный порт (один из портов, перечисленных в /etc/services
), добавьте a Sockets
запись следующим образом:
<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> |
Строка для SockServiceName
обычно прибывает из крайнего левого столбца в /etc/services
. SockType
один из dgram
(UDP) или stream
(TCP/IP). Если необходимо передать номер порта, не перечисленный в списке стандартных портов, формат является тем же, кроме строки содержит число вместо имени. Например:
<key>SockServiceName</key> |
<string>23</string> |
Отладка launchd Джобс
Существуют некоторые опции, которые полезны для отладки Вашего launchd задания.
Следующий пример включает дампы ядра, устанавливает норму и ошибку перейти к файлу журнала, и дает launchd команду временно увеличиваться, уровень отладки его журналирования при действии от имени задания (не забудьте корректировать syslog.conf соответственно):
<?xml version="1.0" encoding="UTF-8"?> |
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
<plist version="1.0"> |
<dict> |
<key>Label</key> |
<string>com.example.sleep</string> |
<key>ProgramArguments</key> |
<array> |
<string>sleep</string> |
<string>100</string> |
</array> |
<key>StandardOutPath</key> |
<string>/var/log/myjob.log</string> |
<key>StandardErrorPath</key> |
<string>/var/log/myjob.log</string> |
<key>Debug</key> |
<true/> |
<key>SoftResourceLimits</key> |
<dict> |
<key>Core</key> |
<integer>9223372036854775807</integer> |
</dict> |
<key>HardResourceLimits</key> |
<dict> |
<key>Core</key> |
<integer>9223372036854775807</integer> |
</dict> |
</dict> |
</plist> |
Выполнение задания периодически
Следующий пример создает рабочее место, выполняющееся каждые пять минут (300 секунд):
<?xml version="1.0" encoding="UTF-8"?> |
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
<plist version="1.0"> |
<dict> |
<key>Label</key> |
<string>com.example.touchsomefile</string> |
<key>ProgramArguments</key> |
<array> |
<string>touch</string> |
<string>/tmp/helloworld</string> |
</array> |
<key>StartInterval</key> |
<integer>300</integer> |
</dict> |
</plist> |
Поочередно, можно указать основанный на календаре интервал. Следующий пример запускает задание в 7-й день каждого месяца в 13:45 (13:45). Как подсистема крона Unix, любой недостающий ключ StartCalendarInterval
словарь обрабатывается как подстановочный знак — в этом случае, месяц опущен, таким образом, задание выполняется каждый месяц.
<?xml version="1.0" encoding="UTF-8"?> |
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
<plist version="1.0"> |
<dict> |
<key>Label</key> |
<string>com.example.touchsomefile</string> |
<key>ProgramArguments</key> |
<array> |
<string>touch</string> |
<string>/tmp/helloworld</string> |
</array> |
<key>StartCalendarInterval</key> |
<dict> |
<key>Minute</key> |
<integer>45</integer> |
<key>Hour</key> |
<integer>13</integer> |
<key>Day</key> |
<integer>7</integer> |
</dict> |
</dict> |
</plist> |
Контроль каталога
Следующий пример запускает задание каждый раз, когда изменился любой из наблюдаемых путей:
<?xml version="1.0" encoding="UTF-8"?> |
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
<plist version="1.0"> |
<dict> |
<key>Label</key> |
<string>com.example.watchhostconfig</string> |
<key>ProgramArguments</key> |
<array> |
<string>syslog</string> |
<string>-s</string> |
<string>-l</string> |
<string>notice</string> |
<string>somebody touched /etc/hostconfig</string> |
</array> |
<key>WatchPaths</key> |
<array> |
<string>/etc/hostconfig</string> |
</array> |
</dict> |
</plist> |
Дополнительный триггер файловой системы является понятием каталога очереди. launchd демон запускает Ваше задание каждый раз, когда данные каталоги непусты, и оно сохраняет Вашу работу, работающую, пока те каталоги не пусты:
<?xml version="1.0" encoding="UTF-8"?> |
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
<plist version="1.0"> |
<dict> |
<key>Label</key> |
<string>com.example.mailpush</string> |
<key>ProgramArguments</key> |
<array> |
<string>my_custom_mail_push_tool</string> |
</array> |
<key>QueueDirectories</key> |
<array> |
<string>/var/spool/mymailqdir</string> |
</array> |
</dict> |
</plist> |
Эмуляция inetd
launchd демон эмулирует более старое inetd
- разработайте семантику демона, если Вы обеспечиваете inetdCompatibility
ключ:
<?xml version="1.0" encoding="UTF-8"?> |
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
<plist version="1.0"> |
<dict> |
<key>Label</key> |
<string>com.example.telnetd</string> |
<key>ProgramArguments</key> |
<array> |
<string>/usr/libexec/telnetd</string> |
</array> |
<key>inetdCompatibility</key> |
<dict> |
<key>Wait</key> |
<false/> |
</dict> |
<key>Sockets</key> |
<dict> |
<key>Listeners</key> |
<dict> |
<key>SockServiceName</key> |
<string>telnet</string> |
<key>SockType</key> |
<string>stream</string> |
</dict> |
</dict> |
</dict> |
</plist> |
Поведение для Процессов, Управляемых launchd
Процессы, которыми управляют launchd
должен следовать за определенными требованиями так, чтобы они взаимодействовали должным образом с launchd
. Это включает демонов запуска и агенты запуска.
Требуемые способы поведения
Поддерживать launchd
, необходимо повиноваться следующим инструкциям при записи кода демона:
Необходимо предоставить списку свойств некоторые основные критерии запуска по требованию демона. Посмотрите Создание launchd Файла Списка свойств.
Вы не должны daemonize Ваш процесс. Это включает вызов
daemon
функция, вызываяfork
сопровождаемыйexec
, или вызовfork
сопровождаемыйexit
. Если Вы делаете,launchd
думает, что умер Ваш процесс. В зависимости от Ваших ключевых настроек списка свойств,launchd
или продолжит пытаться повторно запустить Ваш процесс, пока он не сдается (с “перепорождением слишком быстро” сообщение об ошибке) или будет неспособен перезапустить его, если он действительно умирает.Демоны и агенты, установленные глобально, должны принадлежать полностью пользователь. Агенты, установленные для текущего пользователя, должны принадлежать тому пользователю. Все демоны и агенты не должны быть перезаписываемой группой или перезаписываемый мир. (Т.е. им нужно было установить режим файла в
600
или400
.)
Рекомендуемые способы поведения
Поддерживать launchd
, рекомендуется повиноваться следующим инструкциям при записи кода демона:
Ожидайте, пока Ваш демон не будет полностью инициализирован прежде, чем попытаться обработать запросы. Ваш демон должен всегда обеспечивать разумный ответ (а не ошибка) при обработке запросов.
Зарегистрируйте сокеты и дескрипторы файлов, используемые Вашим демоном в Вашем
launchd
файл списка свойств конфигурации.Если Ваш демон распространяет сокет, регистрацию с
launchd
как часть Вашей инициализации демона. Для реализации в качестве примера процесса регистрации посмотрите SampleD.Во время регистрации получите словарь запуска от
launchd
, извлеките и сохраните его содержание, и затем отбросьте словарь. Доступ к структуре данных, используемой для словаря, является очень медленным, так хранит целый словарь локально и доступ, это часто могло повреждать производительность.Обеспечьте обработчик для ловли
SIGTERM
сигнал.
В дополнение к предыдущему списку следующее является списком вещей, рекомендуется избежать в коде:
Не устанавливайте пользователя или группу ID для Вашего демона. Включайте
UserName
,UID
,GroupName
, илиGID
ключи в списке свойств конфигурации Вашего демона вместо этого.Не устанавливайте рабочий каталог. Включайте
WorkingDirectory
введите список свойств конфигурации своего демона вместо этого.Не вызывать
chroot
изменить корневой каталог. ВключайтеRootDirectory
введите список свойств конфигурации своего демона вместо этого.Не вызывать
setsid
создать новый сеанс.Не закрывайте случайные дескрипторы файлов.
Не изменяться
stdio
указать на/dev/null
. ВключайтеStandardOutPath
илиStandardErrorPath
ключи в файле списка свойств конфигурации Вашего демона вместо этого.Не устанавливайте пределы ресурса с
setrusage
.Не устанавливайте приоритет демона с
setpriority
Несмотря на то, что многие предыдущие способы поведения могут быть стандартными задачами для демонов выполнить, им не рекомендуют при выполнении под launchd
. Причина - это launchd
конфигурирует операционную среду для демонов, которыми она управляет. Изменение этой среды могло вмешаться в нормальное функционирование Вашего демона.
Решение, когда закрыться
Если Вы не ожидаете, что Ваш демон обработает много запросов, Вы могли бы хотеть завершить работу его после предопределенной суммы времени простоя, вместо того, чтобы продолжать работать. Несмотря на то, что правильно написанный демон не использует ресурсов CPU, когда неактивный, это все еще использует память и могло быть разбито на страницы в течение периодов интенсивного использования памяти.
Синхронизация того, когда закрыться, отличается для каждого демона и зависит от нескольких факторов, включая:
Число и частота запросов это получает
Время это берет для запуска демона
Время это берет для закрытия демона
Потребность сохранить информацию состояния
Если Ваш демон не получает частые запросы и может быть запущен и закрыт быстро, Вы могли бы предпочесть завершать работу его, а не ожидать его, чтобы быть разбитыми на страницы к диску. Память разбивки на страницы к диску и впоследствии чтение его назад, подвергаются двум дисковым операциям. Если Вам не нужны данные, хранившие в памяти, Ваш демон может закрыть и избежать шага записи памяти к диску.
Специальные зависимости
В то время как launchd
заботится о зависимостях между демонами, в некоторых случаях, Ваш демон может зависеть от другой функциональности системы, которая не может адресоваться этим способом. В этом разделе описываются многие из этих особых случаев и как обработать их.
Доступность сети
Если Ваш демон зависит от сети, являющейся доступным, это не может быть обработано с зависимостями, потому что сетевые интерфейсы могут прийти и уйти в любое время в OS X. Для решения этой проблемы необходимо использовать сетевую функциональность достижимости или функциональность динамической памяти в платформе Конфигурации системы. Это документируется в Инструкции по Программированию Конфигурации системы и Ссылку Платформы Конфигурации системы. Для получения дополнительной информации о сетевой достижимости, посмотрите Определение Достижимости и быть соединенным в Инструкциях по Программированию Конфигурации системы.
Диск или доступность сервера
Если Ваш демон зависит от доступности смонтированного объема (или локальный или удаленный), можно определить состояние того объема с помощью Дисковой Арбитражной платформы. Это документируется в Дисковую Арбитражную Ссылку Платформы.
Демоны Non-launchd
Если у Вашего демона есть зависимость от не -launchd
демон, необходимо проявить дополнительную заботу, чтобы гарантировать, что демон работает правильно если это не -launchd
когда Ваш демон запускается, демон не запустил. Лучший способ сделать это должно включать цикл во время начала, проверяющее, чтобы видеть если не -launchd
демон работает, и в противном случае спит в течение нескольких секунд прежде, чем проверить снова.
Обязательно установите обработчики для SIGTERM
до этого цикла, чтобы гарантировать, что Вы в состоянии должным образом закрыться, если демон Вы полагаетесь, никогда не становится доступным.
Пользовательское имя для входа в систему
В целом демон не должен заботиться, зарегистрирован ли пользователь, и агенты пользователя должны использоваться для обеспечения функциональности в расчете на пользователя. Однако в некоторых случаях это может быть полезно.
Для определения, какой пользователь зарегистрирован в консоли можно использовать платформу Конфигурации системы, как описано в Технических Вопросах и ответах QA1133.
Расширения ядра
Если Ваш демон требует, чтобы определенное расширение ядра было загружено до выполнения, у Вас есть две опции: загрузите его сами или ожидайте его, чтобы быть загруженными.
Демон может вручную запросить, чтобы было загружено расширение. Чтобы сделать это, работать kextload
с надлежащим использованием параметров exec
или варианты этого. Расширения ядра Набора I/O не должны быть загружены kextload
; Набор I/O загрузит их автоматически, когда они будут необходимы.
Также наш демон может ожидать службы ядра, чтобы быть доступным. Чтобы сделать это, необходимо сначала зарегистрироваться для уведомления изменения службы. Это далее документируется в Ссылку Платформы Набора I/O.
После регистрации для этих уведомлений необходимо проверить, чтобы видеть, доступна ли служба уже. Если служба становится доступной между проверкой доступность и регистрацией для уведомления, путем выполнения этого после регистрации для уведомлений Вы избегаете ожидать навсегда.
Для получения дополнительной информации о службах I/O Kit и соответствии, см. Основные принципы IOKit, Ссылка Платформы Набора I/O (ссылка пространства пользователя) и Ссылка Платформы Ядра (ссылка пространства ядра).
Для получения дополнительной информации
Страницы руководства для launchd
и launchd.plist
два лучших источника для получения информации о launchd
.
Кроме того, можно найти исходного демона, сопровождающего launchd
исходный код (доступный от http://www .macosforge.org/). Этому демону также предоставлены от Библиотеки Разработчика Mac как проект примера кода SampleD.
Техническое примечание Демонов и Агентов предоставляет дополнительную информацию о как launchd
демоны и агенты работают под капотом.
Наконец, много предоставленных Apple демонов поддерживают launchd
. Их файлы списка свойств могут быть найдены в /System/Library/LaunchDaemons
. Некоторые из этих демонов также доступны как открытый исходный код от http://www .opensource.apple.com/или http://www .macosforge.org/.