Outra coisa que devemos aprender com o MacOS é que shell script é uma coisa do mal. O Shell é rápido e shell é lento. Rápido para programar e modificar, mas lento demais para executar. O SysVinit é lento pelas mesmas razões já que é modelado em torno de shell script. Independente de ser o bash ou outro shell, no fim essa abordagem é lenta de qualquer modo.
Os scripts podem fazer um sem número de chamadas. Por exemplo, meu sistema atual é baseado em /etc/init.d. Ele faz 77 chamadas para grep, 92 chamadas para AWK, 23 chamadas para cut e 74 chamadas para SED. Para cada uma destas chamadas um processo é instanciado, várias bibliotecas são carregadas, várias coisas como i18n são configuradas e executadas.
Além disto, scripts são frágeis, e mudam de comportamento de acordo com o ambiente e suas variáveis. Algumas dessas coisas são difíceis de controlar. Então, que tal se nos livrarmos de shell script na inicialização! Quando percebemos que a maior parte do que esses scripts fazem é apenas uma bobagem chata.
A maior parte do serviço de scripts são coisas triviais relacionadas com configuração, que poderiam ser reescritas em C, mantidas em executáveis separados, movidas para um daemon ou simplesmente incluídas no próprio sistema init. É óbvio que não podemos nos livrar de scripts do dia para a noite. Reescrever todas essas rotinas em C, depurar e testar pode levar tempo.
Mantendo o rastreamento de processos
A parte central de um sistema que inicializa e mantém serviços é evitar que ele aja como uma babá: na verdade ele deve assistir os serviços. Assim, deve reiniciá-los se eles falharem, neste caso deve coletar informações sobre a falha, administrar despejos gerados por essas falhas, gerar informações em registro de log ou dados para auditoria.
Além disto, o sistema deve ser capaz de encerrar um serviço completamente. Isso pode soar como uma coisa fácil, mas acredite isso é muito difícil de implementar. Tradicionalmente, um processo Unix pode criar um ou mais forks durante sua execução.
Deste modo, é muito fácil perder o controle entre o processo filho, seu pai e seu avô. Um exemplo fácil é quando Apache utiliza CGI. Esses processos podem se perder facilmente quando Apache é encerrado de modo abrupto.
Então, como manter o rastreamento desses processos que não podem escapar da supervisão de uma babá? Diferentes pessoas vieram com diferentes soluções. Sem entrar em detalhes vimos soluções como ptrace ou conectores netlink (baseados em fork() ou exit()) que são muito criticados. O que nós podemos fazer realmente a respeito disto?
Bem, desde que o kernel incorporou grupos de controle (cgroup) podemos criar uma hierarquia com os processos. Essa hierarquia é exposta diretamente para um sistema de arquivos virtual facilmente acessível. Cgroup são basicamente nomes de diretórios em um sistema de arquivos.
Assim, se um processo do grupo fizer um fork(), seu filho se torna membro do grupo automaticamente. Normalmente um processo não pode escapar do grupo (há exceções). A ideia original de Cgroups era funcionar como um contenedor: certos subsistemas do kernel podem forçar os limites de recursos de certos grupos.
Tradicionalmente a limitação de recursos (CPU e memória) são implementados via setrlimit() em uma base por processo. Cgroup por outro lado pode forçar limites para um grupo de processos. Você poderia utilizar Cgroups para limitar a memória de Apache e seus processos filhos.
Então, aquele CGI desgarrado está limitado por um certo controle. O controle de processos por Cgroup pode ser visualizado em /proc/$PID/cgroup. Afinal, Cgroups é uma ótima opção para manter o rastreamento de processos para finalidades de tutela por uma babá.
Controlando o Ambiente de Execução de Processos
Buscamos uma babá que deve ser boa em controlar a execução, o término e as falhas dos processos. Além disto, ela deve cuidar do ambiente de execução e da segurança desse ambiente de modo geral.
Na prática, isso significa configurar coisas óbvias como os parâmetros e limites para o processo (setrlimit()), limitar recursos, bloquear usuários/grupos e outras tarefas básicas. O kernel
Linux dá a usuários e administradores um monte de controles sobre processos (apesar disto, poucos são utilizados corretamente).
Para cada processo você pode configurar controles sobre CPU ou agendamento de entrada/saída, afinidade de CPU e variáveis de ambiente cgroup, seus limites e muito mais.
Finalmente, o sistema de Logs é uma parte importante da execução de serviços: no mundo ideal cada tarefa deveria gerar um log. Um bom sistema init deve fornecer meios de registrar logs sobre os daemons que gerencia. Esse sistema de logs associado ao init poderia ser um bom substituto para syslog.