Dev (Back & Front)ARTIGO

IOError: [Errno 10] No child processes

Daemons são os programas que rodam em background no sistema, não precisando de um terminal (console) anexado.

Às vezes eu escrevo programas. Entre esses programas, alguns são daemons. Além da confusão com demônios, o que são daemons?

Daemons são os programas que rodam em background no sistema, não precisando de um terminal (console) anexado. E qualquer tipo de programa pode ser um daemon, pra qualquer finalidade.

Em geral daemons seguem as seguintes regras pra se tornarem daemons:

  1. Mudar pro diretório raiz (“/”).
  2. Realizar um fork().
  3. Finalizar o processo pai, ficando somente o filho, criado no fork().
  4. Realizar outro fork().
  5. Finalizar o primeiro processo filho, deixando somente o segundo, criado no segundo fork().

O segundo fork() é feito para garantir que o programa, através do segundo processo filho, seja “herdado” pelo processo init do sistema.

Em Python, sempre incluo uma função como esta:

def Daemonize(self):
      """
      Fork to became a daemon.
      """

      if not self.isDaemon:
         try:
            self.run()
         except KeyboardInterrupt:
            sys.exit(0)
         return

      os.chdir("/")
      pid = os.fork()

      if (pid > 0):
         sys.exit(os.EX_OK)
      else:
         pid = os.fork()

         if (pid > 0):
            sys.exit(os.EX_OK)
         else:
            self.run()

Essa é parte de um método, mas poderia ser uma função. A ideia é usar o getopt() para verificar as opções passadas e entrar no modo de daemon ou não, dependendo da opção passada, que modifica a variável booleana self.isDaemon.

Mas um dos meus programas começou a apresentar o seguinte erro:

helio@goosfraba:~$ connect_TSP.py ccn
IP already setup... skipping root access
Running as daemon
daemonized...
close failed in file object destructor:
IOError: [Errno 10] No child processes
Error in sys.excepthook:
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/apport_python_hook.py", line 66, in apport_excepthook
    from apport.fileutils import likely_packaged, get_recent_crashes
RuntimeError: sys.meta_path must be a list of import hooks

Original exception was:
IOError: [Errno 10] No child processes

Inicialmente, achei que era problema no “apport” com meu programa, que usa python-expect. Mesmo com tal erro, o programa funcionava perfeitamente em background, como daemon. Em várias fontes na Internet, principalmente no Launchpad, o sistema de bug report do Ubuntu, muitas pessoas reclamavam de tal erro como sendo problema do apport.

Após muito buscar a origem do problema, não no Ubuntu, mas no Python, descobri que alguns file descriptors estavam causando esse erro, por continuarem abertos quando ocorria o fork(). Corrigi da seguinte forma:

def Daemonize(self):
      """
      Fork to became a daemon.
      """

      if not self.isDaemon:
         try:
            self.run()
         except KeyboardInterrupt:
            sys.exit(0)
         return

      os.chdir("/")
      pid = os.fork()

      if (pid > 0):
         os.close(sys.stdin.fileno())
         os.close(sys.stout.fileno())
         os.close(sys.stderr.fileno())
         sys.exit(os.EX_OK)
      else:
         pid = os.fork()

         if (pid > 0):
            os.close(sys.stdin.fileno())
            os.close(sys.stdout.fileno())
            os.close(sys.stderr.fileno())
            sys.exit(os.EX_OK)
         else:
            self.run()

Então bastou fechar os descritores de arquivo do STDIN, STDOU e STDERR pra ter certeza de que o daemon não sairia com o erro acima.

Happy hacking 🙂

trabalha em telecomunicações na Ericsson. Formado em engenharia elétrica pela UFSC e com MBA em gestão estratégica de TI pela FGV, trilha o mundo do software livre desde 1997, passando por Linux em geral, Debian e FreeBSD. Atualmente, se interessa mais pelo lado de startups do software livre e menos por código, mas sempre dá uma escapadinha para programar em Python.

Ver perfil