记录一些场面的命令或代码,不然老是要百度。
#include
/* 静态初始化 */
static DEFINE_SPINLOCK(g_spin_lock);
/* 嵌入到结构体中 */
spinlock_t xxx_lock;
spin_lock_init(&xxx_lock);
// 没有反初始化函数
/* 只是关掉内核抢占,不会关中断 */
spin_lock(&xxx_lock);
spin_unlock(&xxx_lock);
/* 关内核抢占, 关本地中断 -> 所以任何情况下调用都是安全的,但是速度比 spin_lock慢一点点 */
spin_lock_irq(&xxx_lock);
spin_unlock_irq(&xxx_lock);
/* 上面的保存flags版本,建议用这个. */
spin_lock_irqsave(&xxx_lock);
spin_unlock_irqrestore(&xxx_lock);
#include
static DEFINE_MUTEX(g_mutex_lock);
struct mutex mutex;
mutex_init(&mutex);
mutex_destroy(&mutex);
mutex_lock(&mutex);
mutex_unlock(&mutex);
mutex_lock_interruptible(&mutex);
mutex_unlock(&mutex);
mutex_lock_killable(&mutex);
mutex_unlock(&mutex);
没啥好说的,顾名思义。
用于在串口卡住的时候,进行调试。(比如 运行某个应用卡住了)
依赖于:
CONFIG_KGDB=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
CONFIG_MAGIC_SYSRQ_SERIAL=y
这里以 mobaxterm
为例:
右键 -> special Command -> Break,然后输入 w
。打印出阻塞的task
也可以输入 h
查看支持的命令。
如:
root@TinaLinux:/# [ 1042.966141] sysrq: Show Blocked State
[ 1042.970259] task PC stack pid father
[ 1042.976134] usb-hardware-sc D 0 1054 2 0x00000000
[ 1042.982287] Backtrace:
[ 1042.985037] [] (__schedule) from [] (schedule+0xdc/0x110)
[ 1042.993039] r10:c3daa2dc r9:c7505ccc r8:c04efc20 r7:c0c02d00 r6:c3de0000 r5:c3de0000
[ 1043.001817] r4:c6d81600
[ 1043.004658] [] (schedule) from [] (schedule_timeout+0xc0/0x100)
[ 1043.013245] r5:00000000 r4:0001225d
[ 1043.017252] [] (schedule_timeout) from [] (schedule_timeout_uninterruptible+0x30/0x34)
[ 1043.028081] r7:c0d9def8 r6:c0d9def0 r5:c0d9def8 r4:c0c4b238
[ 1043.034428] [] (schedule_timeout_uninterruptible) from [] (msleep+0x28/0x30)
[ 1043.044282] [] (msleep) from [] (usb_hardware_scan_thread+0x34/0x68)
[ 1043.053358] [] (usb_hardware_scan_thread) from [] (kthread+0x12c/0x140)
[ 1043.062719] r7:c0d9def8 r6:c3daa540 r5:c3de0000 r4:c3daa2c0
[ 1043.069064] [] (kthread) from [] (ret_from_fork+0x14/0x2c)
[ 1043.077161] Exception stack(0xc3de1fb0 to 0xc3de1ff8)
[ 1043.082820] 1fa0: 00000000 00000000 00000000 00000000
[ 1043.091994] 1fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 1043.101162] 1fe0: 00000000 00000000 00000000 00000000 00000013 00000000
[ 1043.108576] r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c013d09c
[ 1043.117357] r4:c3daa540 r3:00000000
[ 1394.817053] sysrq: HELP : loglevel(0-9) reboot(b) crash(c) terminate-all-tasks(e) memory-full-oom-kill(f) kill-all-tasks(i) thaw-filesystems(j) sak(k) show-backtrace-all-active-cpus(l) show-memory-usage(m) nice-all-RT-tasks(n) poweroff(o) show-registers(p) show-all-timers(q) unraw(r) sync(s) show-task-states(t) unmount(u) show-blocked-tasks(w) dump-ftrace-buffer(z)
// 头文库
#include
// 返回值 struct task_struct *k
#define kthread_run(threadfn, data, namefmt, ...)
void kthread_bind(struct task_struct *k, unsigned int cpu);
void kthread_bind_mask(struct task_struct *k, const struct cpumask *mask);
// 注意: stop会阻塞等到线程退出才会返回, 所以线程需要 时不时要调用 kthread_should_stop 来判断是否需要退出
int kthread_stop(struct task_struct *k);
bool kthread_should_stop(void);
// 设置线程优先级
#include
struct sched_param parm;
parm.sched_priority = MAX_RT_PRIO - 10;
sched_setscheduler(task, SCHED_FIFO, &parm);
主要是用来等待一些条件的满足。
使用:
#include
#include
wait_queue_head_t wq;
init_waitqueue_head(&wq);
// 没有反初始化函数
wait_event_interruptible(wq, condition);
wait_event_interruptible_timeout(wq, condition, msecs_to_jiffies(ms))
wake_up_interruptible(&wq);
wake_up_interruptible_nr(&wq);
注意:
wait_event_*
这些是一个宏,wq
不需要 &wq
, 宏内部会自动添加&
> 0
:条件变成真,返回值是剩余时间(至少是1)= 0
:超时时,条件还是假< 0
:出错(被中断唤醒)#include
struct sk_buff_head queue; /* head */
struct sk_buff *skb; /* entry */
skb_queue_head_init(&queue);
/* ---------------- 添加skb, 假设数据源: src, len --------------- */
struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC); /* 看情况, 也可以是 GFP_KERNEL */
/* skb_put 用于拓展skb的数据区,并返回拓展出的Buffer的首地址, 在后头添加数据 */
memcpy(skb_put(skb, len), src, len);
/* 在前头添加数据 */
memcpy(skb_push(skb, len), src, len);
/* sk_buff_head 自带一个spinlock,一般不需要自己额外添加lock */
skb_queue_tail(&queue, skb);
skb_queue_head(&queue, skb);
/* ---------------- 获取skb, 假设数据源: src, len --------------- */
while (1) {
if (skb_queue_empty(&ser->queue)) {
...
continue;
}
struct sk_buff *skb = skb_dequeue(&queue);
data = skb->data;
len = sbk->len;
// 处理数据
...
kfree_skb(skb);
}
用于ID分配,每个ID可以绑定一个void *
.
#include
struct idr xxx;
idr_init(&xxx);
idr_destroy(&xxx);
/* 从 [start, end) 范围内分配一个id, */
idr_alloc(&xxx, priv, start, start + 1, GFP_KERNEL);
/* 通过id找到对应的priv指针 */
priv = idr_find(&xxx, id);
idr_remove(&xxx, id);
/* 后2个成员一个是void*, 一个是id */
idr_for_each_entry(&xxx, entry, id) {
...
}
如果仅需要分配ID,不需要绑定void *
#include
static DEFINE_IDA(xxx);
struct ida xxx;
ida_init(&xxx);
ida_simple_get(&xxx, min, RPMSG_DEV_MAX, GFP_KERNEL);
ida_simple_remove(&xxx, id); /* 释放指定ID */
ida_destroy(&xxx); /* 释放所有ID */
#include
# 静态属性初始化
static struct class *xxx_class;
static ssize_t xxx_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
...
}
static ssize_t name_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
...
}
DEVICE_ATTR_RW(xxx) /* 会定义结构体 struct device_attribute dev_attr_xxx */
static struct attribute *attrs[] = {
&dev_attr_xxx.attr,
...
};
/* 现在内核推荐使用 attr group 使用定义属性 */
static const struct attribute_group devgroup = {
.attrs = attrs
};
static const struct attribute_group *devgroups[] = {
&devgroup,
NULL
};
/* 静态定义class */
struct class xxx_class = {
.name = "xxxx",
.dev_groups = devgroups,
};
# 动态初始化
xxx_class = class_create(THIS_MODULE, "xxx");
class_destroy(xxx_class);
dev->class = xxx_class;
device_create_file(&dev, &dev_attr_xxx); /* 会在 dev->class下 创建对应目录 */
完成量(在我看来就是是个二值信号量)
#include
struct completion complete;
init_completion(&complete);
/* 如果调用 complete后, 还需要再使用complete,需要重新初始化 */
reinit_completion(¬ify->complete);
complete(&complete);
wait_for_completion_timeout(&complete, msecs_to_jiffies(500));
延迟队列,定期执行某个函数。
注意不太准,CPU负载比较重的时候不一定会及时执行。
#include
struct delayed_work work;
void work_func(struct work_struct *work)
{
/* delay_work是基于work封装的 */
struct delayed_work *p = to_delayed_work(work);
...
}
/* 初始化 */
INIT_DELAYED_WORK(&work, work_func);
/* 启动delay_work */
schedule_delayed_work(&work, DELAY_TIME);
/* 取消delay_work, free之前一定要调用这个,避免 use-after-free */
cancel_delayed_work(&work);
cancel_delayed_work_sync(&work);
调用dump_stack()
函数即可,不需要包含头文件。
du -h --max-depth=1 .
内核配置:
CONFIG_ELF_CORE=y
CONFIG_ELFCORE=y
CONFIG_COREDUMP=y
CONFIG_BINFMT_ELF=y
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y /* 可不选 */
配置coredump
文件路径:
ulimit -c unlimited /* 依赖于根文件系统配置 */
echo /tmp/%e.%t.%p.%s.core > /proc/sys/kernel/core_pattern
# 支持格式如下:
# %p: pis
# %P: 全局pid(初始化PID namespace)
# %i: tid
# %I: 全局tid(初始化PID namespace)
# %u: uid
# %g: gid
# %d: dump mode, 匹配PR_SET_DUMPABLE和/proc/sys/fs/suid_dumpable
# %s: 信号数
# %t: unix 时间
# %h: hostname
# %e: 可执行程序名(可能会缩短)
# %f: 可执行程序名
# %E: 可执行程序路径
# %c: core file的最大size, RLIMIT_CORE
编译应用时加上:
-fsanitize=leak
-fsanitize=address
-fno-omit-frame-pointer
链接时加上:-lasan
使用 ar
命令
一般使用:
xxx-ar rvs libname obj1 obj2 ... objn
若要生成的lib
仅仅只是中间文件,后续会合并成一个更大的lib
,可使用 thin-archive
生成一个轻量静态库(不保存实际的目标文件,仅仅保存执行目标文件的指针)来加上编译过程.
可在生成静态库时追加T
选项来生成轻量lib
最终可通过以下命令生成完整的lib
for lib in `find -name *.a`;
do
xxx-ar -t $lib | xargs ar rvs $lib.new && mv $lib.new $lib
done
note:这啥GNU的ar,与BSP冲突;且只记录前15个字符
遇到的问题:头文件更新,对应C文件不会重新编译
原因:没有依赖对应头文件
解决办法:可使用-MD
或 -MMD
来生产依赖文件
使用 -MD / -MMD
后,可以生成一个 xxx.d
文件,里面会列出所有依赖的文件,格式如下:
ads-path/to/file.o: \
depends file1 \
...
这种格式符合 Makefile
的规则格式,可以直接 include
SOURCES := $(wildcard *.cpp)
OBJECTS := $(patsubst %.cpp,%.o,$(SOURCES))
DEPENDS := $(patsubst %.cpp,%.d,$(SOURCES))
...
-include ($(DEPENDS))
...
-MD
和-MMD
区别:-MD
包含系统头文件如stdio.h
这种,-MMD
不包含
# a - 将所有引用的东西打包到一个包中
# d - 打包之后,如果新创建的包使某些现有包冗余,移除冗余包
git repack -a -d --depth=250 --window=250
git prune-packed # 删除已经在包文件中的额外对象
或:
git gc --aggressive --prune
git prune
# 控制台不休眠
echo N > /sys/module/printk/parameters/console_suspend
# 打印调用时间
echo 1 > /sys/power/pm_print_times
#打印函数调用
echo Y > /sys/module/kernel/parameters/initcall_debug;
# 触发休眠
echo mem > /sys/power/state
# RTC唤醒
echo +10 > /sys/class/rtc/rtc0/wakealarm; # 10s后RTC唤醒
内核默认用的是 SLUB
如果存在SLUB
内存泄露,可以打开下面选项:
CONFIG_SLUB_DEBUG
CONFIG_SLUB_DEBUG_ON
CONFIG_SLUB_STATS
大概思路:
# 可先查看整体大小, 看看SLAB相关的内存是不是一直增加
cat /proc/meminfo
Slab: 32536 kB
SReclaimable: 9724 kB
SUnreclaim: 22812 kB
# 定期查看 是哪个 slab 一直增加, 确定是哪个slab泄露
cat /proc/slabinfo
# name : tunables : slabdata
...
kmalloc-8k 10 11 24576 1 8 : tunables 0 0 0 : slabdata 11 11 0
...
# 以 kmalloc-8k 为例
root@TinaLinux:/# cat /sys/kernel/slab/kmalloc-8k/alloc_calls
1 ubifs_mount+0x10a8/0x1408 age=89307 pid=1083 cpus=0
1 register_framebuffer+0x214/0x2d0 age=89742 pid=1 cpus=0
1 disp_init_lcd+0xb4/0x43c age=89744 pid=1 cpus=0
1 kzalloc+0x14/0x18 age=89807 pid=0 cpus=0
1 sunxi_dump_reg_probe+0x12c/0x17c age=89649 pid=1 cpus=0
2 kmalloc_array.constprop.39+0x2c/0x34 age=89756/89756/89756 pid=1 cpus=1
2 kzalloc.constprop.3+0x20/0x28 age=89514/89514/89514 pid=1 cpus=0
1 netlink_proto_init+0x40/0x148 age=89799 pid=1 cpus=0
root@TinaLinux:/# cat /sys/kernel/slab/kmalloc-8k/free_calls
10 <not-available> age=64244 pid=0 cpus=0
配置:
CONFIG_DEBUG_KMEMLEAK=y
CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000
使用方法:
1. cmd_line添加: kmemleak=off 或 kmemleak=on
2. mount -t debugfs nodev /sys/kernel/debug/
3. echo scan >/sys/kernel/debug/kmemleak
4. cat /sys/kernel/debug/kmemleak
5. Tracked的函数是:kmalloc,vmalloc、kmem_cache_alloc、per_cpu
# 作用: 打印出系统消逝的时间
CONFIG_PRINTK_TIME=y
# 与保留内存配合使用,记录内核最后crash相关信息
1. 内核配置
CONFIG_PSTORE=y
CONFIG_PSTORE_CONSOLE=y 所有内核信息
CONFIG_PSTORE_PMSG=y 所有用户态信息保留在/dev/pmsg0
CONFIG_PSTORE_RAM=y panic/oops信息
CONFIG_PSTORE_FTRACE=y ftrace信息
2. 预留内存
pstore_reserve_mem: pstore_reserve_mem_region@0 {
linux, reserve-contiguous-region;
linux, reserve-region;
linux, remove-completely;
reg =<0x0 startaddress 0x0 len>;
};
3. 查看上次异常的dmesg的消息
mount -t pstore -o kmsg_bytes=8000 - /sys/fs/pstore
使用场景:死锁的检测机制,抢占被长时间关闭而导致进程无法调度(soft lockup),和中断被长时间关闭而导致更严重的问题(hard lockup),表现现象可能是系统卡死。
# 内核配置
CONFIG_LOCKUP_DETECTOR=y
CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1
# 使用方法
#设置,当发生softlockup时系统是否panic
/proc/sys/kernel/softlockup_panic
#当CPU发生IPI中断时,触发softlockup
/proc/sys/kernel/softlockup_all_cpu_backtrace
使用场景:进程长时间处于D状态,即TASK_UNINTERRUPTIBLE
状态,处于这种状态的进程不处理信号,所以kill不掉。
# 内核配置
CONFIG_DETECT_HUNG_TASK=y
CONFIG_DEFAULT_HUNG_TIMEOUT=120
CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=1
CONFIG_WQ_WATCHDOG=y
# 使用方法
# 设置发生hung task时系统是否panic
/proc/sys/kernel/hung_task_panic
# 设置默认timeout的阈值120s
/proc/sys/kernel/hung_task_timeout_secs
# watchdog异常等待时间
/proc/sys/kernel/watchdog_thresh
主要是介绍下 /proc/PID/stat
这个文件。
具体可参考内核目录下的Documentation/filesystems/proc.txt
或直接指向 man proc 5
一般cat该文件会得到一堆数字:
root@(none):/# cat /proc/104/stat
104 (rproc-e907_rpro) S 2 0 0 0 -1 2130240 0 0 0 0 0 4461 0 0 -91 0 1 0 6 0 0 4294967295 0 0 0 0 0 0 0 2147483647 0 1 0 0 17 0 90 1 0 0 0 0 0 0 0 0 0 0 0
# 域
1:pid 2:(exec-file-name) 3:state 4:ppid 5:pgrp 6:session 7:tty_nr 8:tpgid 9 10 11 12 13 14:utime 15:stime 16:cutime 17:cstime 18 19 20 21 22:starttime 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43:guest_time 44 45 46 47 48 49 50 51 52
下面解释其各个域的含义:
PF_*
的定义(include/linux/sched.h)进程总耗时= utime + stime
进程总耗时= utime + stime
SIGALRM
的jiffies
时间,2.6之后,不再使用,固定为0process-running-time(seconds) = system-uptime(seconds) - (starttime / USER_HZ)
USER_HZ
一般都是固定为100,定义在include/asm-generic/param.h
RLIMIT_RSS
定义include/uapi/linux/sched.h
简易脚本:
#/bin/bash
if [ $# -ne 1 ]; then
echo "Usage: parse_stat.sh PID"
exit
fi
stat=`cat /proc/$1/stat`
stat_info=(${stat// / })
#1. pid
echo "PID: "${stat_info[0]}
#2. exec-file-name
echo "exec: "${stat_info[1]}
#3. state
# R - running
# S - 可中断休眠
# D - 不可中断休眠
# Z - 僵尸进程
# T - 被追踪或停止
# X - 死亡线程
if [ ${stat_info[2]} == "R" ]; then
echo "state: Running"
elif [ ${stat_info[2]} == "S" ]; then
echo "state: Sleeping(interruptible)"
elif [ ${stat_info[2]} == "D" ]; then
echo "state: Sleeping(uninterruptible)"
elif [ ${stat_info[2]} == "Z" ]; then
echo "state: Zombie"
elif [ ${stat_info[2]} == "T" ]; then
echo "state: Stopped"
elif [ ${stat_info[2]} == "X" ]; then
echo "state: Dead"
else
echo "state: "${stat_info[2]}
fi
#4. ppid
echo "parent process ID: "${stat_info[3]}
#5. pgrp
echo "group process ID: "${stat_info[4]}
#6. session
echo "session ID: "${stat_info[5]}
#7. tty_nr
echo "tty_nr: "${stat_info[6]}
#8. tpgid
echo "terminal process ID: "${stat_info[7]}
#9. flags
printf "flags: 0x%x\n" ${stat_info[8]}
#10. minflt
echo "minflt: "${stat_info[9]}
#11. cminflt
echo "cminflt: "${stat_info[10]}
#12. majflt
echo "majflt: "${stat_info[11]}
#13. cmajflt
echo "cmajflt: "${stat_info[12]}
#14. utime
ms=`expr ${stat_info[13]} \* 10`
echo "user time: ${ms} ms"
#15. stime
ms=`expr ${stat_info[14]} \* 10`
echo "kernel time: ${ms} ms"
#16. cutime
ms=`expr ${stat_info[15]} \* 10`
echo "child user time: ${ms} ms"
#17. cstime
ms=`expr ${stat_info[16]} \* 10`
echo "child kernel time: ${ms} ms"
#18. priority
echo "priority: "${stat_info[17]}
#19. nice
echo "nice: "${stat_info[18]}
#20. num_threads
echo "num_threads: "${stat_info[19]}
#21. itrealvalue
echo "itrealvalue: "${stat_info[20]} "(废弃)"
#22. starttime
ms=`expr ${stat_info[21]} \* 10`
echo "starttime: ${ms} ms"
#23. vsize
echo "vsize: ${stat_info[22]} Bytes"
#24. rss (unit page)
size=`expr ${stat_info[23]} \* 4`
echo "rss: $size Kb"
#25. rsslim
echo "rsslim: ${stat_info[24]} Bytes"
#26. startcode
printf "startcode: 0x%x\n" ${stat_info[25]}
#27. endcode
printf "endcode: 0x%x\n" ${stat_info[26]}
#28. startstack
printf "startstack: 0x%x\n" ${stat_info[27]}
#29. kstkesp
printf "kstkesp: 0x%x\n" ${stat_info[28]}
#30. kstkeip
printf "kstkeip: 0x%x\n" ${stat_info[29]}
#31. signal
echo "signal(pending): "${stat_info[30]}
#32. blocked
echo "signal(blocked): "${stat_info[31]}
#33. sigignore
printf "signal(ignore): 0x%x\n" ${stat_info[32]}
#34. sigcatch
echo "signal(catch): "${stat_info[33]}
#35. wchan
echo "wchan: "${stat_info[34]}
#36. nswap
echo "swap pages: "${stat_info[35]}
#37. cnswap
echo "child swap pages: "${stat_info[36]}
#38. exit_signal
echo "exit_signal: "${stat_info[37]}
#39. processor
echo "processor: "${stat_info[38]}
#40. rt_priority
echo "rt_priority: "${stat_info[39]}
#41. policy
# 0:SCHED_NORMAL
# 1:SCHED_FIFO
# 2:SCHED_RR
# 3:SCHED_BATCH
# 5:SCHED_IDLE
# 6:SCHED_DEADLINE
if [ ${stat_info[40]} == "0" ]; then
echo "policy: SCHED_NORMAL"
elif [ ${stat_info[40]} == "1" ]; then
echo "policy: SCHED_FIFO"
elif [ ${stat_info[40]} == "2" ]; then
echo "policy: SCHED_RR"
elif [ ${stat_info[40]} == "3" ]; then
echo "policy: SCHED_BATCH"
elif [ ${stat_info[40]} == "5" ]; then
echo "policy: SCHED_IDLE"
elif [ ${stat_info[40]} == "6" ]; then
echo "policy: SCHED_DEADLINE"
else
echo "policy: "${stat_info[40]}
fi
#42. delayacct_blkio_ticks
ms=`expr ${stat_info[41]} \* 10`
echo "delayacct_blkio_ticks: $ms ms"
#43. guest_time
ms=`expr ${stat_info[42]} \* 10`
echo "guest_time: $ms ms"
#44. cguest_time
ms=`expr ${stat_info[43]} \* 10`
echo "child guest_time: $ms ms"
#45. start_data
printf "start_data: 0x%x\n" ${stat_info[44]}
#46. end_data
printf "end_data: 0x%x\n" ${stat_info[45]}
#47. start_brk
printf "start_brk: 0x%x\n" ${stat_info[46]}
#48. arg_start
printf "arg_start: 0x%x\n" ${stat_info[47]}
#49. arg_end
printf "arg_end: 0x%x\n" ${stat_info[48]}
#50. env_start
printf "env_start: 0x%x\n" ${stat_info[49]}
#51. env_end
printf "env_end: 0x%x\n" ${stat_info[50]}
#52. exit_code
echo "exit_code: "${stat_info[51]}
# cat /proc/[pid]/statm
statm=`cat /proc/$1/statm`
statm_info=(${statm// / })
# size (1) total program size
# (same as VmSize in /proc/[pid]/status)
ms=`expr ${statm_info[0]} \* 4`
echo "program size: $ms kB"
# resident (2) resident set size
ms=`expr ${statm_info[1]} \* 4`
echo "rss: $ms kB"
# share (3) shared pages (i.e., backed by a file)
ms=`expr ${statm_info[2]} \* 4`
echo "share: $ms kB"
# text (4) text (code)
ms=`expr ${statm_info[3]} \* 4`
echo "text: $ms kB"
# lib (5) library (unused in Linux 2.6)
# data (6) data + stack
ms=`expr ${statm_info[5]} \* 4`
echo "data: $ms kB"
# dt (7) dirty pages (unused in Linux 2.6)
cat sys/kernel/debug/pinctrl/pio/pinmux-pins
Pinmux settings per pin
Format: pin (name): mux_owner gpio_owner hog?
pin 0 (PA0): (MUX UNCLAIMED) (GPIO UNCLAIMED)
...
pin 64 (PC0): spi0 (GPIO UNCLAIMED) function spi0 group PC0
pin 65 (PC1): spi0 (GPIO UNCLAIMED) function spi0 group PC1
...
pin 238 (PH14): (MUX UNCLAIMED) pio:238
# (MUX UNCLAIMED) (GPIO UNCLAIMED) 表示当前该IO无人申请
# spi0 (GPIO UNCLAIMED)表示该IO被某一个组申请, 如 PC0属于SPI0, 当前的复用功能是 spi0
# (MUX UNCLAIMED) pio:238 表示该IO被pio管理,但无人申请
查看所有信号:
kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
其中:
常用信号:
// 头文件
#include
#include
#include
#include
/*
* filgs:
* O_RDONLY, O_WRONLY, O_RDWR 这3个互斥,只能任选其一
* 下面的flags可通过'|'同时使用
* O_CREAT: 不存在则创建
* O_NOCTTY: 打开的文件为终端机设备时, 则不会将该终端机当成进程控制终端机
* O_TRUNC: 若文件存在并以可写的方式打开时, 会令文件长度清为0, 而原来数据会消失.
* O_APPEND: 追加
* O_NONBLOCK: 非阻塞打开文件
* O_NDELAY: 功能同上
* O_SYNC: 同步打开
* O_NOFOLLOW: 如果打开文件为符号连接,打开失败
* O_DIRECTORY: 如果打开文件不是目录,打开失败
* mode:
* 权限说明: x:1 w:2 r:4 从左到右 owner,group,other
* S_IRWXU: 0700, 所有者可读写执行
* S_IRUSR/S_IREAD: 0400 所有者可读
* S_IWUSR/S_IWRITE: 0200 所有者可写
* S_IXUSR/S_IEXEC: 0100 所有者可执行
* S_IRWXG: 0070
* S_IRGRP: 0040
* S_IWGRP: 0020
* S_IXGRP: 0010
* S_IRWXO: 0007
* S_IROTH: 0004
* S_IWOTH: 0002
* S_IXOTH: 0001
* 返回值:
* 成功返回0, 否则负数错误码
*/
int open(const char * pathname, int flags);
int open(const char * pathname, int flags, mode_t mode);
/*
* 成功返回读取字节数 >= 0
* 失败返回-1, errno保存负数错误码
* EINTR: 此调用被信号所中断
* EAGAIN: 使用非阻塞I/O 时(O_NONBLOCK), 若无数据可读取则返回此值
* EBADF: fd 非有效的文件描述词, 或该文件已关闭
*/
ssize_t read(int fd, void * buf, size_t count);
/*
* 成功返回读取字节数 >= 0
* 失败返回-1, errno保存负数错误码
* EINTR 此调用被信号所中断.
* EAGAIN 当使用不可阻断I/O 时 (O_NONBLOCK), 若无数据可读取则返回此值.
* EADF 参数fd 非有效的文件描述词, 或该文件已关闭.
*/
ssize_t write (int fd, const void * buf, size_t count);
回退到某个特定时间点之前:
repo forall -c 'commitID=`git log --before "2017-03-17 07:00" -1 --pretty=format:"%H"`; git reset --hard $commitID'
宏:
#define xxx_debug(fmt, ...) \
(printf(__FILE__, __func__, __LINE__, fmt, ##__VA_ARGS__))
函数:
#include
int my_printf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt); // 第二个参数必须是 ... 的前一个参数
while (*fmt) {
...
switch (ch) {
case 'd': num = va_arg(args, int); break;
case 's': num = va_arg(args, char *); break;
...
}
}
va_end(args);
return 0;
}
文件位置:/proc/timer_stats
依赖选项:CONFIG_TIMER_STATS
# enable
echo 1 > /proc/timer_stats
# disable
echo 0 > /proc/timer_stats
# 也可在stop前 cat, 无具体要求
cat /proc/timer_stats
Timer Stats Version: v0.3
Sample period: 4.778 s
Collection: inactive
次数 PID 进程名 调用地点(回调函数)
1, 0 swapper/0 tick_nohz_restart (tick_sched_timer)
21, 0 swapper/1 tick_nohz_restart (tick_sched_timer)
1194, 0 swapper/0 tick_nohz_restart (tick_sched_timer)
5, 1476 netifd schedule_hrtimeout_range_clock (hrtimer_wakeup)
471, 1492 swupdate-progre do_nanosleep (hrtimer_wakeup)
592, 7 rcu_preempt rcu_gp_kthread (process_timeout)
359, 0 swapper/1 __tick_nohz_idle_enter (tick_sched_timer)
36, 614 kworker/0:1 queue_delayed_work_on (delayed_work_timer_fn)
可参考文档:Documentation/RCU/stallwarn.txt
sys/module/rcupdate/parameters/rcu_cpu_stall_suppress
参数用于配置是否使能RCU的CPU停顿检测机制打印信息
INFO: rcu_sched_state detected stall on CPU 5 (t=2500 jiffies)
CPU5产生了停顿,随后会有CPU5打印出栈回溯
如果停顿的CPU没办法及时地打印数据,将有其他CPU帮忙打印,会出现如下的INFO:
INFO: rcu_bh_state detected stalls on CPUs/tasks: { 3 5 } (detected by 2, 2502 jiffies)
后面的信息如下:
INFO: rcu_preempt detected stall on CPU
0: (63959 ticks this GP) idle=241/3fffffffffffffff/0 softirq=82/543
(t=65000 jiffies)
(63959 ticks this GP) 表示超过了宽限周期多少个调度tick
idle= 部分 打印 dyntick-idle 状态。
1. 241: dyntick计数器的低12bit, 如果CPU处理dyntikc-idle模式它会是一个偶数,否则是奇数
2. 3fffffffffffffff:16进制嵌套值,如果在空闲循环会是一个很小的证书,否则是一个很大的正数
softirq= 部分
1. 82:最后一次记录宽限周期时,softirq执行的次数
2. 543: CPU启动到当前时间执行的softsirq次数
如果这个数字在多次RCU的消息中不变,可能说明softirq不能在该CPU上运行(正在持有自旋锁?)
或在 -rt 内核中 如果高优先级进程正在挨饿
引发RCU警告的几种原因:
RCU-sche
和 RCU-bh
停顿RCU-sche
和 RCU-bh
停顿RCU-sche
和 RCU-bh
停顿区别:
使用场景:fork出的子进程在执行exec时,关闭父进程的文件句柄
缘由:
#include
#include
int fd=open("foo.txt",O_RDONLY);
int flags = fcntl(fd, F_GETFD);
flags |= FD_CLOEXEC;
fcntl(fd, F_SETFD, flags);