RT-Thread线程间同步(信号量, 互斥量, 事件集)--02源码分析

源码分析

使用看上一篇API使用

信号量

/**
 * Semaphore structure
 */
struct rt_semaphore
{
    struct rt_ipc_object parent;                        /**< inherit from ipc_object */

    rt_uint16_t          value;                         /**< value of semaphore. 
    												信号量的值*/
    rt_uint16_t          reserved;                      /**< reserved field 保留*/
};
typedef struct rt_semaphore *rt_sem_t;
/**
 * Base structure of IPC object
 */
struct rt_ipc_object
{
    struct rt_object parent;                            /**< inherit from rt_object */

    rt_list_t        suspend_thread;                    /**< threads pended on this 														resource 希望获取这一个的线程 */
};

创建

rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag)
{
    rt_sem_t sem;

    /* allocate object 获取一个对象, 这一个是对象处理的时候分析过了 */
    sem = (rt_sem_t)rt_object_allocate(RT_Object_Class_Semaphore, name);
    if (sem == RT_NULL)
        return sem;

    /* initialize ipc object 初始化以及记录链表的信息*/
    rt_ipc_object_init(&(sem->parent));

    /* set initial value */
    sem->value = value;

    /* set parent */
    sem->parent.parent.flag = flag;

    return sem;
}
//初始化一个链表
rt_inline rt_err_t rt_ipc_object_init(struct rt_ipc_object *ipc)
{
    /* initialize ipc object */
    rt_list_init(&(ipc->suspend_thread));

    return RT_EOK;
}

删除

rt_err_t rt_sem_delete(rt_sem_t sem)
{
    RT_DEBUG_NOT_IN_INTERRUPT;

    /* wakeup all suspended threads 唤醒所有的在等待这一个线程的任务, 
    把他们的错误标志位设置为错误 */
    rt_ipc_list_resume_all(&(sem->parent.suspend_thread));

    /* delete semaphore object 把这一个对象放在删除队列里面, 空闲任务的时候会处理 */
    rt_object_delete(&(sem->parent.parent));

    return RT_EOK;
}
rt_inline rt_err_t rt_ipc_list_resume_all(rt_list_t *list)
{
    struct rt_thread *thread;
    register rt_ubase_t temp;

    /* wakeup all suspended threads */
    while (!rt_list_isempty(list))
    {
        //这一个信号量有正在等待他的线程 
        /* disable interrupt 临界区 */
        temp = rt_hw_interrupt_disable();

        /* get next suspended thread 获取一个线程的控制块 */
        thread = rt_list_entry(list->next, struct rt_thread, tlist);
        /* set error code to RT_ERROR 线程的标志位改为错误 */
        thread->error = -RT_ERROR;

        /*
         * resume thread 恢复这一个线程的运行, 关闭线程时钟
         * In rt_thread_resume function, it will remove current thread from
         * suspended list
         */
        rt_thread_resume(thread);

        /* enable interrupt */
        rt_hw_interrupt_enable(temp);
    }

    return RT_EOK;
}

获取

rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time)
{
    register rt_base_t temp;
    struct rt_thread *thread;
	//回调函数
    RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(sem->parent.parent)));

    /* disable interrupt 临界区 */
    temp = rt_hw_interrupt_disable();
	//Debug信息打印
    RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread %s take sem:%s, which value is: %d\n",
                                rt_thread_self()->name,
                                ((struct rt_object *)sem)->name,
                                sem->value));

    if (sem->value > 0)
    {
        //这时候还有可以申请的
        /* semaphore is available */
        sem->value --;

        /* enable interrupt */
        rt_hw_interrupt_enable(temp);
    }
    else
    {
        //没有可以使用的资源了
        /* no waiting, return with timeout */
        if (time == 0)
        {
            //不想等待
            rt_hw_interrupt_enable(temp);

            return -RT_ETIMEOUT;
        }
        else
        {
            //有一个等待时间, 需要挂起
            /* current context checking */
            RT_DEBUG_IN_THREAD_CONTEXT;

            /* semaphore is unavailable, push to suspend list */
            /* get current thread */
            //获取当前的线程
            thread = rt_thread_self();

            /* reset thread error number */
            //改变一下线程的错误值
            thread->error = RT_EOK;

            RT_DEBUG_LOG(RT_DEBUG_IPC, ("sem take: suspend thread - %s\n",
                                        thread->name));

            /* suspend thread */
            //把这个线程插入链表里面
            rt_ipc_list_suspend(&(sem->parent.suspend_thread),
                                thread,
                                sem->parent.parent.flag);

            /* has waiting time, start thread timer */
            if (time > 0)
            {
                RT_DEBUG_LOG(RT_DEBUG_IPC, ("set thread:%s to timer list\n",
                                            thread->name));

                /* reset the timeout of thread timer and start it 
                使用这一个线程的时钟进行唤醒 */
                rt_timer_control(&(thread->thread_timer),
                                 RT_TIMER_CTRL_SET_TIME,
                                 &time);
                rt_timer_start(&(thread->thread_timer));
            }

            /* enable interrupt */
            rt_hw_interrupt_enable(temp);

            /* do schedule 获取当前优先级最高的函数并切换过去 */
            rt_schedule();
			//这个时候1.获取到了2.超时3.信号量没了
            if (thread->error != RT_EOK)
            {
                //出现错误了
                return thread->error;
            }
        }
    }

    RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(sem->parent.parent)));

    return RT_EOK;
}
rt_inline rt_err_t rt_ipc_list_suspend(rt_list_t        *list,
                                       struct rt_thread *thread,
                                       rt_uint8_t        flag)
{
    /* suspend thread */
    rt_thread_suspend(thread);

    switch (flag)
    {
    case RT_IPC_FLAG_FIFO:
        //按照先进先出的方式进行添加
        rt_list_insert_before(list, &(thread->tlist));
        break;

    case RT_IPC_FLAG_PRIO:
        {
            //按照优先级的模式进行添加
            struct rt_list_node *n;
            struct rt_thread *sthread;

            /* find a suitable position 遍历一下链表获取一个合适的位置 */
            for (n = list->next; n != list; n = n->next)
            {
                sthread = rt_list_entry(n, struct rt_thread, tlist);

                /* find out */
                if (thread->current_priority < sthread->current_priority)
                {
                    /* insert this thread before the sthread 把这个线程插入进去 */
                    rt_list_insert_before(&(sthread->tlist), &(thread->tlist));
                    break;
                }
            }

            /* 这一个线程的优先级是链表里面最低的放在最后
             * not found a suitable position,
             * append to the end of suspend_thread list
             */
            if (n == list)
                rt_list_insert_before(list, &(thread->tlist));
        }
        break;
    }

    return RT_EOK;
}
rt_err_t rt_sem_trytake(rt_sem_t sem)
{	
    //一个不延时的获取信号量
    return rt_sem_take(sem, 0);
}

释放

rt_err_t rt_sem_release(rt_sem_t sem)
{
    register rt_base_t temp;
    register rt_bool_t need_schedule;

    need_schedule = RT_FALSE;//记录一下需不需要任务的切换

    /* disable interrupt 临界区 */
    temp = rt_hw_interrupt_disable();

    RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread %s releases sem:%s, which value is: %d\n",
                                rt_thread_self()->name,
                                ((struct rt_object *)sem)->name,
                                sem->value));
	//看一看有么有挂起的任务
    if (!rt_list_isempty(&sem->parent.suspend_thread))
    {
        /* resume the suspended thread */
        //把一个任务释放出来, 这一个任务获取到这一个信号量, 下面有分析
        rt_ipc_list_resume(&(sem->parent.suspend_thread));
        need_schedule = RT_TRUE;
    }
    else
        sem->value ++; /* increase value */

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    /* resume a thread, re-schedule 之前记录的需要切换任务 */
    if (need_schedule == RT_TRUE)
        rt_schedule();

    return RT_EOK;
}
rt_inline rt_err_t rt_ipc_list_resume(rt_list_t *list)
{
    struct rt_thread *thread;

    /* get thread entry */
    thread = rt_list_entry(list->next, struct rt_thread, tlist);

    RT_DEBUG_LOG(RT_DEBUG_IPC, ("resume thread:%s\n", thread->name));

    /* resume it 恢复一个线程, 把线程时钟关了 */
    rt_thread_resume(thread);

    return RT_EOK;
}

互斥量

struct rt_mutex
{
    struct rt_ipc_object parent;                        /**< inherit from ipc_object */

    rt_uint16_t          value;                         /**< value of mutex 值*/

    rt_uint8_t           original_priority;             /**< priority of last thread hold
    												the mutex 持有的线程的原优先级*/
    rt_uint8_t           hold;                          /**< numbers of thread hold the
    												mutex 持有线程的持有次数*/

    struct rt_thread    *owner;                         /**< current owner of mutex 
    												当前拥有互斥量的线程*/
};

创建

//一个标准的对象创建, 和信号量基本一致
rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag)
{
    struct rt_mutex *mutex;

    RT_DEBUG_NOT_IN_INTERRUPT;

    /* allocate object */
    mutex = (rt_mutex_t)rt_object_allocate(RT_Object_Class_Mutex, name);
    if (mutex == RT_NULL)
        return mutex;

    /* initialize ipc object */
    rt_ipc_object_init(&(mutex->parent));

    mutex->value              = 1;
    mutex->owner              = RT_NULL;
    mutex->original_priority  = 0xFF;
    mutex->hold               = 0;

    /* set flag */
    mutex->parent.parent.flag = flag;

    return mutex;
}

释放

rt_err_t rt_mutex_delete(rt_mutex_t mutex)
{
    RT_DEBUG_NOT_IN_INTERRUPT;

    /* wakeup all suspended threads 唤醒所有的线程, 上面分析过了 */
    rt_ipc_list_resume_all(&(mutex->parent.suspend_thread));

    /* delete mutex object 等待释放 */
    rt_object_delete(&(mutex->parent.parent));

    return RT_EOK;
}

获取

rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time)
{
    register rt_base_t temp;
    struct rt_thread *thread;
	//这一个函数不可以在中断里面使用, 这时候的优先级是无效的
    /* this function must not be used in interrupt even if time = 0 */
    RT_DEBUG_IN_THREAD_CONTEXT;

    /* get current thread 获取当前的线程*/
    thread = rt_thread_self();

    /* disable interrupt 临界区 */
    temp = rt_hw_interrupt_disable();

    /* reset thread error */
    thread->error = RT_EOK;
	//看一下是不是一个线程的重复上锁
    if (mutex->owner == thread)
    {
        /* it's the same thread 是的*/
        mutex->hold ++;
    }
    else
    {
__again:
        /* The value of mutex is 1 in initial status. Therefore, if the
         * value is great than 0, it indicates the mutex is avaible.
         */
        if (mutex->value > 0)
        {
            //这是第一次上锁是可以获取的状态
            /* mutex is available */
            mutex->value --;

            /* set mutex owner and original priority 记录一下这个线程的优先级 */
            mutex->owner             = thread;
            mutex->original_priority = thread->current_priority;
            mutex->hold ++;
        }
        else
        {
            /* no waiting, return with timeout 这个互斥量已经被拥有了 */
            if (time == 0)
            {
                //不需要等待
                /* set error as timeout */
                thread->error = -RT_ETIMEOUT;

                /* enable interrupt */
                rt_hw_interrupt_enable(temp);

                return -RT_ETIMEOUT;
            }
            else
            {
                //等待这线互斥量被释放
                /* mutex is unavailable, push to suspend list */
                RT_DEBUG_LOG(RT_DEBUG_IPC, ("mutex_take: suspend thread: %s\n",
                                            thread->name));
				//调整一下优先级, 以防被优先级反转
                /* change the owner thread priority of mutex */
                if (thread->current_priority < mutex->owner->current_priority)
                {
                    //持有者的优先级比较低, 需要进行升级
                    /* change the owner thread priority */
                    rt_thread_control(mutex->owner,
                                      RT_THREAD_CTRL_CHANGE_PRIORITY,
                                      &thread->current_priority);
                }

                /* suspend current thread 把这一个线程归入挂起的队列里面(按互斥量的获取规则) */
                rt_ipc_list_suspend(&(mutex->parent.suspend_thread),
                                    thread,
                                    mutex->parent.parent.flag);

                /* has waiting time, start thread timer 使能这一个线程的时钟用于唤醒 */
                if (time > 0)
                {
                    RT_DEBUG_LOG(RT_DEBUG_IPC,
                                 ("mutex_take: start the timer of thread:%s\n",
                                  thread->name));

                    /* reset the timeout of thread timer and start it */
                    rt_timer_control(&(thread->thread_timer),
                                     RT_TIMER_CTRL_SET_TIME,
                                     &time);
                    rt_timer_start(&(thread->thread_timer));
                }

                /* enable interrupt */
                rt_hw_interrupt_enable(temp);

                /* do schedule 开启任务切换 */
                rt_schedule();
				//这个时候以及获取到或者失败
                if (thread->error != RT_EOK)
                {
                    //失败了
                    /* interrupt by signal, try it again */
                    if (thread->error == -RT_EINTR) goto __again;//这一个分支是使用信号
                    										 //机制打断的时候的处理

                    /* return error */
                    return thread->error;
                }
                else
                {
                    /* the mutex is taken successfully. */
                    /* disable interrupt */
                    temp = rt_hw_interrupt_disable();
                }
            }
        }
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mutex->parent.parent)));

    return RT_EOK;
}

释放

rt_err_t rt_mutex_release(rt_mutex_t mutex)
{
    register rt_base_t temp;
    struct rt_thread *thread;
    rt_bool_t need_schedule;

    need_schedule = RT_FALSE;

    /* only thread could release mutex because we need test the ownership 
    不可以在中断里面使用 */
    RT_DEBUG_IN_THREAD_CONTEXT;

    /* get current thread */
    thread = rt_thread_self();

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();

    RT_DEBUG_LOG(RT_DEBUG_IPC,
                 ("mutex_release:current thread %s, mutex value: %d, hold: %d\n",
                  thread->name, mutex->value, mutex->hold));

    RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mutex->parent.parent)));

    /* mutex only can be released by owner 只有拥有这一个互斥量的线程可以释放它 */
    if (thread != mutex->owner)
    {
        //没有释放的权利
        thread->error = -RT_ERROR;

        /* enable interrupt */
        rt_hw_interrupt_enable(temp);

        return -RT_ERROR;
    }

    /* decrease hold */
    mutex->hold --;
    /* if no hold */
    if (mutex->hold == 0)
    {
        //这是最后一层的释放
        /* change the owner thread to original priority */
        if (mutex->original_priority != mutex->owner->current_priority)
        {
            rt_thread_control(mutex->owner,
                              RT_THREAD_CTRL_CHANGE_PRIORITY,
                              &(mutex->original_priority));
        }

        /* wakeup suspended thread 看一看有没有在等待的线程 */
        if (!rt_list_isempty(&mutex->parent.suspend_thread))
        {
            /* get suspended thread 获取一下下一个等待的线程 */
            thread = rt_list_entry(mutex->parent.suspend_thread.next,
                                   struct rt_thread,
                                   tlist);

            RT_DEBUG_LOG(RT_DEBUG_IPC, ("mutex_release: resume thread: %s\n",
                                        thread->name));

            /* set new owner and priority 记录信息 */
            mutex->owner             = thread;
            mutex->original_priority = thread->current_priority;
            mutex->hold ++;

            /* resume thread 把这一个线程从等待队列里面取出来以及关闭时钟, 前面有分析 */
            rt_ipc_list_resume(&(mutex->parent.suspend_thread));

            need_schedule = RT_TRUE;
        }
        else
        {
            //最外层并且没有在等待的线程
            //设置为空闲的状态
            /* increase value */
            mutex->value ++;

            /* clear owner */
            mutex->owner             = RT_NULL;
            mutex->original_priority = 0xff;
        }
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    /* perform a schedule */
    if (need_schedule == RT_TRUE)
        rt_schedule();

    return RT_EOK;
}

事件集

struct rt_event
{
    struct rt_ipc_object parent;                        /**< inherit from ipc_object */

    rt_uint32_t          set;                           /**< event set 
    												记录事件, 每一bit表示1个事件 */
};

创建以及释放和上面基本一样–略

发送事件

rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set)
{
    struct rt_list_node *n;
    struct rt_thread *thread;
    register rt_ubase_t level;
    register rt_base_t status;
    rt_bool_t need_schedule;

    if (set == 0)//没有要发送的事件
        return -RT_ERROR;

    need_schedule = RT_FALSE;

    /* disable interrupt 临界区 */
    level = rt_hw_interrupt_disable();

    /* set event 设置一下对应的位 */
    event->set |= set;

    if (!rt_list_isempty(&event->parent.suspend_thread))
    {
        //这个队列里面有在等待的事件, 遍历一遍看一看有没有可以释放的
        /* search thread list to resume thread */
        n = event->parent.suspend_thread.next;
        while (n != &(event->parent.suspend_thread))
        {
            /* get thread */
            thread = rt_list_entry(n, struct rt_thread, tlist);

            status = -RT_ERROR;//记录一下可不可以释放
            if (thread->event_info & RT_EVENT_FLAG_AND)
            {
                //使用AND的方式比较
                if ((thread->event_set & event->set) == thread->event_set)
                {
                    /* received an AND event */
                    status = RT_EOK;
                }
            }
            else if (thread->event_info & RT_EVENT_FLAG_OR)
            {
                //使用OR的方式进行比较
                if (thread->event_set & event->set)
                {
                    /* save the received event set 传递一下当前的事件 */
                    thread->event_set = thread->event_set & event->set;

                    /* received an OR event */
                    status = RT_EOK;
                }
            }

            /* move node to the next 下一个链表记录一下*/
            n = n->next;

            /* condition is satisfied, resume thread */
            if (status == RT_EOK)
            {
                //需要释放这一个任务
                /* clear event */
                if (thread->event_info & RT_EVENT_FLAG_CLEAR)
                    event->set &= ~thread->event_set;//需要清除这一个事件

                /* resume thread, and thread list breaks out 释放这一个任务 */
                rt_thread_resume(thread);

                /* need do a scheduling 记录一下需要进行任务切换 */
                need_schedule = RT_TRUE;
            }
        }
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(level);

    /* do a schedule */
    if (need_schedule == RT_TRUE)
        rt_schedule();

    return RT_EOK;
}

接收事件

rt_err_t rt_event_recv(rt_event_t   event,
                       rt_uint32_t  set,
                       rt_uint8_t   option,
                       rt_int32_t   timeout,
                       rt_uint32_t *recved)
{
    struct rt_thread *thread;
    register rt_ubase_t level;
    register rt_base_t status;

    if (set == 0)//没有等待的事件
        return -RT_ERROR;

    /* initialize status */
    status = -RT_ERROR;
    /* get current thread 获取当前的任务 */
    thread = rt_thread_self();
    /* reset thread error */
    thread->error = RT_EOK;

    /* disable interrupt 临界区 */
    level = rt_hw_interrupt_disable();

    /* check event set 看一看这一个事件是不是已经达成了 */
    if (option & RT_EVENT_FLAG_AND)
    {
        if ((event->set & set) == set)
            status = RT_EOK;
    }
    else if (option & RT_EVENT_FLAG_OR)
    {
        if (event->set & set)
            status = RT_EOK;
    }
    else
    {
        /* either RT_EVENT_FLAG_AND or RT_EVENT_FLAG_OR should be set */
        RT_ASSERT(0);
    }

    if (status == RT_EOK)
    {
        //这个事件已经实现了, 记录一下当前的情况
        /* set received event */
        if (recved)
            *recved = (event->set & set);

        /* received event */
        if (option & RT_EVENT_FLAG_CLEAR)//需要清除标志位
            event->set &= ~set;
    }
    else if (timeout == 0)
    {
        //事件没有达成, 但是不等待
        /* no waiting */
        thread->error = -RT_ETIMEOUT;
    }
    else
    {
        /* fill thread event info */
        thread->event_set  = set;
        thread->event_info = option;

        /* put thread to suspended thread list 把这一个任务挂起 */
        rt_ipc_list_suspend(&(event->parent.suspend_thread),
                            thread,
                            event->parent.parent.flag);

        /* if there is a waiting timeout, active thread timer 使用时钟进行唤醒 */
        if (timeout > 0)
        {
            /* reset the timeout of thread timer and start it */
            rt_timer_control(&(thread->thread_timer),
                             RT_TIMER_CTRL_SET_TIME,
                             &timeout);
            rt_timer_start(&(thread->thread_timer));
        }

        /* enable interrupt */
        rt_hw_interrupt_enable(level);

        /* do a schedule 任务切换 */
        rt_schedule();
		//这时候获取到事件或者时间到了
        if (thread->error != RT_EOK)
        {
            //出错了(比如超时)
            /* return error */
            return thread->error;
        }

        /* received an event, disable interrupt to protect */
        level = rt_hw_interrupt_disable();

        /* set received event */
        if (recved)//记录一下当前的事件
            *recved = thread->event_set;
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(level);

    return thread->error;
}

你可能感兴趣的:(stm32,单片机,mcu,c语言,笔记)