if (!error) {
tp->tv_sec = 0;
tp->tv_nsec = ((NSEC_PER_SEC + HZ - 1) / HZ);
if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) {
tp->tv_nsec = 1;
}
}
return error;
}
该函数的执行逻辑分成两个部分,一部分是参数校验,一部分是返回精度。参数校验需要检查的包括:
(a)clock id中的高29个bit包含了pid,获取pid的代码如下:
#define CPUCLOCK_PID(clock) ((pid_t) ~((clock) >> 3))
从代码可知,实际上并不是将pid放到高29个bit,而是将反码保存到了高29个bit。为何保存反码?这样做为了确保clock id是一个负数(MSB是1),还记得clockid_to_kclock的实现吗?要获取该clock id的精度,要确保该pid的task存在
(b)如果该clock id是一个进程相关的(调用clock_getcpuclockid获得),那么这个进程id应该是一个实实在在的进程id。在linux kernel中,pid实际上是线程ID,POSIX标准的进程ID,也就是PID在内核中被成为线程组ID。因此,所谓一个“实实在在的进程id”就是说该线程的id(pid)和tgid一样,该pid标识的线程是线程组leader。当然,就是获取精度而已,实际上要求并不要那么严格,也许该pid标识的线程leader会退出,因此实际上要求该pid标识的task有thread group leader就OK了。(这里有可能理解有误,TODO)
(c)如果该clock id是一个线程相关的(调用pthread_getcpuclockid获得),那么调用者必须和该线程(clock id中指明的那个线程)属于一个进程(线程组)。
返回精度部分的代码逻辑很简单,对于PROF和VIRT类型的CPU-time clock,其精度是tick,对于SCHED类型,精度是1ns。
(2)获取当前时间值
同样的,首先需要从clock id中获取pid的值,然后根据pid的值获取对应的task sturct,如果pid等于0,那么不需要费劲去寻找。得到task struct之后,可以调用posix_cpu_clock_get_task函数获取时间值:
static int posix_cpu_clock_get_task(struct task_struct *tsk, const clockid_t which_clock,
struct timespec *tp)
{
int err = -EINVAL;
unsigned long long rtn;
if (CPUCLOCK_PERTHREAD(which_clock)) {---per 线程的cpu clock
if (same_thread_group(tsk, current))---必须和调用者是同一个线程组,也就是同一个进程
err = cpu_clock_sample(which_clock, tsk, &rtn);
} else {
if (tsk == current || thread_group_leader(tsk))---进程的cpu clock
err = cpu_clock_sample_group(which_clock, tsk, &rtn);
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-77921-5.html
坐等消息
关键是