¿Cómo verificar qué límite se superó? (Proceso terminado debido a ulimit.)

11

Supongamos que el proceso se ejecuta en un entorno limitado:

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

El programa ha finalizado.

Puede haber muchas razones: memoria / tiempo / límite de archivo excedido; simplemente segfault simple; o incluso terminación normal con el código de retorno 0.

¿Cómo verificar cuál fue el motivo de la finalización del programa, sin modificar el programa?

PD Me refiero a "cuando se da binario". ¿Tal vez algún envoltorio (trazado, etc.) podría ayudar?

Grzegorz Wierzowiecki
fuente

Respuestas:

6

Hablando en general, no creo que puedas desafortunadamente. (Algunos sistemas operativos pueden proporcionarlo, pero no conozco los que sé que lo respaldan).

Documento de referencia para límites de recursos: getrlimitde POSIX 2008.

Tomemos, por ejemplo, el límite de la CPU RLIMIT_CPU.

  • Si el proceso excede el límite flexible, se envía un SIGXCPU
  • Si el proceso excede el límite estricto, se obtiene un claro SIGKILL

Si puede wait()en su programa, podría decir si fue asesinado por SIGXCPU. Pero no se podía diferenciar un SIGKILLdespacho por incumplimiento del límite estricto de una vieja matanza desde afuera. Además, si el programa maneja el XCPU, ni siquiera lo verá desde afuera.

Lo mismo para RLIMIT_FSIZE. Se puede ver la SIGXFSZdel wait()estado si el programa no manejarlo. Pero una vez que se excede el límite de tamaño de archivo, lo único que sucede es que más E / S que intente probar ese límite nuevamente simplemente recibirán EFBIG, esto será manejado (o no, desafortunadamente) por el programa internamente. Si el programa maneja SIGXFSZ, igual que el anterior, no lo sabrá.

RLIMIT_NOFILE? Bueno, ni siquiera recibes una señal. openy amigos acaban de regresar EMFILEal programa. No se molesta de otra manera, por lo que fallará (o no) de cualquier manera que se codificó para fallar en esa situación.

RLIMIT_STACK? Muy bien SIGSEGV, no se puede distinguir de la puntuación de otras razones para obtener uno. (Sin embargo, sabrá que eso fue lo que mató el proceso, por el waitestado).

RLIMIT_ASy RLIMIT_DATAsolo se producirá malloc()y algunos otros comenzarán a fallar (o recibirán SIGSEGVsi se alcanza el límite AS al intentar extender la pila en Linux). A menos que el programa esté muy bien escrito, probablemente fallará de manera bastante aleatoria en ese punto.

En resumen, en general, las fallas no son visiblemente diferentes de otras razones de muerte del proceso, por lo que no puede estar seguro o puede manejarse completamente desde el programa, en cuyo caso decide si / cuándo / cómo procede, no usted desde fuera.

Hasta donde sé, lo mejor que puede hacer es escribir un código que bifurca su programa, lo espera y:

  • verifique el estado de salida para detectar SIGXCPUy SIGXFSZ(AFAIK, esas señales solo serán generadas por el sistema operativo para problemas de límite de recursos). Dependiendo de sus necesidades exactas, podría suponer eso SIGKILLy SIGSEGVtambién estar relacionado con los límites de recursos, pero eso es un poco exagerado.
  • mire lo que puede obtener de getrusage(RUSAGE_CHILDREN,...)su implementación para obtener una pista sobre los otros.

Es posible que existan recursos específicos del sistema operativo para ayudar aquí (posiblemente cosas como ptraceen Linux o Solaris dtrace), o posiblemente técnicas de tipo depurador, pero eso estará aún más vinculado a su implementación específica.


(Espero que alguien más responda con algo mágico que desconozco por completo).

Estera
fuente
Okay. ¿Qué pasa con esos tres: (Mem) que excede el límite de memoria, (Tiempo) límite de tiempo, (Err) otro error? Sé cómo hacer wrapper, mallocpero desafortunadamente no resuelve el problema de memoria en general, porque en general se trata de una llamada al sistema brk(¿estoy en lo cierto?).
Grzegorz Wierzowiecki
1
Envolver malloc no ayudará si no controlas el programa. Si usted está hablando de cortes como LD_PRELOADing que de límite para su "no modificar el proceso de" restricción, y va a ayudar un poco, pero no realmente - malloc, brk, sbrky mmapfallará con ENOMEM, exactamente como si realmente estuviera en una situación de memoria baja (pero muy por debajo de los límites de memoria). El límite de tiempo es RLIMIT_CPU, no sé de un límite de tiempo de reloj de pared.
Mat
Gracias por asegurarme acerca de brk. Como veo, el requisito 'el programa no maneja las señales X, Y, Z ...' resolverá los problemas de SIGXCPU, SIGXFSZ, SIGSEGV, gracias a waitpid (si estoy equivocado, corrígeme).
Grzegorz Wierzowiecki
1
SIGSEGV se puede generar en situaciones que no son infracciones del límite de recursos (la desreferencia de puntero nulo es lo más común que lo genera): no puede estar seguro de que sea un golpe ulimit lo que lo causa.
Mat
Gracias por asegurarme acerca de brk. Como veo, el requisito "el programa no maneja las señales X, Y, Z ..." resolverá los problemas de SIGXCPU, SIGXFSZ, SIGSEGV, gracias a waitpid. Estoy en lo cierto?
Grzegorz Wierzowiecki