Como verificar, qual limite foi excedido? (Processo finalizado por causa de ulimit.)

11

Vamos supor que o processo seja executado no ambiente ulimited:

(
ulimit  ... -v ... -t ... -x 0 ...
./program
)

O programa está terminado.

Pode haver muitas razões: limite de memória / tempo / arquivo excedido; apenas segfault simples; ou mesmo terminação normal com o código de retorno 0.

Como verificar qual foi o motivo da finalização do programa, sem modificar o programa?

P.S. Quero dizer "quando o binário é dado". Talvez algum wrapper (ptrace-ing etc) possa ajudar?

    
por Grzegorz Wierzowiecki 25.10.2011 / 17:03

2 respostas

6

De um modo geral, não acho que você possa, infelizmente. (Alguns sistemas operacionais podem fornecer isso, mas não estou ciente dos que eu conheço apoiando isso.)

Documento de referência para limites de recursos: getrlimit do POSIX 2008.

Por exemplo, o limite da CPU RLIMIT_CPU .

  • Se o processo exceder o limite flexível, será enviado um SIGXCPU
  • Se o processo exceder o limite máximo, ele receberá uma SIGKILL

Se você puder wait() em seu programa, poderá dizer se ele foi eliminado por SIGXCPU . Mas você não poderia diferenciar um SIGKILL enviado para a violação do limite rígido de uma simples matança de fora. Além disso, se o programa lida com o XCPU , você nem verá isso de fora.

Mesma coisa para RLIMIT_FSIZE . Você pode ver o SIGXFSZ do status wait() se o programa não lidar com isso. Mas quando o limite de tamanho do arquivo for excedido, a única coisa que acontece é que mais E / S que tentam testar esse limite novamente receberão simplesmente EFBIG - isso será tratado (ou não, infelizmente) pelo programa internamente. Se o programa lida com SIGXFSZ , o mesmo que acima, você não saberá sobre isso.

RLIMIT_NOFILE ? Bem, você nem recebe um sinal. open e amigos retornam EMFILE para o programa. Não é de outro modo incomodado, por isso falhará (ou não) de qualquer forma que tenha sido codificado para falhar nessa situação.

RLIMIT_STACK ? O bom e velho SIGSEGV , não pode ser distinguido da pontuação de outros motivos para receber um. (Você saberá que foi isso que matou o processo, a partir do status wait .)

RLIMIT_AS e RLIMIT_DATA apenas farão malloc() e alguns outros começarão a falhar (ou receber SIGSEGV se o limite AS for atingido ao tentar estender a pilha no Linux). A menos que o programa esteja muito bem escrito, ele provavelmente falhará de forma bastante aleatória nesse ponto.

Portanto, em geral, as falhas não são visivelmente diferentes de outras causas de morte do processo, portanto você não pode ter certeza, ou pode ser tratado inteiramente a partir do programa, caso decida se / quando / como ele continua. não você do lado de fora.

O melhor que você pode fazer, tanto quanto eu sei, é escrever um pouco de código que garfos do seu programa, espera nele e:

  • verifique o status de saída para detectar SIGXCPU e SIGXFSZ (AFAIK, esses sinais serão gerados apenas pelo sistema operacional para problemas de limite de recursos). Dependendo de suas necessidades exatas, você pode assumir que SIGKILL e SIGSEGV também estavam relacionados a limites de recursos, mas isso é um pouco exagerado.
  • veja o que você pode obter de getrusage(RUSAGE_CHILDREN,...) em sua implementação para obter uma dica sobre os outros.

Recursos específicos do SO podem existir para ajudar aqui (possivelmente coisas como ptrace no Linux ou Solaris dtrace ) ou, possivelmente, técnicas do tipo depurador, mas isso será ainda mais vinculado à sua implementação específica.

(Espero que alguém mais responda com alguma coisa mágica da qual eu esteja completamente inconsciente.)

    
por 26.10.2011 / 21:07
3

Atualmente, estou trabalhando no mesmo problema. Eu pude ter uma solução parcial para isso. Eu usei o audit susbsystem. Você pode acompanhar o trabalho em [1].

[1] link

    
por 12.11.2013 / 14:00