• mutex互斥锁 - linux内核锁(四)


    头文件
    #include
    定义并初始化
    struct mutex mutex;
    mutex_init(&cm_dev->mutex);
    一 相关操作
    mutex_lock:加锁
    /**
     * mutex_lock - acquire the mutex
     * @lock: the mutex to be acquired
     *
     * Lock the mutex exclusively for this task. If the mutex is not
     * available right now, it will sleep until it can get it.
     *
     * The mutex must later on be released by the same task that
     * acquired it. Recursive locking is not allowed. The task
     * may not exit without first unlocking the mutex. Also, kernel
     * memory where the mutex resides must not be freed with
     * the mutex still locked. The mutex must first be initialized
     * (or statically defined) before it can be locked. memset()-ing
     * the mutex to 0 is not allowed.
     *
     * ( The CONFIG_DEBUG_MUTEXES .config option turns on debugging
     *   checks that will enforce the restrictions and will also do
     *   deadlock debugging. )
     *
     * This function is similar to (but not equivalent to) down().
     */
    void __sched mutex_lock(struct mutex *lock)
    {
        might_sleep();
        /*
         * The locking fastpath is the 1->0 transition from
         * 'unlocked' into 'locked' state.
         */
        __mutex_fastpath_lock(&lock->count, __mutex_lock_slowpath);
        mutex_set_owner(lock);
    }
    mutex_trylock:尝试加锁
    上锁失败返回0,成功返回1,本次实验中,循环判断上锁

    while(mutex_trylock(&cm_dev->mutex) == 0){
            msleep(1);
        }
    /**
     * mutex_trylock - try to acquire the mutex, without waiting
     * @lock: the mutex to be acquired
     *
     * Try to acquire the mutex atomically. Returns 1 if the mutex
     * has been acquired successfully, and 0 on contention.
     *
     * NOTE: this function follows the spin_trylock() convention, so
     * it is negated from the down_trylock() return values! Be careful
     * about this when converting semaphore users to mutexes.
     *
     * This function must not be used in interrupt context. The
     * mutex must be released by the same task that acquired it.
     */
    int __sched mutex_trylock(struct mutex *lock)
    {
        int ret;
     
        ret = __mutex_fastpath_trylock(&lock->count, __mutex_trylock_slowpath);
        if (ret)
            mutex_set_owner(lock);
     
        return ret;
    }

    mutex_unlock:解锁
     
    /**
     * mutex_unlock - release the mutex
     * @lock: the mutex to be released
     *
     * Unlock a mutex that has been locked by this task previously.
     *
     * This function must not be used in interrupt context. Unlocking
     * of a not locked mutex is not allowed.
     *
     * This function is similar to (but not equivalent to) up().
     */
    void __sched mutex_unlock(struct mutex *lock)
    {
        /*
         * The unlocking fastpath is the 0->1 transition from 'locked'
         * into 'unlocked' state:
         */
    #ifndef CONFIG_DEBUG_MUTEXES
        /*
         * When debugging is enabled we must not clear the owner before time,
         * the slow path will always be taken, and that clears the owner field
         * after verifying that it was indeed current.
         */
        mutex_clear_owner(lock);
    #endif
        __mutex_fastpath_unlock(&lock->count, __mutex_unlock_slowpath);
    }

    实例验证:
    static int
    cm_thread_1(void *arg)
    {
        int ret = 0;
        int send_count = 0;
        struct buf_node *pnode;
        struct cm_dev_ *cm_dev = (struct cm_dev_ *)arg;
        wait_queue_t wait = __WAITQUEUE_INITIALIZER(wait, current);
        DEBUG_CM("");
        while(mutex_trylock(&cm_dev->mutex) == 0){
            msleep_interruptible(1);
        }
        add_wait_queue(&cm_dev->w_wait,&wait);
        mutex_unlock(&cm_dev->mutex);
        DEBUG_CM("");
        while(1){
            DEBUG_CM("");
            if(kthread_should_stop()){
                DEBUG_CM("exit thread");
                break;
            }
            DEBUG_CM("");
            while(mutex_trylock(&cm_dev->mutex) == 0){
                msleep_interruptible(1);
            }
            while(cm_list_size(&cm_dev->ready_list) == 0){
                mutex_unlock(&cm_dev->mutex);
                DEBUG_CM("");
                set_current_state(TASK_INTERRUPTIBLE);
                schedule();            
                ret = signal_pending(current);
                if(ret){
                    DEBUG_CM("ret = %d",ret);
                    while(mutex_trylock(&cm_dev->mutex) == 0){
                        msleep_interruptible(1);
                    }
                    continue;
                }
                //执行kthread_stop函数后,也会调度该线程,此时signal_pending也是0
                if(kthread_should_stop()){
                    DEBUG_CM("exit thread");
                    goto end_thread_1;
                }
                while(mutex_trylock(&cm_dev->mutex) == 0){
                    msleep_interruptible(1);
                }
            }
            mutex_unlock(&cm_dev->mutex);
            ++send_count;
            DEBUG_CM("send a string:%d",send_count);
            while(mutex_trylock(&cm_dev->mutex) == 0){
                msleep_interruptible(1);
            }
            if(cm_list_size(&cm_dev->ready_list) > 0){
                pnode = pop_list(&cm_dev->ready_list);
                sprintf(pnode->buf,"send_count:%d",send_count);
                list_add_tail(&pnode->node,&cm_dev->ok_list);
                wake_up_interruptible(&cm_dev->r_wait);
            }else{
                DEBUG_CM("ready_list size == 0");
            }
            mutex_unlock(&cm_dev->mutex);
            DEBUG_CM("");
            
        }
    end_thread_1:
        remove_wait_queue(&cm_dev->w_wait,&wait);
        return 0;
    }
     
    static int
    cm_thread_2(void *arg)
    {
        int ret = 0;
        int send_count = 0;
        struct buf_node *pnode;
        struct cm_dev_ *cm_dev = (struct cm_dev_ *)arg;
        wait_queue_t wait = __WAITQUEUE_INITIALIZER(wait, current);
        while(mutex_trylock(&cm_dev->mutex) == 0){
            msleep_interruptible(1);
        }
        add_wait_queue(&cm_dev->r_wait,&wait);
        mutex_unlock(&cm_dev->mutex);
        while(1){
            if(kthread_should_stop()){
                DEBUG_CM("exit thread");
                break;
            }
            while(mutex_trylock(&cm_dev->mutex) == 0){
                msleep_interruptible(1);
            }
            while(cm_list_size(&cm_dev->ok_list) == 0){
                mutex_unlock(&cm_dev->mutex);
                set_current_state(TASK_INTERRUPTIBLE);            
                schedule();            
                ret = signal_pending(current);
                if(ret){
                    DEBUG_CM("ret = %d",ret);
                    
                    while(mutex_trylock(&cm_dev->mutex) == 0){
                        msleep_interruptible(1);
                    }
                    continue;
                }
                //执行kthread_stop函数后,也会调度该线程,此时signal_pending也是0
                if(kthread_should_stop()){
                    DEBUG_CM("exit thread");
                    goto end_thread_2;
                }
                
                while(mutex_trylock(&cm_dev->mutex) == 0){
                    msleep_interruptible(1);
                }
            }
            mutex_unlock(&cm_dev->mutex);
            ++send_count;
            while(mutex_trylock(&cm_dev->mutex) == 0){
                msleep_interruptible(1);
            }
            if(cm_list_size(&cm_dev->ok_list) > 0){
                DEBUG_CM("send a string:%d",send_count);
                pnode = pop_list(&cm_dev->ok_list);
                DEBUG_CM("pnode->buf = %s",pnode->buf);
                list_add_tail(&pnode->node,&cm_dev->ready_list);
                wake_up_interruptible(&cm_dev->w_wait);
            }else{
                DEBUG_CM("ready_list size == 0");
            }
            mutex_unlock(&cm_dev->mutex);
        }
    end_thread_2:
        remove_wait_queue(&cm_dev->r_wait,&wait);
        return 0;
    }
    输出结果:截取一段
    [   26.240569] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:182:
    [   26.246527] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:136:
    [   26.252454] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:141:
    [   26.258418] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_2:240: send a string:94
    [   26.265775] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_2:242: pnode->buf = send_count:94
    [   26.283228] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:169: send a string:95
    [   26.290566] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:182:
    [   26.296521] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:136:
    [   26.302448] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:141:
    [   26.308411] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_2:240: send a string:95
    [   26.315763] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_2:242: pnode->buf = send_count:95
    [   26.333223] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:169: send a string:96
    [   26.340564] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:182:
    [   26.346525] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:136:
    [   26.352455] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:141:
    [   26.358419] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_2:240: send a string:96
    [   26.365777] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_2:242: pnode->buf = send_count:96
    [   26.383230] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:169: send a string:97
    [   26.390571] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:182:
    [   26.396525] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:136:
    [   26.402453] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:141:
    [   26.408418] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_2:240: send a string:97
    [   26.415775] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_2:242: pnode->buf = send_count:97
    [   26.433223] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:169: send a string:98
    [   26.440560] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:182:

    ————————————————
    版权声明:本文为CSDN博主「千册」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/yueni_zhao/article/details/127416219

  • 相关阅读:
    【GDB】常用命令
    Python学习基础笔记七十六——Python装饰器2
    我的十年编程路 2019年篇
    python实现B/B+树
    代谢组学分析手段(一)
    scRNA-seq的fastq文件处理流程——持续更新
    【C++】map / multimap容器
    所见即所得即MySQL函数
    代码签名证书以及如何申请
    【Oracle】使用 SQL Developer 连接 Oracle 数据库
  • 原文地址:https://blog.csdn.net/u012294613/article/details/127890773