lwIPのソースコードを読んでます。
lwIPは最近人気の軽量TCP/IPプロトコルスタック です。
対象バージョンはよく使われている 1.41 にしました。 (ESP8266のSDK, mbed, Realtek ameba で使われている)
まずはメインループを見てみました。
lwIPのメインループ
- src/api/tcpip.c の tcpip_thread()にメインループがあります。
- http://git.savannah.gnu.org/cgit/lwip.git/tree/src/api/tcpip.c?h=DEVEL-1_4_1
tcpip.c
static void
tcpip_thread(void *arg)
{
struct tcpip_msg *msg;
LWIP_UNUSED_ARG(arg);
- 初期化チェックです。 tcpip_thread()の前に、初期化を実行することを期待しています。
tcpip.c
if (tcpip_init_done != NULL) {
tcpip_init_done(tcpip_init_done_arg);
}
LOCK_TCPIP_CORE();
- メインループです。
- sys_timeouts_mbox_ftech()でメッセージを取り出して、API、IPパケット、タイムアウト、コールバックの処理をします。
tcpip.c
while (1) { /* MAIN Loop */
UNLOCK_TCPIP_CORE();
LWIP_TCPIP_THREAD_ALIVE();
/* wait for a message, timeouts are processed while waiting */
sys_timeouts_mbox_fetch(&mbox, (void **)&msg);
LOCK_TCPIP_CORE();
switch (msg->type) {
#if LWIP_NETCONN
case TCPIP_MSG_API:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
break;
#endif /* LWIP_NETCONN */
#if !LWIP_TCPIP_CORE_LOCKING_INPUT
case TCPIP_MSG_INPKT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
#if LWIP_ETHERNET
if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
} else
#endif /* LWIP_ETHERNET */
{
ip_input(msg->msg.inp.p, msg->msg.inp.netif);
}
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
break;
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
#if LWIP_NETIF_API
case TCPIP_MSG_NETIFAPI:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));
msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));
break;
#endif /* LWIP_NETIF_API */
#if LWIP_TCPIP_TIMEOUT
case TCPIP_MSG_TIMEOUT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
case TCPIP_MSG_UNTIMEOUT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg));
sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
#endif /* LWIP_TCPIP_TIMEOUT */
case TCPIP_MSG_CALLBACK:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
msg->msg.cb.function(msg->msg.cb.ctx);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
case TCPIP_MSG_CALLBACK_STATIC:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg));
msg->msg.cb.function(msg->msg.cb.ctx);
break;
default:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
LWIP_ASSERT("tcpip_thread: invalid message", 0);
break;
}
}
}
- LOCK_TCPIP_COREとUNLOCK_TCPIP_CORE は src/include/lwip/tcpip.hで定義してます。排他制御するか、しないかを設定できます。できれば、排他制御した方がよいです。
tcpip.h
#if LWIP_TCPIP_CORE_LOCKING
/** The global semaphore to lock the stack. */
extern sys_mutex_t lock_tcpip_core;
#define LOCK_TCPIP_CORE() sys_mutex_lock(&lock_tcpip_core)
#define UNLOCK_TCPIP_CORE() sys_mutex_unlock(&lock_tcpip_core)
...
#else /* LWIP_TCPIP_CORE_LOCKING */
#define LOCK_TCPIP_CORE()
#define UNLOCK_TCPIP_CORE()
...
#endif /* LWIP_TCPIP_CORE_LOCKING */
- 2.0のメインループはもっとすっきりしてます。 http://git.savannah.gnu.org/cgit/lwip.git/tree/src/api/tcpip.c?h=DEVEL