数据结构
typedef struct smc_sem {
smc_list_head_t slist; /* Thread that is suspended for waiting for a semaphore */
smc_uint16_t value; /* semaphore value */
} smc_sem_t;
操作函数
对sem的操作主要是初始化、获取、释放。
void smc_sem_init(smc_sem_t *sem, smc_uint16_t value);/*sem的初始化*/
smc_int32_t smc_sem_pend(smc_sem_t *sem, smc_int32_t time_out);/*sem的获取*/
smc_int32_t smc_sem_release(smc_sem_t *sem);/*sem的释放*/
在SMC-RTOS中,一些接口函数的实现相对于ucosii来说是十分简洁的,比如在获取信号量时候分阻塞式和非阻塞式,ucosii实现了将阻塞式和非阻塞式两个接口,在SMC-RTOS中则十分简洁,只用了一个接口,通过传参的方式来实现阻塞式和非阻塞式获取信号量。
- 初始化
void smc_sem_init(smc_sem_t *sem, smc_uint16_t value)
{
smc_list_node_init(&sem->slist);/*初始化被sem阻塞的链表,实际就是将前后节点指针指向自己*/
sem->value = value;/*sem的本质还是个计数类型的数据,初始化sem的value*/
}
- 获取
smc_int32_t smc_sem_pend(smc_sem_t *sem, smc_int32_t time_out)
{
smc_uint32_t status;
/* disable interrupt */
status = smc_cpu_disable_interrupt();
if (sem->value > 0) {/* 如果信号量的值大于0,不管阻塞式还是非阻塞式,将sem->value减一即可返回 */
sem->value--;
/* enable interrupt */
smc_cpu_enable_interrupt(status);
} else {
if (time_out == SMC_SEM_NO_WAIT) {/* 如果信号量的值小于0,且是非阻塞式的获取,立即返回获取失败*/
smc_cpu_enable_interrupt(status);
return -SMC_TIMEOUT;
} else {/* 如果信号量的值小于0,且是阻塞式的获取,就先要将本thread挂起,并设置超时时间,然后将本thread添加到sem的rlist等待信号量的链表中,然后触发一次schedule(如果到了超时时间也没有信号量可以获取,就会返回获取失败,在没有到超时时间前就有信号量可以获取的话,就会返回成功)*/
/* reset thread error number */
smc_thread_current->error_num = SMC_OK;
/* suspend the current thread and do schedule */
smc_thread_suspend(smc_thread_current);/*将本任务挂起*/
if (time_out != SMC_SEM_WAIT_FOREVER) {/*设置超时时间*/
smc_uint8_t flag = SMC_TIMER_ONCE;
/* set timer timeout tick */
smc_timer_command(&smc_thread_current->timer,
SMC_TIMER_SET_TIMEOUT_TICK_IMMEDIATELY,
&time_out);
/* set timer flag */
smc_timer_command(&smc_thread_current->timer,
SMC_TIMER_SET_OPERATION_MODE,
&flag);
/* timer startup */
smc_timer_enable(&smc_thread_current->timer);
}
/* add the current thread to semaphore list */
smc_list_add(&smc_thread_current->rlist, &sem->slist);/*将本thread添加到sem->rlist等待链表中去*/
smc_scheduler();
/* enable interrupt, and will make contex switch */
smc_cpu_enable_interrupt(status);
if (smc_thread_current->error_num != SMC_OK)
return smc_thread_current->error_num;
}
}
return SMC_OK;
}
- 释放
smc_int32_t smc_sem_release(smc_sem_t *sem)
{
smc_uint32_t status;
/* disable interrupt */
status = smc_cpu_disable_interrupt();
/*根据sem->slist的等待链表是否为空决定是唤醒一个任务还是释放信号量给sem->value自加1*/
if (!smc_list_is_empty(&sem->slist)) {/*如果sem_rlist为空就resume他头节点指向的thread,先来后到,ucosii是resume等待队列中优先级最高的thread*/
smc_thread_t *thread;
thread = smc_list_entry(sem->slist.next, smc_thread_t, rlist);
/**
* resume the first thread in the pending thread list waiting for
* the special semaphore.
*/
smc_thread_resume(thread);
} else {
sem->value++;
}
/* enable interrupt */
smc_cpu_enable_interrupt(status);
return SMC_OK;
}
所有关于sem的源代码就这么多,其中没有实现防止信号量翻转的功能,下一步我会去实现这个功能,这部分之后再补充。
还有就是在释放信号量的时候是根据等待队列中哪个thread先申请信号量就唤醒哪个thread,还是唤醒等待队列中优先级最高的thread…没有定论吧,下面想实现两个可以供用户通过宏开关选择的接口。后续补充