• linux内核 —— 读写信号量实验


    内核版本:5.14
    代码路径:

    • kernel/locking/rwsem.c
    • include/linux/rwsem.h

    概述

    读写信号量具有如下特点:

    • 是一种睡眠锁
    • 可以有多个read持有读信号量
    • 只允许一个write持有持有写信号量
    • read和write之间互斥
    • write和write之间互斥
    • 以严格的FIFO顺序处理等待读/写信号量的所有进程。如果read或write进程发现信号量关闭,这些进程就被插入到信号量等待队列链表的末尾。
    • 当信号量被释放时,检查处于等待队列链表第一个位置的进程。第一个进程被唤醒。如果时一个写者进程,等待队列上的其他的进程就继续睡眠。如果是一个读者进程,那么紧跟第一个进程的其他所有读者进程也被唤醒并获得信号量。不过,在写者进程之后排队的读者进程继续睡眠

    数据结构

    struct rw_semaphore {
    	atomic_long_t count;
    	atomic_long_t owner;
    #ifdef CONFIG_RWSEM_SPIN_ON_OWNER
    	struct optimistic_spin_queue osq; /* spinner MCS lock */
    #endif
    	raw_spinlock_t wait_lock;
    	struct list_head wait_list;
    };
    
    • owner
      bit0:是否是读者持有信号,是的话为1
      bit1:是否可以在读者持有的信号量上自旋等待
      bit2~63:当读者持有信号时,owner中会记录获取到信号的最后一个读者进程的task_struct。如果写者持有信号,那么owner记录的是该写者进程的task_struct

    • count
      bit0:是否是写者持有信号
      bit1:是否有进程阻塞在等待队列中
      bit2:handoff
      bit8~62:读者的数量
      bit63:read fail

    实验

    实现一个申请和释放读写信号量rwsem_test的内核模块,然后通过应用来控制申请或者释放,期间使用crash工具查看rwsem_test信号量的内部状态。

    • 获取读写信号量rwsem_test的地址
    root@ubuntu-vm:~# crash /mnt/linux-5.14/vmlinux
          KERNEL: /mnt/linux-5.14/vmlinux
        DUMPFILE: /dev/mem
            CPUS: 12
            DATE: Sat Mar 26 09:34:29 CST 2022
          UPTIME: 00:29:52
    LOAD AVERAGE: 0.72, 0.23, 0.08
           TASKS: 176
        NODENAME: ubuntu-vm
         RELEASE: 5.14.0+
         VERSION: #3 SMP Fri Mar 25 08:57:39 PDT 2022
         MACHINE: x86_64  (3599 Mhz)
          MEMORY: 16 GB
             PID: 578
         COMMAND: "crash"
            TASK: ffff8de0c595ec80  [THREAD_INFO: ffff8de0c595ec80]
             CPU: 2
           STATE: TASK_RUNNING (ACTIVE)
    
    crash> sym rwsem_test
    ffffffffa5645b00 (d) rwsem_test
    
    • 查看读写信号量的状态
    crash> rw_semaphore.count,owner,wait_list -x ffffffffa5645b00
      count = {
        counter = 0x0
      },
      owner = {
        counter = 0x0
      },
      wait_list = {
        next = 0xffffffffa5645b18 <rwsem_test+24>,
        prev = 0xffffffffa5645b18 <rwsem_test+24>
      }
    

    可以看到初始状态count和owner都是0

    • 查看等待队列的地址
    crash> rw_semaphore.wait_list -ox ffffffffa5645b00
    struct rw_semaphore {
      [ffffffffa5645b18] struct list_head wait_list;
    }
    
    • 遍历等待队列

    方式一:

    crash> list -o rwsem_waiter.list -O rw_semaphore.wait_list -s rwsem_waiter.task,type -h ffffffffa5645b00
    (empty)
    

    方式二:

    crash> list -o rwsem_waiter.list  -s rwsem_waiter.task,type -H ffffffffa5645b18
    (empty)
    

    或者: 由于list在rwsem_waiter中的偏移量为0

    crash> list  -s rwsem_waiter.task,type -H ffffffffa5645b18
    (empty)
    
    • 实验数据

    说明:

    r: 申请读信号
    w:申请写信号
    R:释放读信号
    W:释放写信号
    
    操作序列 状态 队列 备注
    初始 count:0 owner:0
    r1 count:0x100
    owner:0xffff9ba7465b9f01
    count表示读者数量为1
    owner的bit0为1,表示被读者持有,读者的task_struct为0xffff9ba7465b9f00
    w1 count:0x1
    owner:0xffff9ba7465b9f00
    count的bit0为1,表示写者持有
    owner记录的时这个写者的task_struct:0xffff9ba7465b9f00
    r1R1 count:0x0
    owner:0xffff9ba7465b9f01
    w1W1 count:0
    owner:0
    r1r2 count:0x200
    owner:0xffff9ba7465bae81
    r1r2R1 count:0x100
    owner:0xffff9ba7465bae81
    r1r2R1R2 count:0x0
    owner:0xffff9ba7465bae81
    r1r1 count:0x200
    owner:0xffff9ba7465b9f01
    w1w2 count:0x3
    owner:0xffff9ba7465b9f00
    task = 0xffff9ba7465bae80,
    type = RWSEM_WAITING_FOR_WRITE
    w1w2W1 count:0x1
    owner:0xffff9ba7465bae80
    w1w2W1W2 count:0
    owner:0
    r1w1 count:0x102
    owner:0xffff9ba7465b9f03
    task = 0xffff9ba7465bae80,
    type = RWSEM_WAITING_FOR_WRITE
    r1w1r2 count:0x102
    owner:0xffff9ba7465b9f03
    task = 0xffff9ba7465bae80,
    type = RWSEM_WAITING_FOR_WRITE
    task = 0xffff9ba748febe00,
    type = RWSEM_WAITING_FOR_READ
    r1w1r2R1 count:0x3
    owner:0xffff9ba7465bae80
    task = 0xffff9ba748febe00,
    type = RWSEM_WAITING_FOR_READ
    r1w1r2R1W1 count:0x100
    owner:0xffff9ba748febe01
    r1w1r2R1W1R2 count:0x0
    owner:0xffff9ba748febe01
    w1r1 count:0x3
    owner:0xffff9ba7465b9f00
    task = 0xffff9ba7465bae80,
    type = RWSEM_WAITING_FOR_READ
    w1r1W1 count:0x100
    owner:0xffff9ba7465bae81
    w1r1w2 count:0x3
    owner:0xffff9ba7465b9f00
    task = 0xffff9ba7465bae80,
    type = RWSEM_WAITING_FOR_READ
    task = 0xffff9ba748febe00,
    type = RWSEM_WAITING_FOR_WRITE
    w1r1w2W1 count:0x102
    owner:0xffff9ba7465bae81
    task = 0xffff9ba748febe00,
    type = RWSEM_WAITING_FOR_WRITE
    w1r1w2W1R1 count:0x1
    owner:0xffff9ba748febe00
    w1r1w2W1R1W2 count:0
    owner:0
    r1w1w2 count:0x102
    owner:0xffff9ba7465b9f03
    task = 0xffff9ba7465bae80,
    type = RWSEM_WAITING_FOR_WRITE
    task = 0xffff9ba748febe00,
    type = RWSEM_WAITING_FOR_WRITE
    r1w1w2R1 count:0x3
    owner:0xffff9ba7465bae80
    task = 0xffff9ba748febe00,
    type = RWSEM_WAITING_FOR_WRITE
    r1w1w2R1W1 count:0x1
    owner:0xffff9ba748febe00
    r1w1w2R1W1W2 count:0
    owner:0
    r1r2w1 count:0x202
    owner:0xffff9ba7465bae83
    task = 0xffff9ba748febe00,
    type = RWSEM_WAITING_FOR_WRITE
    r1r2w1R2 count:0x102
    owner:0xffff9ba7465bae83
    task = 0xffff9ba748febe00,
    type = RWSEM_WAITING_FOR_WRITE
    r1r2w1R2R1 count:0x1
    owner:0xffff9ba748febe00
    r1r2w1R2R1W1 count:0
    owner:0

    玩完。

  • 相关阅读:
    前端常见跨域解决方案
    前端必须要懂的浏览器缓存机制
    判断一个变量是数组还是对象
    javascript中Array常用方法
    Javascript数据类型
    Email接收验证码,以实现登录/注册/修改密码
    web安全之机器学习入门——3.2 决策树与随机森林
    web安全之机器学习入门——3.1 KNN/k近邻
    web安全之机器学习入门——2.机器学习概述
    cmd下的一些小技巧
  • 原文地址:https://www.cnblogs.com/pengdonglin137/p/16057702.html
Copyright © 2020-2023  润新知