sys.c:系统抽象层,其中会调用和os相关的部分,如sys_arch_timeouts, sys_arch_mbox_fetch等,在lwip中是以sys_arch_命名开头的,
"为了方便 LwIP 移植,属于操作系统的函数调用及数据结构并没有在代码中直接使用,
而是用操作系统模拟层来代替对这些函数的使用。操作系统模拟层使用统一的接口提供定时器、进程同步及消息传递机制等诸如此类的系统服务。原则上,移植 LwIP ,只需针对目标 操作系统修改模拟层实现即可。
TCP 用到的定时器功能由操作系统模拟层提供。这个定时器是一个时间间隔至少为 200ms 的单脉冲定时器(one-shot timer,单脉冲定时器,指的是当时钟启动时,它把存储寄存器的值复 制到计数器中,然后晶体的每一个脉冲使计数器减 1。减至 0 时,产生一个中断,并停止工作,直至软件 重新启动它,译者注),当时间溢出发生时就会调用一个已注册的函数。
进程同步机制仅提供了信号量。即使信号量不被底层的操作系统支持也可以使用其它基 本的同步方式来模拟,比如条件变量或者加锁。
消息传递通过一个简单机制来实现,它使用一个被称作邮箱的抽象方法。邮箱有两种操 作:邮递(post )与提取(fetch ),邮递操作不会阻塞进程;相反,投递到邮箱的消息被操 作系统模拟层放到队列中直至其它进程将它们取出。即使底层的操作系统本身并不支持邮箱 机制,采用信号量的方式也是很容易实现的。"
/* BEGIN: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
/* 获取lwip进程定时器链表,需要移植 */
/* END: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
struct sys_timeouts *sys_arch_timeouts(void);
/**
* Create a one-shot timer (aka timeout). Timeouts are processed in the
* following cases:
* - while waiting for a message using sys_mbox_fetch()
* - while waiting for a semaphore using sys_sem_wait() or sys_sem_wait_timeout()
* - while sleeping using the inbuilt sys_msleep()
*
* @param msecs time in milliseconds after that the timer should expire
* @param h callback function to call when msecs have elapsed
* @param arg argument to pass to the callback function
*/
/* BEGIN: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
/* lwip进程中创建定时器,被arp_timer igmp_timer等调用 */
/* END: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
void
sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
{
struct sys_timeouts *timeouts;
struct sys_timeo *timeout, *t;
timeout = memp_malloc(MEMP_SYS_TIMEOUT);
if (timeout == NULL) {
LWIP_ASSERT("sys_timeout: timeout != NULL", timeout != NULL);
return;
}
timeout->next = NULL;
timeout->h = h;
timeout->arg = arg;
timeout->time = msecs;
/* BEGIN: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
/* 获取lwip进程定时器链表 */
/* END: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
timeouts = sys_arch_timeouts();
LWIP_DEBUGF(SYS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n",
(void *)timeout, msecs, *(void**)&h, (void *)arg));
if (timeouts == NULL) {
LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL);
return;
}
if (timeouts->next == NULL) {
timeouts->next = timeout;
return;
}
/* BEGIN: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
/* 将此次timeout定时器加入lwip进程定时器链 */
/* END: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
if (timeouts->next->time > msecs) {
timeouts->next->time -= msecs;
timeout->next = timeouts->next;
timeouts->next = timeout;
} else {
for(t = timeouts->next; t != NULL; t = t->next) {
timeout->time -= t->time;
if (t->next == NULL || t->next->time > timeout->time) {
if (t->next != NULL) {
t->next->time -= timeout->time;
}
timeout->next = t->next;
t->next = timeout;
break;
}
}
}
}
/**
* Go through timeout list (for this task only) and remove the first matching
* entry, even though the timeout has not triggered yet.
*
* @note This function only works as expected if there is only one timeout
* calling 'h' in the list of timeouts.
*
* @param h callback function that would be called by the timeout
* @param arg callback argument that would be passed to h
*/
/* BEGIN: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
/* 将h和arg匹配的定时器删除 */
/* END: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
sys_untimeout(sys_timeout_handler h, void *arg)
{
struct sys_timeouts *timeouts;
struct sys_timeo *prev_t, *t;
timeouts = sys_arch_timeouts();
if (timeouts == NULL) {
LWIP_ASSERT("sys_untimeout: timeouts != NULL", timeouts != NULL);
return;
}
if (timeouts->next == NULL) {
return;
}
for (t = timeouts->next, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
if ((t->h == h) && (t->arg == arg)) {
/* We have a match */
/* Unlink from previous in list */
if (prev_t == NULL) {
timeouts->next = t->next;
} else {
prev_t->next = t->next;
}
/* If not the last one, add time of this one back to next */
if (t->next != NULL) {
t->next->time += t->time;
}
memp_free(MEMP_SYS_TIMEOUT, t);
return;
}
}
return;
}
/**
* Wait (forever) for a semaphore to become available.
* While waiting, timeouts (for this thread) are processed.
*
* @param sem semaphore to wait for
*/
/* BEGIN: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
/* forever的等待一个semaphore,在等待过程中,lwip进程上的定时器会被刷新 */
/* END: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
void
sys_sem_wait(sys_sem_t sem)
{
u32_t time_needed;
struct sys_timeouts *timeouts;
struct sys_timeo *tmptimeout;
sys_timeout_handler h;
void *arg;
again:
timeouts = sys_arch_timeouts();
/* BEGIN: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
/* 如果lwip进程没有定时器,则sys_arch_sem_wait(sem, 0)中的参数为0,一直等待这个信号量 */
/* END: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
if (!timeouts || !timeouts->next) {
sys_arch_sem_wait(sem, 0);
} else {
/* BEGIN: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
/* 否则找到最小的一个定时器时间,以此为超时参数,调用sys_arch_sem_wait */
/* END: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
if (timeouts->next->time > 0) {
/* BEGIN: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
/* time_needed:表明获得这个信号量需要的时间 */
/* END: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
time_needed = sys_arch_sem_wait(sem, timeouts->next->time);
} else {
time_needed = SYS_ARCH_TIMEOUT;
}
/* BEGIN: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
/* SYS_ARCH_TIMEOUT表明在指定时间未获得信号量,说明未从邮箱获得报文,继续等待(forever的缘由) */
/* END: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
if (time_needed == SYS_ARCH_TIMEOUT) {
/* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
could be fetched. We should now call the timeout handler and
deallocate the memory allocated for the timeout. */
tmptimeout = timeouts->next;
timeouts->next = tmptimeout->next;
h = tmptimeout->h;
arg = tmptimeout->arg;
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
if (h != NULL) {
LWIP_DEBUGF(SYS_DEBUG, ("ssw h=%p(%p)\n", *(void**)&h, (void *)arg));
h(arg);
}
/* We try again to fetch a message from the mbox. */
goto again;
} else {
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
occured. The time variable is set to the number of
milliseconds we waited for the message. */
/* BEGIN: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
/* 若在超时之前获得信号量,则刷新定时器链表下一个时间 */
/* ?:这里有一个问题,为什么刷新的只是链中第一个定时器的时间呢,其它的不用刷新吗?contact me:[email protected] */
/* END: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
if (time_needed < timeouts->next->time) {
timeouts->next->time -= time_needed;
} else {
timeouts->next->time = 0;
}
}
}
}
/**
* Wait for a semaphore with timeout (specified in ms)
*
* @param sem semaphore to wait
* @param timeout timeout in ms (0: wait forever)
* @return 0 on timeout, 1 otherwise
*/
/* BEGIN: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
/* 带有超时的信号量等待函数 */
/* END: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
int
sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout)
{
struct sswt_cb sswt_cb;
sswt_cb.psem = &sem;
sswt_cb.timeflag = 0;
/* If timeout is zero, then just wait forever */
/* BEGIN: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
/* 为了实现超时,调用sys_timeout向lwip进程加入一个定时器 */
/* END: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
if (timeout > 0) {
/* Create a timer and pass it the address of our flag */
sys_timeout(timeout, sswt_handler, &sswt_cb);
}
/* BEGIN: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
/* 由于sswt_handler实现中,若超时则释放信号量,所以调用sys_sem_wait肯定不会forever的等待 */
/* END: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
sys_sem_wait(sem);
/* Was it a timeout? */
if (sswt_cb.timeflag) {
/* timeout */
return 0;
} else {
/* Not a timeout. Remove timeout entry */
sys_untimeout(sswt_handler, &sswt_cb);
return 1;
}
}
/**
* Timeout handler function for sys_sem_wait_timeout()
*
* @param arg struct sswt_cb* used to signal a semaphore and end waiting.
*/
/* BEGIN: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
/* 超时的时候发送一个信号量 */
/* END: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
static void
sswt_handler(void *arg)
{
struct sswt_cb *sswt_cb = (struct sswt_cb *) arg;
/* Timeout. Set flag to TRUE and signal semaphore */
sswt_cb->timeflag = 1;
sys_sem_signal(*(sswt_cb->psem));
}
/**
* Sleep for some ms. Timeouts are processed while sleeping.
*
* @param ms number of milliseconds to sleep
*/
/* BEGIN: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
/* 等待some ms,在其中定义一个临时信号量,并调用sys_sem_wait_timeout来实现等待 */
/* END: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
void
sys_msleep(u32_t ms)
{
sys_sem_t delaysem = sys_sem_new(0);
sys_sem_wait_timeout(delaysem, ms);
sys_sem_free(delaysem);
}
/**
* Wait (forever) for a message to arrive in an mbox.
* While waiting, timeouts (for this thread) are processed.
*
* @param mbox the mbox to fetch the message from
* @param msg the place to store the message
*/
/* BEGIN: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
/* forever的在邮箱中等待一个message,在等待过程中lwip进程的定时器会被刷新 */
/* END: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
void
sys_mbox_fetch(sys_mbox_t mbox, void **msg)
{
u32_t time_needed;
struct sys_timeouts *timeouts;
struct sys_timeo *tmptimeout;
sys_timeout_handler h;
void *arg;
again:
timeouts = sys_arch_timeouts();
if (!timeouts || !timeouts->next) {
UNLOCK_TCPIP_CORE();
/* BEGIN: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
/* 参数为0,永远等待邮箱中有message */
/* END: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
time_needed = sys_arch_mbox_fetch(mbox, msg, 0);
LOCK_TCPIP_CORE();
} else {
if (timeouts->next->time > 0) {
UNLOCK_TCPIP_CORE();
/* BEGIN: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
/* 选用lwip进程下的第一个定时器(时间最小)作为参数,定时等待邮箱 */
/* END: Added by zhengxiang, 2013/10/2 PN:lwip_comment */
time_needed = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time);
LOCK_TCPIP_CORE();
} else {
time_needed = SYS_ARCH_TIMEOUT;
}
if (time_needed == SYS_ARCH_TIMEOUT) {
/* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
could be fetched. We should now call the timeout handler and
deallocate the memory allocated for the timeout. */
tmptimeout = timeouts->next;
timeouts->next = tmptimeout->next;
h = tmptimeout->h;
arg = tmptimeout->arg;
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
if (h != NULL) {
LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", *(void**)&h, arg));
h(arg);
}
/* We try again to fetch a message from the mbox. */
goto again;
} else {
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
occured. The time variable is set to the number of
milliseconds we waited for the message. */
if (time_needed < timeouts->next->time) {
timeouts->next->time -= time_needed;
} else {
timeouts->next->time = 0;
}
}
}
}