源码分析
使用看上一篇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;}elsesem->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 holdthe mutex 持有的线程的原优先级*/rt_uint8_t hold; /**< numbers of thread hold themutex 持有线程的持有次数*/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;
}