LWIP_NETCONN_FULLDUPLEX: unblock rx threads on close

Threads blocked on the rx mbox are counted and on close,
one "netconn closed" message per thread is posted to the mbox
to ensure all threads are woken.

The netconn can then be safely deleted. In socket API, "fd_used"
and "fd_free_pending" help with auto-deleting the netconn.

Signed-off-by: goldsimon <goldsimon@gmx.de>
This commit is contained in:
goldsimon
2018-04-18 21:51:34 +02:00
parent 41fea4ad7d
commit 3abc8ae161
4 changed files with 98 additions and 23 deletions

View File

@@ -92,6 +92,19 @@ static void netconn_drain(struct netconn *conn);
#define TCPIP_APIMSG_ACK(m) do { sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0)
#endif /* LWIP_TCPIP_CORE_LOCKING */
#if LWIP_NETCONN_FULLDUPLEX
const u8_t netconn_deleted = 0;
int
lwip_netconn_is_deallocated_msg(void *msg)
{
if (msg == &netconn_deleted) {
return 1;
}
return 0;
}
#endif /* LWIP_NETCONN_FULLDUPLEX */
#if LWIP_TCP
const u8_t netconn_aborted = 0;
const u8_t netconn_reset = 0;
@@ -823,16 +836,21 @@ netconn_drain(struct netconn *conn)
/* Delete and drain the recvmbox. */
if (sys_mbox_valid(&conn->recvmbox)) {
while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
#if LWIP_TCP
if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
err_t err;
if (!lwip_netconn_is_err_msg(mem, &err)) {
pbuf_free((struct pbuf *)mem);
}
} else
#endif /* LWIP_TCP */
#if LWIP_NETCONN_FULLDUPLEX
if (!lwip_netconn_is_deallocated_msg(mem))
#endif /* LWIP_NETCONN_FULLDUPLEX */
{
netbuf_delete((struct netbuf *)mem);
#if LWIP_TCP
if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
err_t err;
if (!lwip_netconn_is_err_msg(mem, &err)) {
pbuf_free((struct pbuf *)mem);
}
} else
#endif /* LWIP_TCP */
{
netbuf_delete((struct netbuf *)mem);
}
}
}
sys_mbox_free(&conn->recvmbox);
@@ -843,18 +861,23 @@ netconn_drain(struct netconn *conn)
#if LWIP_TCP
if (sys_mbox_valid(&conn->acceptmbox)) {
while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
err_t err;
if (!lwip_netconn_is_err_msg(mem, &err)) {
struct netconn *newconn = (struct netconn *)mem;
/* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
/* pcb might be set to NULL already by err_tcp() */
/* drain recvmbox */
netconn_drain(newconn);
if (newconn->pcb.tcp != NULL) {
tcp_abort(newconn->pcb.tcp);
newconn->pcb.tcp = NULL;
#if LWIP_NETCONN_FULLDUPLEX
if (!lwip_netconn_is_deallocated_msg(mem))
#endif /* LWIP_NETCONN_FULLDUPLEX */
{
err_t err;
if (!lwip_netconn_is_err_msg(mem, &err)) {
struct netconn *newconn = (struct netconn *)mem;
/* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
/* pcb might be set to NULL already by err_tcp() */
/* drain recvmbox */
netconn_drain(newconn);
if (newconn->pcb.tcp != NULL) {
tcp_abort(newconn->pcb.tcp);
newconn->pcb.tcp = NULL;
}
netconn_free(newconn);
}
netconn_free(newconn);
}
}
sys_mbox_free(&conn->acceptmbox);
@@ -867,8 +890,20 @@ netconn_drain(struct netconn *conn)
static void
netconn_mark_mbox_invalid(struct netconn *conn)
{
int i, num_waiting;
void *msg = LWIP_CONST_CAST(void *, &netconn_deleted);
/* Prevent new calls/threads from reading from the mbox */
conn->flags |= NETCONN_FLAG_MBOXINVALID;
SYS_ARCH_LOCKED(num_waiting = conn->mbox_threads_waiting);
for (i = 0; i < num_waiting; i++) {
if (sys_mbox_valid_val(conn->recvmbox)) {
sys_mbox_trypost(&conn->recvmbox, msg);
} else {
sys_mbox_trypost(&conn->acceptmbox, msg);
}
}
}
#endif /* LWIP_NETCONN_FULLDUPLEX */