IOError: [Errno 10] No child processes
Às vezes eu escrevo programas. Entre esse 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:
- Mudar pro diretório raiz ("/").
- Realizar um fork().
- Finalizar o processo pai, ficando somente o filho, criado no fork().
- Realizar outro fork().
- 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 essa:
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()
Esse é parte de um método, mas poderia ser uma função. A idéia é 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 programs 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. Várias fontes na Internet, principalmente no Launchpad, o sistema de bug report do Ubuntu, várias 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 que o daemon não sairia com o erro acima.
Happy hacking :-)
Acessos: 7160