10.06 系统软件时钟
系统软件时钟的单位是 jiffies,这是时间片轮转的单位。经过多年的发展,现在时钟频率可以设置到 100 / 250(默认)/ 300 / 1000 Hz。
(2025.2.13) Linux 6.13 在 250Hz 与 1000Hz 计时器频率之间的性能对比 近日,社区有讨论将默认始终频率从 250Hz 调整到 1000Hz。
系统软件时钟的单位是 jiffies,这是时间片轮转的单位。经过多年的发展,现在时钟频率可以设置到 100 / 250(默认)/ 300 / 1000 Hz。
(2025.2.13) Linux 6.13 在 250Hz 与 1000Hz 计时器频率之间的性能对比 近日,社区有讨论将默认始终频率从 250Hz 调整到 1000Hz。
进程时间包含:
times
系统调用
#include <sys/times.h>
clock_t times(struct tms *buf);
其中 tms
结构体包含了当前进程和等待的子进程的时间信息。“等待的子进程”含义是:只有调用 wait
或者 waitpid
回收了一个子进程,子进程的时间才会累加到当前进程的 tms_cutime
和 tms_cstime
上。
struct tms {
clock_t tms_utime; /* user time */
clock_t tms_stime; /* system time */
clock_t tms_cutime; /* user time of children */
clock_t tms_cstime; /* system time of children */
};
sysconf
获取的限制,这些限制在进程运行期间保持恒定。获取限制一般使用 _SC
开头的宏作为参数。pathconf
和 fpathconf
获取的限制,这些限制在进程运行期间是可以改变的。获取限制一般使用 _PC
开头的宏作为参数。pid_t
类型的表示上限
在我的 wsl 中来看,pid_t
这个数据类型占用 4 个字节,是一个有符号整数(实际上是 int
),我这里 /proc/sys/kernel/pid_max 显示可用的最大 pid 号为 4194304,即 $2^{22}$。这其实和 PID_MAX_LIMIT
相等,不可能将 pid_max 调整得更大,但是可以小于这个值。在 32 位机器上,这个系统限制最大是 32768,即 $2^{15}$。最大可用的 pid 值比文件中的值小 1,见后文。
参考 https://unix.stackexchange.com/a/162105/ 。
$ sudo sysctl -w kernel.pid_max=4194303 # 改小可以
kernel.pid_max = 4194303
$ sudo sysctl -w kernel.pid_max=4194305 # 改大不行
sysctl: setting key "kernel.pid_max": Invalid argument
$ sudo sysctl -w kernel.pid_max=4194304 # 改回默认值
kernel.pid_max = 4194304
直接向 /proc/sys/kernel/pid_max 里面 echo
也是可以的,只是 sudo
给命令的提权并不会作用于当前 shell 的重定向符号(重定向使用的权限是当前的 shell 的)。这种情况下可以用 ... | sudo tee
,也可以用 sudo bash -c '...'
把 echo
和重定向包在内部。
在 Linux/UNIX 系统编程手册中看到这样的一段代码:
(py310) xxx /data/apue $ file /proc/self/fd/0
/proc/self/fd/0: symbolic link to /dev/pts/2
(py310) xxx /data/apue $ file /proc/self/fd/0 < .
/proc/self/fd/0: symbolic link to /data/apue
这说明目录也是能够被重定向并使用 0 号 fd 打开的,只要程序支持标准输入流不是普通文件就行。
这些信息都是以 /proc/PID 开头的,其中 PID 为进程自己的进程号。用 /proc/self 可以表示进程本身。
在内核 2.4 之后,Linux 增加了线程组概念,正式支持了 POSIX 线程模型。/proc/PID/task/TID 是进程号为 PID 的进程中线程号为 TID 的线程的信息文件夹。
由于 $$
表示当前 shell 的进程号,而一个进程中的主线程号和进程号相同,我们可以用以下方式来访问当前 shell 主线程的文件夹:
(py310) xxx /data/apue $ ls /proc/$$/task/$$
arch_status cgroup cmdline cwd fd io maps mounts oom_adj pagemap root sessionid smaps_rollup statm uid_map
attr children comm environ fdinfo limits mem net oom_score personality sched setgroups stack status wchan
auxv clear_refs cpuset exe gid_map loginuid mountinfo ns oom_score_adj projid_map schedstat smaps stat syscall
uname
是个系统调用,同时也对应于命令 /usr/bin/uname。
进程凭证包括以下内容:
文件系统中每个非目录文件有设置用户/组 ID 位,启动这样的文件会使得有效用户/组 ID 按照文件的所有者来设置。出于安全考虑,在 Linux 中可执行文件的设置用户/组 ID 权限对于 shell 脚本无效。
设计保存的设置用户 ID(保存的设置组 ID 同,为了表述方便略去)是为了让程序的有效用户 ID 能够在实际用户 ID 和保存的设置用户 ID 之间切换。这样程序在不需要使用其他用户(尤其是 root)的权限时可以将有效用户 ID 转回实际用户 ID,需要权限时再转回来。程序启动时,保存的设置用户 ID 从有效用户 ID 复制过来。
文件系统用户/组 ID 管辖和文件系统操作相关的权限问题,是由 Linux 专有的。一般情况下它们和有效用户/组 ID 相同,除非调用了 setfsuid
/ setfsgid
。
在 Linux 上推荐使用的创建临时文件的方法只有 mkstemp
和 tmpfile
。前者是系统调用,用起来更复杂一点,后者是 C 标准库函数。其他的函数多多少少有自己的问题。
tmpfile
不再需要我们提供字符数组来存储文件名,返回的是 FILE*
而不是 fd。此外还在刚创建文件之后就使用了 unlink
来删除文件,这样就只有当前进程可以访问到这个文件了(除非 fork
)。
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main() {
// 创建文件,记得关闭。
FILE *fp;
assert((fp = tmpfile()) != NULL);
// 查询文件路径并打印。
char path[128];
char link_path[128];
int fd = fileno(fp);
assert(fd != -1);
sprintf(link_path, "/proc/self/fd/%d", fd);
assert(readlink(link_path, path, sizeof(path)) != -1);
printf("tmpfile: %s\n", path);
fprintf(fp, "write something\n");
fflush(fp);
// 在这里停顿。由于已经 unlink 了这个文件,文件系统上看不到它。
getchar();
fclose(fp);
}
运行结果:
(py310) xxx /data/apue $ /data/apue/build/apue
tmpfile: /tmp/#943520 (deleted)
/proc/self/cmdline 是一个以 \0
结尾的文件,我尝试过用 fgets
读取,但是失败了;转而使用 fgetc
逐字符读文件。
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main() {
FILE *f = fopen("/proc/self/cmdline", "r");
if (!f) {
perror("fopen");
return 1;
}
int i = 0, j = 0;
int ch;
char buf[128];
while ((ch = fgetc(f)) != EOF) {
if (ch == '\0') {
buf[j] = '\0';
printf("argv[%d]: %s\n", i++, buf);
j = 0;
} else {
buf[j++] = ch;
}
}
fclose(f);
}
例子:
(py310) xxx /data/apue $ /data/apue/build/apue 5 265
argv[0]: /data/apue/build/apue
argv[1]: 5
argv[2]: 265