Generally speaking, I don't think you can unfortunately. (Some operating systems might provide for it, but I'm not aware of the ones I know supporting this.)
Reference doc for resource limits: getrlimit from POSIX 2008.
Take for example the CPU limit RLIMIT_CPU.
- If the process exceeds the soft limit, it gets sent a
SIGXCPU
- If the process exceeds the hard limit, it gets a plain
SIGKILL
If you can wait() on your program, you could tell if it was killed by SIGXCPU. But you could not differentiate a SIGKILL dispatched for breach of the hard limit from a plain old kill from outside. What's more, if the program handles the XCPU, you won't even see that from outside.
Same thing for RLIMIT_FSIZE. You can see the SIGXFSZ from the wait() status if the program doesn't handle it. But once the file size limit is exceeded, the only thing that happens is that further I/O that attempts to test that limit again will simply receive EFBIG - this will be handled (or not, unfortunately) by the program internally. If the program handles SIGXFSZ, same as above - you won't know about it.
RLIMIT_NOFILE? Well, you don't even get a signal. open and friends just return EMFILE to the program. It's not otherwise bothered, so it will fail (or not) in whichever way it was coded to fail in that situation.
RLIMIT_STACK? Good old SIGSEGV, can't be distinguished from the score of other reasons to get delivered one. (You will know that that was what killed the process though, from the wait status.)
RLIMIT_AS and RLIMIT_DATA will just make malloc() and a few others start to fail (or receive SIGSEGV if the AS limit is hit while trying to extend the stack on Linux). Unless the program is very well written, it will probably fail fairly randomly at that point.
So in short, generally, the failures are either not visibly different from other process death reasons, so you can't be sure, or can be handled entirely from the program in which case it decides if/when/how it proceeds, not you from the outside.
The best you can do as far as I know is write a bit of code that forks of your program, waits on it, and:
- check the exit status to detect
SIGXCPU and SIGXFSZ (AFAIK, those signals will only be generated by the OS for resource limit problems). Depending on your exact needs, you could assume that SIGKILL and SIGSEGV were also related to resource limits, but that's a bit of a stretch.
- look at what you can get out of
getrusage(RUSAGE_CHILDREN,...) on your implementation to get a hint about the other ones.
OS-specific facilities might exist to help out here (possibly things like ptrace on Linux, or Solaris dtrace), or possibly debugger-type techniques, but that's going to be even more tied to your specific implementation.
(I'm hoping someone else will answer with some magic thing I'm completely unaware of.)