使用看上一篇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;
}