linux 关于rw_semaphore 结构体内的count,到底是如何记录信息的?

huawenforever 2014-07-21 01:46:17
linux 3.10
在include/linux/Rwsem.h中有关于rw_semaphore结构体的定义:
#ifdef CONFIG_RWSEM_GENERIC_SPINLOCK
#include <linux/rwsem-spinlock.h> /* use a generic implementation */
#else
/* All arch specific implementations share the same struct */
struct rw_semaphore {
long count;
raw_spinlock_t wait_lock;
struct list_head wait_list;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
};

Understanding the Linux Kernel, 3rd Edition 里面对 count 的定义是:
count
Stores two 16-bit counters. The counter in the most significant word encodes in two's complement form the sum of the number of nonwaiting writers (either 0 or 1) and the number of waiting kernel control paths. The counter in the less significant word encodes the total number of nonwaiting readers and writers.

我对应了lib/rwsem.c的实现函数:rwsem_down_read_failed,rwsem_down_write_failed 还是看不懂count的意义。
我的理解是比如有1个read占有信号,而一个write阻塞,这样的话count应该是0xffff 0001 ;而1个write占有信号,1个read被阻塞应该是0x fffe 0001
实际情况不是这样的,有没有谁可以帮忙解释下,谢谢了
另外x86 下,arch/x86/include/asm/Rwsem.h中的几个宏为什么这样定义?
#ifdef CONFIG_X86_64
# define RWSEM_ACTIVE_MASK 0xffffffffL
#else
# define RWSEM_ACTIVE_MASK 0x0000ffffL
#endif

#define RWSEM_UNLOCKED_VALUE 0x00000000L
#define RWSEM_ACTIVE_BIAS 0x00000001L
#define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1)
#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
...全文
727 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
huawenforever 2014-07-24
  • 打赏
  • 举报
回复
帖子的分数分配给你没? 第一次玩这东西,看着帖子总是显示结贴状态,但是分数像是没有分配状态
colddown 2014-07-23
  • 打赏
  • 举报
回复
我是3.10内核。同感很苦。。。
huawenforever 2014-07-23
  • 打赏
  • 举报
回复
你运行的linux 内核版本是多少? 看着log信息的话,确实如你说的,高16位只是记录当前write信号的获取(0或1)+ 等待队列是否为空(0或1). [ 6312.313546] reader_1 is waiting for read [ 6312.313559] reader_2 is waiting for read [ 6312.314651] writer_2 is running [ 6312.327622] writer_2 is waiting for write [ 6312.424645] sem.count=0xfffffffe00000001 write 1 拿到信号 ,read 1、2 和 write 2 阻塞 0xfffffffe00000001 晚上我回去在自己机子上运行下,再推下数值,就可以结贴了 编程菜鸟,看内核何其苦逼!!! ~~~~(>_<)~~~~
colddown 2014-07-22
  • 打赏
  • 举报
回复
我的理解基本和楼主一样。区别就是count的上半部分等于当前获得锁的写者数目(0或1)加上等待列表是否为空(0或1)的补码。 例如: 1. 当前有一个获得锁的写者且等待链表为空,则count=0xffff0001 2. 当前有一个获得锁的写者且等待链表非空,则count=0xfffe0001 3. 当前有多个获得锁的读者且等待链表为空,则count=0x0000000X 4. 当前有多个获得锁的读者且等待链表非空,则count=0xffff000X 楼主实际测试过并且发现不是这样?
colddown 2014-07-22
  • 打赏
  • 举报
回复
我用如下的模块试了一下,根据log推断,count的变化应该和之前想的一样。 [ 6312.206759] Hello, world [ 6312.208982] reader_1 is running [ 6312.209347] reader_2 is running [ 6312.209724] writer is running [ 6312.222916] writer is waiting for write [ 6312.222924] writer got write lock [ 6312.222926] sem.count=0xffffffff00000001 [ 6312.222928] writer is sleeping 200 [ 6312.313546] reader_1 is waiting for read [ 6312.313559] reader_2 is waiting for read [ 6312.314651] writer_2 is running [ 6312.327622] writer_2 is waiting for write [ 6312.424645] sem.count=0xfffffffe00000001 [ 6312.424651] writer releses write lock [ 6312.424697] reader_1 got read lock [ 6312.424700] sem.count=0xffffffff00000002 [ 6312.424701] reader_1 is sleeping 200 [ 6312.424705] reader_2 got read lock [ 6312.424707] sem.count=0xffffffff00000002 [ 6312.424708] reader_2 is sleeping 200 [ 6312.627648] reader_2 releses read lock [ 6312.627747] reader_1 releses read lock [ 6312.627867] writer_2 got write lock [ 6312.627872] sem.count=0xffffffff00000001 [ 6312.627874] writer_2 is sleeping 200 [ 6312.831732] sem.count=0xffffffff00000001 [ 6312.831739] writer_2 releses write lock
#include <linux/init.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/rwsem.h>
MODULE_LICENSE("Dual BSD/GPL");

static struct rw_semaphore sem;

static void print_sem(struct rw_semaphore *sem)
{
    printk(KERN_DEBUG "sem.count=0x%016lx\n", sem->count);
}

static void get_read_lock(struct rw_semaphore *sem, char *name)
{
    printk(KERN_DEBUG "%s is waiting for read\n", name);
    down_read(sem);
    printk(KERN_DEBUG "%s got read lock\n", name);
}

static void release_read_lock(struct rw_semaphore *sem, char *name)
{
    printk(KERN_DEBUG "%s releses read lock\n", name);
    up_read(sem);
}

static void get_write_lock(struct rw_semaphore *sem, char *name)
{
    printk(KERN_DEBUG "%s is waiting for write\n", name);
    down_write(sem);
    printk(KERN_DEBUG "%s got write lock\n", name);
}

static void release_write_lock(struct rw_semaphore *sem, char *name)
{
    printk(KERN_DEBUG "%s releses write lock\n", name);
    up_write(sem);
}

int reader(void *data)
{
    char *name = (char *)data;
    printk(KERN_DEBUG "%s is running\n", name);
    msleep(100);

    get_read_lock(&sem, name);
    print_sem(&sem);

    printk(KERN_DEBUG "%s is sleeping 200\n", name);
    msleep(200);

    release_read_lock(&sem, name);
    do_exit(0);
}
int writer(void *data)
{
    char *name = (char *)data;
    printk(KERN_DEBUG "%s is running\n", name);
    msleep(10);

    get_write_lock(&sem, name);
    print_sem(&sem);

    printk(KERN_DEBUG "%s is sleeping 200\n", name);
    msleep(200);

    print_sem(&sem);
    release_write_lock(&sem, name);
    do_exit(0);
}

static int hello_init(void)
{
    struct task_struct *task = NULL;
    printk(KERN_ALERT "Hello, world\n");

    init_rwsem(&sem);

    task = kthread_create(reader, "reader_1", "reader");
    if (IS_ERR(task)) {
        printk(KERN_DEBUG "failed to create task\n");
        return 1;
    }
    wake_up_process(task);

    task = kthread_create(reader, "reader_2", "reader");
    if (IS_ERR(task)) {
        printk(KERN_DEBUG "failed to create task\n");
        return 1;
    }
    wake_up_process(task);

   task = kthread_create(writer, "writer", "reader");
    if (IS_ERR(task)) {
        printk(KERN_DEBUG "failed to create task\n");
        return 1;
    }
    wake_up_process(task);

    msleep(100);
    task = kthread_create(writer, "writer_2", "reader");
    if (IS_ERR(task)) {
        printk(KERN_DEBUG "failed to create task\n");
        return 1;
    }
    wake_up_process(task);

    return 0;
}

static void hello_exit(void)
{
    printk(KERN_ALERT"Goodbye, cruel world\n");
}

module_init(hello_init);
module_exit(hello_exit);

huawenforever 2014-07-22
  • 打赏
  • 举报
回复
不是,只是增加读写者的数量,推数值,发现推出来的数值和自己的理解不同 看样子还是得加个驱动,具体看看数值

4,436

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 内核源代码研究区
社区管理员
  • 内核源代码研究区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧