added option LWIP_NETCONN_SEM_PER_THREAD to use a semaphore per thread instead of using one per netconn and per select call

This commit is contained in:
sg 2014-12-10 20:45:01 +01:00
parent 35729f0870
commit cacdbb5262
10 changed files with 187 additions and 48 deletions

View File

@ -6,6 +6,10 @@ HISTORY
++ New features: ++ New features:
2014-12-10: Simon Goldschmidt
* api: added option LWIP_NETCONN_SEM_PER_THREAD to use a semaphore per thread
instead of using one per netconn and per select call
2014-12-08: Simon Goldschmidt 2014-12-08: Simon Goldschmidt
* ip6.h: fixed bug #43778: IPv6 header version not set on 16-bit platform * ip6.h: fixed bug #43778: IPv6 header version not set on 16-bit platform
(macro IP6H_VTCFL_SET()) (macro IP6H_VTCFL_SET())

View File

@ -86,12 +86,14 @@ netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_cal
API_MSG_VAR_FREE(msg); API_MSG_VAR_FREE(msg);
if (err != ERR_OK) { if (err != ERR_OK) {
LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL); LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));
LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox)); LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox));
#if LWIP_TCP #if LWIP_TCP
LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox)); LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox));
#endif /* LWIP_TCP */ #endif /* LWIP_TCP */
#if !LWIP_NETCONN_SEM_PER_THREAD
LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));
sys_sem_free(&conn->op_completed); sys_sem_free(&conn->op_completed);
#endif /* !LWIP_NETCONN_SEM_PER_THREAD */
sys_mbox_free(&conn->recvmbox); sys_mbox_free(&conn->recvmbox);
memp_free(MEMP_NETCONN, conn); memp_free(MEMP_NETCONN, conn);
return NULL; return NULL;
@ -827,7 +829,7 @@ netconn_gethostbyname(const char *name, ip_addr_t *addr)
LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;); LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
#if LWIP_MPU_COMPATIBLE #if LWIP_MPU_COMPATIBLE
if (strlen(name >= DNS_MAX_NAME_LENGTH) { if (strlen(name) >= DNS_MAX_NAME_LENGTH) {
return ERR_ARG; return ERR_ARG;
} }
#endif #endif
@ -862,4 +864,25 @@ netconn_gethostbyname(const char *name, ip_addr_t *addr)
} }
#endif /* LWIP_DNS*/ #endif /* LWIP_DNS*/
#if LWIP_NETCONN_SEM_PER_THREAD
void netconn_thread_init(void)
{
sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
if (sem == SYS_SEM_NULL) {
/* call alloc only once */
LWIP_NETCONN_THREAD_SEM_ALLOC();
LWIP_ASSERT("LWIP_NETCONN_THREAD_SEM_ALLOC() failed", LWIP_NETCONN_THREAD_SEM_GET() != SYS_SEM_NULL);
}
}
void netconn_thread_cleanup(void)
{
sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
if (sem == SYS_SEM_NULL) {
/* call free only once */
LWIP_NETCONN_THREAD_SEM_FREE();
}
}
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
#endif /* LWIP_NETCONN */ #endif /* LWIP_NETCONN */

View File

@ -70,7 +70,7 @@ static void lwip_netconn_do_close_internal(struct netconn *conn);
#if LWIP_RAW #if LWIP_RAW
/** /**
* Receive callback function for RAW netconns. * Receive callback function for RAW netconns.
* Doesn't 'eat' the packet, only references it and sends it to * Doesn't 'eat' the packet, only copies it and sends it to
* conn->recvmbox * conn->recvmbox
* *
* @see raw.h (struct raw_pcb.recv) for parameters and return value * @see raw.h (struct raw_pcb.recv) for parameters and return value
@ -365,8 +365,9 @@ err_tcp(void *arg, err_t err)
old_state = conn->state; old_state = conn->state;
conn->state = NETCONN_NONE; conn->state = NETCONN_NONE;
/* Notify the user layer about a connection error. Used to signal /* @todo: the type of NETCONN_EVT created should depend on 'old_state' */
select. */
/* Notify the user layer about a connection error. Used to signal select. */
API_EVENT(conn, NETCONN_EVT_ERROR, 0); API_EVENT(conn, NETCONN_EVT_ERROR, 0);
/* Try to release selects pending on 'read' or 'write', too. /* Try to release selects pending on 'read' or 'write', too.
They will get an error if they actually try to read or write. */ They will get an error if they actually try to read or write. */
@ -392,12 +393,15 @@ err_tcp(void *arg, err_t err)
SET_NONBLOCKING_CONNECT(conn, 0); SET_NONBLOCKING_CONNECT(conn, 0);
if (!was_nonblocking_connect) { if (!was_nonblocking_connect) {
sys_sem_t* op_completed_sem;
/* set error return code */ /* set error return code */
LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
conn->current_msg->err = err; conn->current_msg->err = err;
op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
LWIP_ASSERT("inavlid op_completed_sem", op_completed_sem != SYS_SEM_NULL);
conn->current_msg = NULL; conn->current_msg = NULL;
/* wake up the waiting task */ /* wake up the waiting task */
sys_sem_signal(&conn->op_completed); sys_sem_signal(op_completed_sem);
} }
} else { } else {
LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL); LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
@ -553,7 +557,7 @@ void
lwip_netconn_do_newconn(struct api_msg_msg *msg) lwip_netconn_do_newconn(struct api_msg_msg *msg)
{ {
msg->err = ERR_OK; msg->err = ERR_OK;
if(msg->conn->pcb.tcp == NULL) { if (msg->conn->pcb.tcp == NULL) {
pcb_new(msg); pcb_new(msg);
} }
/* Else? This "new" connection already has a PCB allocated. */ /* Else? This "new" connection already has a PCB allocated. */
@ -588,7 +592,7 @@ netconn_alloc(enum netconn_type t, netconn_callback callback)
conn->type = t; conn->type = t;
conn->pcb.tcp = NULL; conn->pcb.tcp = NULL;
/* If all sizes are the same, every compiler should optimize this switch to nothing, */ /* If all sizes are the same, every compiler should optimize this switch to nothing */
switch(NETCONNTYPE_GROUP(t)) { switch(NETCONNTYPE_GROUP(t)) {
#if LWIP_RAW #if LWIP_RAW
case NETCONN_RAW: case NETCONN_RAW:
@ -610,13 +614,15 @@ netconn_alloc(enum netconn_type t, netconn_callback callback)
goto free_and_return; goto free_and_return;
} }
if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
goto free_and_return;
}
if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) { if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
sys_sem_free(&conn->op_completed);
goto free_and_return; goto free_and_return;
} }
#if !LWIP_NETCONN_SEM_PER_THREAD
if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
sys_mbox_free(&conn->recvmbox);
goto free_and_return;
}
#endif
#if LWIP_TCP #if LWIP_TCP
sys_mbox_set_invalid(&conn->acceptmbox); sys_mbox_set_invalid(&conn->acceptmbox);
@ -665,8 +671,10 @@ netconn_free(struct netconn *conn)
!sys_mbox_valid(&conn->acceptmbox)); !sys_mbox_valid(&conn->acceptmbox));
#endif /* LWIP_TCP */ #endif /* LWIP_TCP */
#if !LWIP_NETCONN_SEM_PER_THREAD
sys_sem_free(&conn->op_completed); sys_sem_free(&conn->op_completed);
sys_sem_set_invalid(&conn->op_completed); sys_sem_set_invalid(&conn->op_completed);
#endif
memp_free(MEMP_NETCONN, conn); memp_free(MEMP_NETCONN, conn);
} }
@ -790,6 +798,7 @@ lwip_netconn_do_close_internal(struct netconn *conn)
} }
if (err == ERR_OK) { if (err == ERR_OK) {
/* Closing succeeded */ /* Closing succeeded */
sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
conn->current_msg->err = ERR_OK; conn->current_msg->err = ERR_OK;
conn->current_msg = NULL; conn->current_msg = NULL;
conn->state = NETCONN_NONE; conn->state = NETCONN_NONE;
@ -807,7 +816,7 @@ lwip_netconn_do_close_internal(struct netconn *conn)
API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
} }
/* wake up the application task */ /* wake up the application task */
sys_sem_signal(&conn->op_completed); sys_sem_signal(op_completed_sem);
} else { } else {
/* Closing failed, restore some of the callbacks */ /* Closing failed, restore some of the callbacks */
/* Closing of listen pcb will never fail! */ /* Closing of listen pcb will never fail! */
@ -884,8 +893,8 @@ lwip_netconn_do_delconn(struct api_msg_msg *msg)
API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
} }
if (sys_sem_valid(&msg->conn->op_completed)) { if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) {
sys_sem_signal(&msg->conn->op_completed); sys_sem_signal(LWIP_API_MSG_SEM(msg));
} }
} }
@ -940,6 +949,7 @@ lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
{ {
struct netconn *conn; struct netconn *conn;
int was_blocking; int was_blocking;
sys_sem_t* op_completed_sem = NULL;
LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(pcb);
@ -955,12 +965,16 @@ lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
if (conn->current_msg != NULL) { if (conn->current_msg != NULL) {
conn->current_msg->err = err; conn->current_msg->err = err;
op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
} }
if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) { if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) {
setup_tcp(conn); setup_tcp(conn);
} }
was_blocking = !IN_NONBLOCKING_CONNECT(conn); was_blocking = !IN_NONBLOCKING_CONNECT(conn);
SET_NONBLOCKING_CONNECT(conn, 0); SET_NONBLOCKING_CONNECT(conn, 0);
LWIP_ASSERT("blocking connect state error",
(was_blocking && op_completed_sem != NULL) ||
(!was_blocking && op_completed_sem == NULL));
conn->current_msg = NULL; conn->current_msg = NULL;
conn->state = NETCONN_NONE; conn->state = NETCONN_NONE;
if (!was_blocking) { if (!was_blocking) {
@ -969,7 +983,7 @@ lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
if (was_blocking) { if (was_blocking) {
sys_sem_signal(&conn->op_completed); sys_sem_signal(op_completed_sem);
} }
return ERR_OK; return ERR_OK;
} }
@ -990,7 +1004,7 @@ lwip_netconn_do_connect(struct api_msg_msg *msg)
msg->err = ERR_CLSD; msg->err = ERR_CLSD;
if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
/* For TCP, netconn_connect() calls tcpip_apimsg(), so signal op_completed here. */ /* For TCP, netconn_connect() calls tcpip_apimsg(), so signal op_completed here. */
sys_sem_signal(&msg->conn->op_completed); sys_sem_signal(LWIP_API_MSG_SEM(msg));
return; return;
} }
} else { } else {
@ -1029,7 +1043,7 @@ lwip_netconn_do_connect(struct api_msg_msg *msg)
} }
} }
/* For TCP, netconn_connect() calls tcpip_apimsg(), so signal op_completed here. */ /* For TCP, netconn_connect() calls tcpip_apimsg(), so signal op_completed here. */
sys_sem_signal(&msg->conn->op_completed); sys_sem_signal(LWIP_API_MSG_SEM(msg));
return; return;
#endif /* LWIP_TCP */ #endif /* LWIP_TCP */
default: default:
@ -1286,7 +1300,7 @@ lwip_netconn_do_writemore(struct netconn *conn)
if (available < len) { if (available < len) {
/* don't try to write more than sendbuf */ /* don't try to write more than sendbuf */
len = available; len = available;
if (dontblock){ if (dontblock) {
if (!len) { if (!len) {
err = ERR_WOULDBLOCK; err = ERR_WOULDBLOCK;
goto err_mem; goto err_mem;
@ -1347,6 +1361,7 @@ err_mem:
if (write_finished) { if (write_finished) {
/* everything was written: set back connection state /* everything was written: set back connection state
and back to application task */ and back to application task */
sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
conn->current_msg->err = err; conn->current_msg->err = err;
conn->current_msg = NULL; conn->current_msg = NULL;
conn->state = NETCONN_NONE; conn->state = NETCONN_NONE;
@ -1354,12 +1369,13 @@ err_mem:
if ((conn->flags & NETCONN_FLAG_WRITE_DELAYED) != 0) if ((conn->flags & NETCONN_FLAG_WRITE_DELAYED) != 0)
#endif #endif
{ {
sys_sem_signal(&conn->op_completed); sys_sem_signal(op_completed_sem);
} }
} }
#if LWIP_TCPIP_CORE_LOCKING #if LWIP_TCPIP_CORE_LOCKING
else else {
return ERR_MEM; return ERR_MEM;
}
#endif #endif
return ERR_OK; return ERR_OK;
} }
@ -1395,9 +1411,9 @@ lwip_netconn_do_write(struct api_msg_msg *msg)
if (lwip_netconn_do_writemore(msg->conn) != ERR_OK) { if (lwip_netconn_do_writemore(msg->conn) != ERR_OK) {
LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
UNLOCK_TCPIP_CORE(); UNLOCK_TCPIP_CORE();
sys_arch_sem_wait(&msg->conn->op_completed, 0); sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
LOCK_TCPIP_CORE(); LOCK_TCPIP_CORE();
LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE);
} }
#else /* LWIP_TCPIP_CORE_LOCKING */ #else /* LWIP_TCPIP_CORE_LOCKING */
lwip_netconn_do_writemore(msg->conn); lwip_netconn_do_writemore(msg->conn);
@ -1484,8 +1500,9 @@ lwip_netconn_do_getaddr(struct api_msg_msg *msg)
} }
/** /**
* Close a TCP pcb contained in a netconn * Close or half-shutdown a TCP pcb contained in a netconn
* Called from netconn_close * Called from netconn_close
* In contrast to closing sockets, the netconn is not deallocated.
* *
* @param msg the api_msg_msg pointing to the connection * @param msg the api_msg_msg pointing to the connection
*/ */
@ -1521,7 +1538,7 @@ lwip_netconn_do_close(struct api_msg_msg *msg)
{ {
msg->err = ERR_VAL; msg->err = ERR_VAL;
} }
sys_sem_signal(&msg->conn->op_completed); sys_sem_signal(LWIP_API_MSG_SEM(msg));
} }
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)

View File

@ -125,7 +125,7 @@
#define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \ #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \
name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \ name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \
if (name == NULL) { \ if (name == NULL) { \
sock_set_errno(sock, ERR_MEM); \ sock_set_errno(sock, ENOMEM); \
return -1; \ return -1; \
} }while(0) } }while(0)
#else /* LWIP_MPU_COMPATIBLE */ #else /* LWIP_MPU_COMPATIBLE */
@ -135,6 +135,13 @@
#define NUM_SOCKETS MEMP_NUM_NETCONN #define NUM_SOCKETS MEMP_NUM_NETCONN
/** This is overridable for the rare case where more than 255 threads
* select on the same socket...
*/
#ifndef SELWAIT_T
#define SELWAIT_T u8_t
#endif
/** Contains all internal pointers and states used for a socket */ /** Contains all internal pointers and states used for a socket */
struct lwip_sock { struct lwip_sock {
/** sockets currently are built on netconns, each socket has one netconn */ /** sockets currently are built on netconns, each socket has one netconn */
@ -151,12 +158,20 @@ struct lwip_sock {
u16_t sendevent; u16_t sendevent;
/** error happened for this socket, set by event_callback(), tested by select */ /** error happened for this socket, set by event_callback(), tested by select */
u16_t errevent; u16_t errevent;
/** last error that occurred on this socket */ /** last error that occurred on this socket (in fact, all our errnos fit into an u8_t) */
int err; u8_t err;
/** counter of how many threads are waiting for this socket using select */ /** counter of how many threads are waiting for this socket using select */
int select_waiting; SELWAIT_T select_waiting;
}; };
#if LWIP_NETCONN_SEM_PER_THREAD
#define SELECT_SEM_T sys_sem_t*
#define SELECT_SEM_PTR(sem) (sem)
#else /* LWIP_NETCONN_SEM_PER_THREAD */
#define SELECT_SEM_T sys_sem_t
#define SELECT_SEM_PTR(sem) (&(sem))
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
/** Description for a task waiting in select */ /** Description for a task waiting in select */
struct lwip_select_cb { struct lwip_select_cb {
/** Pointer to the next waiting task */ /** Pointer to the next waiting task */
@ -172,7 +187,7 @@ struct lwip_select_cb {
/** don't signal the same semaphore twice: set to 1 when signalled */ /** don't signal the same semaphore twice: set to 1 when signalled */
int sem_signalled; int sem_signalled;
/** semaphore to wake up a task waiting for select */ /** semaphore to wake up a task waiting for select */
sys_sem_t sem; SELECT_SEM_T sem;
}; };
/** A struct sockaddr replacement that has the same alignment as sockaddr_in/ /** A struct sockaddr replacement that has the same alignment as sockaddr_in/
@ -537,8 +552,8 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) { if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) {
/* sockaddr does not match socket type (IPv4/IPv6) */ /* sockaddr does not match socket type (IPv4/IPv6) */
sock_set_errno(sock, err_to_errno(ERR_VAL)); sock_set_errno(sock, err_to_errno(ERR_VAL));
return -1; return -1;
} }
LWIP_UNUSED_ARG(namelen); LWIP_UNUSED_ARG(namelen);
@ -1153,7 +1168,6 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
fd_set lreadset, lwriteset, lexceptset; fd_set lreadset, lwriteset, lexceptset;
u32_t msectimeout; u32_t msectimeout;
struct lwip_select_cb select_cb; struct lwip_select_cb select_cb;
err_t err;
int i; int i;
SYS_ARCH_DECL_PROTECT(lev); SYS_ARCH_DECL_PROTECT(lev);
@ -1186,12 +1200,15 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
select_cb.writeset = writeset; select_cb.writeset = writeset;
select_cb.exceptset = exceptset; select_cb.exceptset = exceptset;
select_cb.sem_signalled = 0; select_cb.sem_signalled = 0;
err = sys_sem_new(&select_cb.sem, 0); #if LWIP_NETCONN_SEM_PER_THREAD
if (err != ERR_OK) { select_cb.sem = LWIP_NETCONN_THREAD_SEM_GET();
#else /* LWIP_NETCONN_SEM_PER_THREAD */
if (sys_sem_new(&select_cb.sem, 0) != ERR_OK) {
/* failed to create semaphore */ /* failed to create semaphore */
set_errno(ENOMEM); set_errno(ENOMEM);
return -1; return -1;
} }
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
/* Protect the select_cb_list */ /* Protect the select_cb_list */
SYS_ARCH_PROTECT(lev); SYS_ARCH_PROTECT(lev);
@ -1217,7 +1234,7 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
LWIP_ASSERT("sock != NULL", sock != NULL); LWIP_ASSERT("sock != NULL", sock != NULL);
SYS_ARCH_PROTECT(lev); SYS_ARCH_PROTECT(lev);
sock->select_waiting++; sock->select_waiting++;
LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); LWIP_ASSERT("sock->select_waiting overflow", sock->select_waiting > 0);
SYS_ARCH_UNPROTECT(lev); SYS_ARCH_UNPROTECT(lev);
} }
} }
@ -1238,7 +1255,7 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
} }
} }
waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout); waitres = sys_arch_sem_wait(SELECT_SEM_PTR(select_cb.sem), msectimeout);
} }
/* Increase select_waiting for each socket we are interested in */ /* Increase select_waiting for each socket we are interested in */
for(i = 0; i < maxfdp1; i++) { for(i = 0; i < maxfdp1; i++) {
@ -1269,8 +1286,11 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
select_cb_ctr++; select_cb_ctr++;
SYS_ARCH_UNPROTECT(lev); SYS_ARCH_UNPROTECT(lev);
#if !LWIP_NETCONN_SEM_PER_THREAD
sys_sem_free(&select_cb.sem); sys_sem_free(&select_cb.sem);
if (waitres == SYS_ARCH_TIMEOUT) { #endif /* LWIP_NETCONN_SEM_PER_THREAD */
if (waitres == SYS_ARCH_TIMEOUT) {
/* Timeout */ /* Timeout */
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
/* This is OK as the local fdsets are empty and nready is zero, /* This is OK as the local fdsets are empty and nready is zero,
@ -1403,7 +1423,7 @@ again:
scb->sem_signalled = 1; scb->sem_signalled = 1;
/* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might
lead to the select thread taking itself off the list, invalidating the semaphore. */ lead to the select thread taking itself off the list, invalidating the semaphore. */
sys_sem_signal(&scb->sem); sys_sem_signal(SELECT_SEM_PTR(scb->sem));
} }
} }
/* unlock interrupts with each step */ /* unlock interrupts with each step */
@ -1742,8 +1762,19 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval = optval; LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval = optval;
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen; LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen;
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = err; LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = err;
#if LWIP_TCPIP_CORE_LOCKING
LOCK_TCPIP_CORE();
lwip_getsockopt_internal(&LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
UNLOCK_TCPIP_CORE();
#else /* LWIP_TCPIP_CORE_LOCKING */
#if LWIP_NETCONN_SEM_PER_THREAD
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
#else
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed;
#endif
tcpip_callback(lwip_getsockopt_internal, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); tcpip_callback(lwip_getsockopt_internal, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
sys_arch_sem_wait(&sock->conn->op_completed, 0); sys_arch_sem_wait((sys_sem_t*)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0);
#endif /* LWIP_TCPIP_CORE_LOCKING */
/* maybe lwip_getsockopt_internal has changed err */ /* maybe lwip_getsockopt_internal has changed err */
err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err;
LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
@ -1993,7 +2024,9 @@ lwip_getsockopt_internal(void *arg)
LWIP_ASSERT("unhandled level", 0); LWIP_ASSERT("unhandled level", 0);
break; break;
} /* switch (level) */ } /* switch (level) */
sys_sem_signal(&sock->conn->op_completed); #if !LWIP_TCPIP_CORE_LOCKING
sys_sem_signal((sys_sem_t*)(data->completed_sem));
#endif
} }
int int
@ -2253,8 +2286,19 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval = (void*)optval; LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval = (void*)optval;
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = &optlen; LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = &optlen;
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = err; LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = err;
#if LWIP_TCPIP_CORE_LOCKING
LOCK_TCPIP_CORE();
lwip_setsockopt_internal(&LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
UNLOCK_TCPIP_CORE();
#else /* LWIP_TCPIP_CORE_LOCKING */
#if LWIP_NETCONN_SEM_PER_THREAD
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
#else
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed;
#endif
tcpip_callback(lwip_setsockopt_internal, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); tcpip_callback(lwip_setsockopt_internal, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
sys_arch_sem_wait(&sock->conn->op_completed, 0); sys_arch_sem_wait((sys_sem_t*)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0);
#endif /* LWIP_TCPIP_CORE_LOCKING */
/* maybe lwip_setsockopt_internal has changed err */ /* maybe lwip_setsockopt_internal has changed err */
err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err;
LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
@ -2510,7 +2554,9 @@ lwip_setsockopt_internal(void *arg)
LWIP_ASSERT("unhandled level", 0); LWIP_ASSERT("unhandled level", 0);
break; break;
} /* switch (level) */ } /* switch (level) */
sys_sem_signal(&sock->conn->op_completed); #if !LWIP_TCPIP_CORE_LOCKING
sys_sem_signal((sys_sem_t*)(data->completed_sem));
#endif
} }
int int

View File

@ -338,8 +338,13 @@ tcpip_apimsg(struct api_msg *apimsg)
TCPIP_MSG_VAR_ALLOC(msg); TCPIP_MSG_VAR_ALLOC(msg);
TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API; TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API;
TCPIP_MSG_VAR_REF(msg).msg.apimsg = apimsg; TCPIP_MSG_VAR_REF(msg).msg.apimsg = apimsg;
#if LWIP_NETCONN_SEM_PER_THREAD
apimsg->msg.op_completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
LWIP_ASSERT("netconn semaphore not initialized",
apimsg->msg.op_completed_sem != SYS_SEM_NULL);
#endif
sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg)); sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg));
sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0); sys_arch_sem_wait(LWIP_API_MSG_SEM(&apimsg->msg), 0);
TCPIP_MSG_VAR_FREE(msg); TCPIP_MSG_VAR_FREE(msg);
return apimsg->msg.err; return apimsg->msg.err;
} }

View File

@ -172,8 +172,10 @@ struct netconn {
} pcb; } pcb;
/** the last error this netconn had */ /** the last error this netconn had */
err_t last_err; err_t last_err;
#if !LWIP_NETCONN_SEM_PER_THREAD
/** sem that is used to synchronously execute functions in the core context */ /** sem that is used to synchronously execute functions in the core context */
sys_sem_t op_completed; sys_sem_t op_completed;
#endif
/** mbox where received packets are stored until they are fetched /** mbox where received packets are stored until they are fetched
by the netconn application thread (can grow quite big) */ by the netconn application thread (can grow quite big) */
sys_mbox_t recvmbox; sys_mbox_t recvmbox;
@ -188,11 +190,11 @@ struct netconn {
#endif /* LWIP_SOCKET */ #endif /* LWIP_SOCKET */
#if LWIP_SO_SNDTIMEO #if LWIP_SO_SNDTIMEO
/** timeout to wait for sending data (which means enqueueing data for sending /** timeout to wait for sending data (which means enqueueing data for sending
in internal buffers) */ in internal buffers) in milliseconds */
s32_t send_timeout; s32_t send_timeout;
#endif /* LWIP_SO_RCVTIMEO */ #endif /* LWIP_SO_RCVTIMEO */
#if LWIP_SO_RCVTIMEO #if LWIP_SO_RCVTIMEO
/** timeout to wait for new data to be received /** timeout in milliseconds to wait for new data to be received
(or connections to arrive for listening netconns) */ (or connections to arrive for listening netconns) */
int recv_timeout; int recv_timeout;
#endif /* LWIP_SO_RCVTIMEO */ #endif /* LWIP_SO_RCVTIMEO */
@ -329,6 +331,14 @@ err_t netconn_gethostbyname(const char *name, ip_addr_t *addr);
#define netconn_get_recvbufsize(conn) ((conn)->recv_bufsize) #define netconn_get_recvbufsize(conn) ((conn)->recv_bufsize)
#endif /* LWIP_SO_RCVBUF*/ #endif /* LWIP_SO_RCVBUF*/
#if LWIP_NETCONN_SEM_PER_THREAD
void netconn_thread_init(void);
void netconn_thread_cleanup(void);
#else /* LWIP_NETCONN_SEM_PER_THREAD */
#define netconn_thread_init()
#define netconn_thread_cleanup()
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -121,8 +121,18 @@ struct api_msg_msg {
} lb; } lb;
#endif /* TCP_LISTEN_BACKLOG */ #endif /* TCP_LISTEN_BACKLOG */
} msg; } msg;
#if LWIP_NETCONN_SEM_PER_THREAD
sys_sem_t* op_completed_sem;
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
}; };
#if LWIP_NETCONN_SEM_PER_THREAD
#define LWIP_API_MSG_SEM(msg) ((msg)->op_completed_sem)
#else /* LWIP_NETCONN_SEM_PER_THREAD */
#define LWIP_API_MSG_SEM(msg) (&(msg)->conn->op_completed)
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
/** This struct contains a function to execute in another thread context and /** This struct contains a function to execute in another thread context and
a struct api_msg_msg that serves as an argument for this function. a struct api_msg_msg that serves as an argument for this function.
This is passed to tcpip_apimsg to execute functions in tcpip_thread context. */ This is passed to tcpip_apimsg to execute functions in tcpip_thread context. */

View File

@ -1473,6 +1473,20 @@
#define LWIP_TCPIP_TIMEOUT 1 #define LWIP_TCPIP_TIMEOUT 1
#endif #endif
/** LWIP_NETCONN_SEM_PER_THREAD==1: Use one (thread-local) semaphore per
* thread calling socket/netconn functions instead of allocating one
* semaphore per netconn (and per select etc.)
* ATTENTION: a thread-local semaphore for API calls is needed:
* - LWIP_NETCONN_THREAD_SEM_GET() returning a sys_sem_t*
* - LWIP_NETCONN_THREAD_SEM_ALLOC() creating the semaphore
* - LWIP_NETCONN_THREAD_SEM_FREE() freeing the semaphore
* The latter 2 can be invoked up by calling netconn_thread_init()/netconn_thread_cleanup().
* Ports may call these for threads created with sys_thread_new().
*/
#ifndef LWIP_NETCONN_SEM_PER_THREAD
#define LWIP_NETCONN_SEM_PER_THREAD 0
#endif
/* /*
------------------------------------ ------------------------------------
---------- Socket options ---------- ---------- Socket options ----------

View File

@ -128,6 +128,10 @@ struct lwip_setgetsockopt_data {
socklen_t *optlen; socklen_t *optlen;
/** if an error occurs, it is temporarily stored here */ /** if an error occurs, it is temporarily stored here */
err_t err; err_t err;
#if !LWIP_TCPIP_CORE_LOCKING
/** semaphore to wake up the calling task */
void* completed_sem;
#endif /* !LWIP_TCPIP_CORE_LOCKING */
}; };
/* Socket protocol types (TCP/UDP/RAW) */ /* Socket protocol types (TCP/UDP/RAW) */

View File

@ -65,8 +65,14 @@ extern sys_mutex_t lock_tcpip_core;
#else #else
#define TCIP_APIMSG_SET_ERR(m, e) #define TCIP_APIMSG_SET_ERR(m, e)
#endif #endif
#if LWIP_NETCONN_SEM_PER_THREAD
#define TCPIP_APIMSG_SET_SEM(m) ((m)->msg.op_completed_sem = LWIP_NETCONN_THREAD_SEM_GET())
#else
#define TCPIP_APIMSG_SET_SEM(m)
#endif
#define TCPIP_APIMSG_NOERR(m,f) do { \ #define TCPIP_APIMSG_NOERR(m,f) do { \
TCIP_APIMSG_SET_ERR(m, ERR_VAL); \ TCIP_APIMSG_SET_ERR(m, ERR_VAL); \
TCPIP_APIMSG_SET_SEM(m); \
LOCK_TCPIP_CORE(); \ LOCK_TCPIP_CORE(); \
f(&((m)->msg)); \ f(&((m)->msg)); \
UNLOCK_TCPIP_CORE(); \ UNLOCK_TCPIP_CORE(); \
@ -85,7 +91,7 @@ extern sys_mutex_t lock_tcpip_core;
#define UNLOCK_TCPIP_CORE() #define UNLOCK_TCPIP_CORE()
#define TCPIP_APIMSG_NOERR(m,f) do { (m)->function = f; tcpip_apimsg(m); } while(0) #define TCPIP_APIMSG_NOERR(m,f) do { (m)->function = f; tcpip_apimsg(m); } while(0)
#define TCPIP_APIMSG(m,f,e) do { (m)->function = f; (e) = tcpip_apimsg(m); } while(0) #define TCPIP_APIMSG(m,f,e) do { (m)->function = f; (e) = tcpip_apimsg(m); } while(0)
#define TCPIP_APIMSG_ACK(m) sys_sem_signal(&m->conn->op_completed) #define TCPIP_APIMSG_ACK(m) sys_sem_signal(LWIP_API_MSG_SEM(m))
#define TCPIP_NETIFAPI(m) tcpip_netifapi(m) #define TCPIP_NETIFAPI(m) tcpip_netifapi(m)
#define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(&m->sem) #define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(&m->sem)
#define TCPIP_PPPAPI(m) tcpip_pppapi(m) #define TCPIP_PPPAPI(m) tcpip_pppapi(m)