How can a process inquire, when it was started?

2019-08-11 11:20发布

问题:

Is there a call, that can be used to ask the OS, when the current process started?

Of course, one could simply call gettimeofday() at start-up and refer to that once-recorded value through the life of the process, but is there another option?

Obviously, the OS keeps the record for each process (one can see it in the output of ps, for example). Can it be queried by the process itself (using C)?

An ideal solution would, of course, be cross-platform, but something (Free)BSD-specific is fine too. Thanks!

Update: I've come up with a BSD-specific implementation, that uses sysctl(3) to obtain the kern_proc structure of the current process and finds the ki_start field in there. If nobody suggests anything better in a few days, I'll post my own function here for posterity...

回答1:

Not sure standard this is for BSDs other than FreeBSD (only tested on FreeBSD 10.0, amd64). Took a lot of picking apart the source code ps, and other than just using a system library, it doing the same thing that Mikhail T.'s solution is doing. Though despite, the code being pretty rough (sort got caught up in figuring out how to do this 'properly' because 'it really shouldn't be that hard, right?', and 2+ hours later, this is what I have. Works wonderfully.

Remember to compile using the -lkvm flag to pull in libkvm (Kernel Data Library). The kinfo_proc is detailed in /usr/include/sys/user.h and has ever bit of information you ever wanted to know about a process. The example code below uses the current process, but it is just pulling the information based on PID. I've got in my scrap pieces of code what you need to pull out the process's environment variables and other stuff, just tell me if you want.

#include <fcntl.h>
#include <kvm.h>
#include <sys/sysctl.h>
#include <sys/user.h>


#include <unistd.h>
#include <stdio.h>
#include <time.h>

int main(int argc,char** args) {
    kvm_t* kd;

    // Get a handle to libkvm interface
    kd = kvm_open(NULL, "/dev/null", NULL, O_RDONLY, "error: ");

    pid_t pid;
    pid = getpid();

    struct kinfo_proc * kp;
    int p_count;

    // Get the kinfo_proc for this process by its pid
    kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &p_count);

    printf("got %i kinfo_proc for pid %i\n", p_count, pid);

    time_t proc_start_time;
    proc_start_time = kp->ki_start.tv_sec;
    kvm_close(kd);

    printf("Process started at %s\n", ctime(&proc_start_time));
    return 0;
}

edit

Full source code for example including FreeBSD, NetBSD and Mac OS X (OpenBSD when I get a chance) can be found here: https://github.com/dnabre/misc/tree/master/proc_info



回答2:

You can look into the /proc/[process-id] folder.. Do a fstat() on it to get more info..



回答3:

Ok, here is my own function -- it works on FreeBSD and is very likely to work on Open, Net, and DragonFly BSDs. Probably, on MacOS too. Feel free to take and adjust to taste -- the function caches the value in a static variable, which means, if your process forks after the function was called once, the child will have the parent's value. Also, I discard the microseconds part of timeval, but you may need it.

static void
getstarttime(struct timeval *ptv)
{
    static time_t   start; /* We cache this value */
    int             mib[4];
    size_t          len;
    struct kinfo_proc   kp;

    ptv->tv_usec = 0;   /* Not using microseconds at all */

    if (start != 0) {
        ptv->tv_sec = start;
        return;
    }
    ptv->tv_sec = 0;

    len = 4;
    if (sysctlnametomib("kern.proc.pid", mib, &len) != 0) {
        warn("Unable to obtain script start-time: %s",
            "sysctlnametomib");
        return;
    }
    mib[3] = getpid();
    len = sizeof(kp);
    if (sysctl(mib, 4, &kp, &len, NULL, 0) != 0) {
        warn("Unable to obtain script start-time: %s",
            "sysctl");
        return;
    }

    start = ptv->tv_sec = kp.ki_start.tv_sec;
}