api_lib.c,其中包含了所有的netconn API实现,应用若使用netconn,只需要包含api.h即可。
api_msg.c,其中为与tcpip主线程进行消息交互的消息处理。
以netconn_new为例,api.h中定义如下
1 #define netconn_new(t) netconn_new_with_proto_and_callback(t, 0, NULL)
会发送一个api_msg给tcpip主线程,api_msg.c中定义如下
1 struct netconn* 2 netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback) 3 { 4 struct netconn *conn; 5 struct api_msg msg; 6 7 conn = netconn_alloc(t, callback); 8 if (conn != NULL) { 9 msg.function = do_newconn; 10 msg.msg.msg.n.proto = proto; 11 msg.msg.conn = conn; 12 if (TCPIP_APIMSG(&msg) != ERR_OK) { 19 sys_sem_free(&conn->op_completed); 20 sys_mbox_free(&conn->recvmbox); 21 memp_free(MEMP_NETCONN, conn); 22 return NULL; 23 } 24 } 25 return conn; 26 }
其中,tcpip.h中定义如下
1 #define TCPIP_APIMSG(m) tcpip_apimsg(m)
tcpip.c中定义如下,实际,会将消息发送给tcpip主线程的邮箱mbox,且一直等待完成(通过等待信号量op_completed实现,在do_xxx函数中会调用TCPIP_APIMSG_ACK(msg),该函数就是释放该信号量)。
1 err_t 2 tcpip_apimsg(struct api_msg *apimsg) 3 { 4 struct tcpip_msg msg; 10 if (sys_mbox_valid(&mbox)) { 11 msg.type = TCPIP_MSG_API; 12 msg.msg.apimsg = apimsg; 13 sys_mbox_post(&mbox, &msg); 14 sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0); 15 return apimsg->msg.err; 16 } 17 return ERR_VAL; 18 }
tcpip主线程中,会一直查询邮箱mbox。第8行,一直查询mbox,第14行,执行消息的函数,这里其实执行的是do_newconn
1 static void 2 tcpip_thread(void *arg) 3 { 4 struct tcpip_msg *msg; 5 6 while (1) { /* MAIN Loop */ 7 /* wait for a message, timeouts are processed while waiting */ 8 sys_timeouts_mbox_fetch(&mbox, (void **)&msg); 9 LOCK_TCPIP_CORE(); 10 switch (msg->type) { 11 #if LWIP_NETCONN 12 case TCPIP_MSG_API: 13 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg)); 14 msg->msg.apimsg->function(&(msg->msg.apimsg->msg)); 15 break; 16 #endif /* LWIP_NETCONN */ 17 18 #if !LWIP_TCPIP_CORE_LOCKING_INPUT 19 case TCPIP_MSG_INPKT: 20 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg)); 21 #if LWIP_ETHERNET 22 if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { 23 ethernet_input(msg->msg.inp.p, msg->msg.inp.netif); 24 } else 25 #endif /* LWIP_ETHERNET */ 26 { 27 ip_input(msg->msg.inp.p, msg->msg.inp.netif); 28 } 29 memp_free(MEMP_TCPIP_MSG_INPKT, msg); 30 break; 31 #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ 32 33 case TCPIP_MSG_CALLBACK: 34 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg)); 35 msg->msg.cb.function(msg->msg.cb.ctx); 36 memp_free(MEMP_TCPIP_MSG_API, msg); 37 break; 38 39 default: 40 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type)); 41 LWIP_ASSERT("tcpip_thread: invalid message", 0); 42 break; 43 } 44 } 45 }
api_msg.c中的do_newconn,执行pcb_new()函数,创建pcb协议控制块,在其中,会根据是udp还是tcp等,创建相应的pcb。
1 void 2 do_newconn(struct api_msg_msg *msg) 3 { 4 msg->err = ERR_OK; 5 if(msg->conn->pcb.tcp == NULL) { 6 pcb_new(msg); 7 }
下图为netconn_new()函数对应的两个线程中的函数,及中间沟通的邮箱(消息队列mbox)。只有两个线程,所有函数都在其中一个线程的上下文中执行。
下图为接收数据的过程,涉及3个线程:接收线程,tcpip主线程,和应用线程。使用了两个消息队列用于传递消息。有3个线程,所有函数都在其中一个线程的上下文中执行。
对于tcpip.c
tcpip_init()会创建mbox邮箱。
tcpip_thread()会接收mbox,并处理。
tcpip_input()是所有netif的input函数,在其中创建msg,然后发送到mbox。