[lwip-users] lwip_accept() blocks for non-blocking sockets ?

1,867 views
Skip to first unread message

Tamas Somogyi

unread,
Sep 30, 2008, 12:35:36 PM9/30/08
to lwip-...@nongnu.org
Hi,

It seems that lwip_accept() blocks the calling thread even if the
listening socket is set to non-blocking mode - see sample code below.
Is it the normal behaviour or a bug?
Winsock's accept() returns immediately for non-blocking sockets...
As far as I debugged, it seems that sys_[arch_]mbox_fetch() waits
forever or till the first connection.
I'm using the Win32-port of LwIP 1.3.0, but this bug perhaps comes on
other platforms as well. Maybe using sys_mbox_TRY_fetch would be more
appropriate if FIONBIO is set, however I'm not familiar with using
mailboxes in lwIP, therefore I would not dive deeper in the code if
somebody can quickly tell me the right solution.

Thanks,
Tamas Somogyi

Example code:
//create socket
int s = lwip_socket(PF_INET, SOCK_STREAM, 0);

//set to non-blocking mode
int i = 1;
lwip_ioctl(s, FIONBIO, &i);

//listen
lwip_listen(s, 0);

//accept connection
struct sockaddr addr;
socklen_t l;
int t = lwip_accept(s, &addr, &l); //lwip_accept doesn't return until an
incoming connection happens


_______________________________________________
lwip-users mailing list
lwip-...@nongnu.org
http://lists.nongnu.org/mailman/listinfo/lwip-users

Jonathan Larmour

unread,
Sep 30, 2008, 12:52:30 PM9/30/08
to Mailing list for lwIP users
Tamas Somogyi wrote:
> Hi,
>
> It seems that lwip_accept() blocks the calling thread even if the
> listening socket is set to non-blocking mode - see sample code below.
> Is it the normal behaviour or a bug?

Normal behaviour. Only non-blocking reads are implemented in lwip.

However lwIP does have receive timeouts, which also affect accepts. Perhaps
that might be useful. Enable LWIP_SO_RCVTIMEO in lwipopts.h, and do a call
to lwip_setsockopt, e.g.:

int timeout = 1000; /* 1000 msecs */
err = lwip_setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));

Jifl
--
eCosCentric Limited http://www.eCosCentric.com/ The eCos experts
Barnwell House, Barnwell Drive, Cambridge, UK. Tel: +44 1223 245571
Registered in England and Wales: Reg No 4422071.
------["Si fractum non sit, noli id reficere"]------ Opinions==mine
>>>> Visit us on stand 905 at the Embedded Systems Show 2008 <<<<
>>>> Oct 1-2, NEC, Birmingham, UK http://www.embedded.co.uk <<<<

ri...@etinternational.com

unread,
Sep 30, 2008, 1:24:35 PM9/30/08
to Mailing list for lwIP users
I've noticed this too. It's a relatively easy fix. In api/sockets.c in
lwip_accept, put this:
if (sock->flags & O_NONBLOCK)
{
if (!(sock->lastdata || sock->rcvevent))
{
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%"S32_F"): returning
EWOULDBLOCK\n", s));
sock_set_errno(sock, EWOULDBLOCK);
return -1;
}
}

before this:
newconn = netconn_accept(sock->conn);

Essentially, I took this from lwip_recvfrom.

John L., you may want to test/commit this too.

Tamas Somogyi

unread,
Oct 1, 2008, 4:30:57 AM10/1/08
to Mailing list for lwIP users
It seems that the below-mentioned fix solves the problem in my
application indeed. Thanks guys for the quick solution!

Tamas

Chu, Zhenwei

unread,
Oct 1, 2008, 4:03:38 PM10/1/08
to Mailing list for lwIP users
I see the similar problem for lwip_select(). Does any body have good
suggestion to make it non-blocking?

Thanks
Zhenwei

-----Original Message-----
From: lwip-users-bounces+zhenwei.chu=analo...@nongnu.org
[mailto:lwip-users-bounces+zhenwei.chu=analo...@nongnu.org] On Behalf
Of ri...@etinternational.com
Sent: Tuesday, September 30, 2008 1:25 PM
To: Mailing list for lwIP users
Subject: Re: [lwip-users] lwip_accept() blocks for non-blocking sockets
?

Jonathan Larmour

unread,
Oct 1, 2008, 4:56:46 PM10/1/08
to Mailing list for lwIP users
ri...@etinternational.com wrote:
> I've noticed this too. It's a relatively easy fix. In api/sockets.c in
> lwip_accept, put this:
> if (sock->flags & O_NONBLOCK)
> {
> if (!(sock->lastdata || sock->rcvevent))

I'm not sure I understand why sock->lastdata is relevant?

Jifl

------["The best things in life aren't things."]------ Opinions==mine

Jonathan Larmour

unread,
Oct 1, 2008, 4:57:55 PM10/1/08
to Mailing list for lwIP users
Chu, Zhenwei wrote:
> I see the similar problem for lwip_select(). Does any body have good
> suggestion to make it non-blocking?

Use a timeout of 0.

Jifl
--
eCosCentric Limited http://www.eCosCentric.com/ The eCos experts
Barnwell House, Barnwell Drive, Cambridge, UK. Tel: +44 1223 245571
Registered in England and Wales: Reg No 4422071.

------["The best things in life aren't things."]------ Opinions==mine

Kieran Mansley

unread,
Oct 2, 2008, 3:51:08 AM10/2/08
to Mailing list for lwIP users
On Wed, 2008-10-01 at 21:56 +0100, Jonathan Larmour wrote:
> ri...@etinternational.com wrote:
> > I've noticed this too. It's a relatively easy fix. In api/sockets.c in
> > lwip_accept, put this:
> > if (sock->flags & O_NONBLOCK)
> > {
> > if (!(sock->lastdata || sock->rcvevent))
>
> I'm not sure I understand why sock->lastdata is relevant?

It shouldn't be for accept. It's relevant for lwip_recvfrom() of
course, where the code came from.

Kieran

Jonathan Larmour

unread,
Oct 2, 2008, 10:17:52 AM10/2/08
to Mailing list for lwIP users
Kieran Mansley wrote:
> On Wed, 2008-10-01 at 21:56 +0100, Jonathan Larmour wrote:
>
>>ri...@etinternational.com wrote:
>>
>>>I've noticed this too. It's a relatively easy fix. In api/sockets.c in
>>>lwip_accept, put this:
>>> if (sock->flags & O_NONBLOCK)
>>> {
>>> if (!(sock->lastdata || sock->rcvevent))
>>
>>I'm not sure I understand why sock->lastdata is relevant?
>
>
> It shouldn't be for accept. It's relevant for lwip_recvfrom() of
> course, where the code came from.

Ok, and given Tamas already verified it, I've checked in something that
should work based on that.

Jifl
--
eCosCentric Limited http://www.eCosCentric.com/ The eCos experts
Barnwell House, Barnwell Drive, Cambridge, UK. Tel: +44 1223 245571
Registered in England and Wales: Reg No 4422071.

------["The best things in life aren't things."]------ Opinions==mine

Rishi Khan

unread,
Oct 2, 2008, 1:43:04 PM10/2/08
to Mailing list for lwIP users
Kieran is correct. I used the example from lwip_recvfrom and didn't
note that sock->lastdata is irrelevant [and always false]. It doesn't
make the code incorrect, but it is irrelevant.

Rishi

Chu, Zhenwei

unread,
Oct 6, 2008, 11:57:00 AM10/6/08
to Mailing list for lwIP users
Hi,

It seems that lwIP_select() always block even if timeout is set to 0.

The call stack shows it stops at
sys_sem_wait(sem); (line 316: sys.c)
sys_sem_wait_timeout();

Any suggestions?

Thanks

Zhenwei Chu

Jonathan Larmour

unread,
Oct 6, 2008, 12:05:02 PM10/6/08
to Mailing list for lwIP users
Chu, Zhenwei wrote:
> Hi,
>
> It seems that lwIP_select() always block even if timeout is set to 0.
>
> The call stack shows it stops at
> sys_sem_wait(sem); (line 316: sys.c)
> sys_sem_wait_timeout();
>
> Any suggestions?

Is this really the latest lwIP? i.e. 1.3.0?

How are you calling lwip_select exactly?

Jifl
--
eCosCentric Limited http://www.eCosCentric.com/ The eCos experts
Barnwell House, Barnwell Drive, Cambridge, UK. Tel: +44 1223 245571
Registered in England and Wales: Reg No 4422071.
------["Si fractum non sit, noli id reficere"]------ Opinions==mine

Rishi Khan

unread,
Oct 6, 2008, 12:06:53 PM10/6/08
to Mailing list for lwIP users
Are you using 1.3.0?
In my code it says:
/* If we don't have any current events, then suspend if we are
supposed to */
if (!nready) {
if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
sys_sem_signal(selectsem);
if (readset)
FD_ZERO(readset);
if (writeset)
FD_ZERO(writeset);
if (exceptset)
FD_ZERO(exceptset);

LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout,
returning 0\n"));
set_errno(0);

return 0;

Rishi Khan

unread,
Oct 6, 2008, 12:19:16 PM10/6/08
to Mailing list for lwIP users
By any chance, are you setting timeout to 0, or timeout->tv_sec = 0
and timeout->tv_usec=0?
The latter is correct. The former means wait forever.

Rishi

On Oct 6, 2008, at 11:57 AM, Chu, Zhenwei wrote:

Chu, Zhenwei

unread,
Oct 6, 2008, 1:41:04 PM10/6/08
to Mailing list for lwIP users
Yes, it is lwIP 1.3.0. timeout is set to 0, and timeout->tv_sec = 0
and timeout->tv_usec=0. The section of code from sockets.c is copied
here.

lwip_select()
{
....

/* add our semaphore to list */
/* We don't actually need any dynamic memory. Our entry on the
* list is only valid while we are in this function, so it's ok
* to use local variables */

select_cb.sem = sys_sem_new(0);
/* Note that we are still protected */
/* Put this select_cb on top of list */
select_cb.next = select_cb_list;
select_cb_list = &select_cb;

/* Now we can safely unprotect */
sys_sem_signal(selectsem);

/* Now just wait to be woken */
if (timeout == 0)
/* Wait forever */
msectimeout = 0;
else {
msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec +
500)/1000));
if(msectimeout == 0)
msectimeout = 1;
}

i = sys_sem_wait_timeout(select_cb.sem, msectimeout); <----
BLOCKED HERE msectimeout=0

/* Take us off the list */
sys_sem_wait(selectsem);
if (select_cb_list == &select_cb)
select_cb_list = select_cb.next;
else
for (p_selcb = select_cb_list; p_selcb; p_selcb = p_selcb->next) {
if (p_selcb->next == &select_cb) {
p_selcb->next = select_cb.next;
break;
}
}

sys_sem_signal(selectsem);

....
}

Thanks

Zhenwei


-----Original Message-----
From: lwip-users-bounces+zhenwei.chu=analo...@nongnu.org
[mailto:lwip-users-bounces+zhenwei.chu=analo...@nongnu.org] On Behalf
Of Rishi Khan
Sent: Monday, October 06, 2008 12:19 PM
To: Mailing list for lwIP users

Jonathan Larmour

unread,
Oct 6, 2008, 2:18:34 PM10/6/08
to Mailing list for lwIP users
Chu, Zhenwei wrote:
> Yes, it is lwIP 1.3.0. timeout is set to 0, and timeout->tv_sec = 0
> and timeout->tv_usec=0. The section of code from sockets.c is copied
> here.

I was wondering how you called lwip_select, not the code that's called.

> lwip_select()
> {
> ....
>
> /* add our semaphore to list */
> /* We don't actually need any dynamic memory. Our entry on the
> * list is only valid while we are in this function, so it's ok
> * to use local variables */
>
> select_cb.sem = sys_sem_new(0);

[snip]

But the code that deals with not blocking is in the bit you have cut out
with "....".

As Rishi said, the bit that starts:


/* If we don't have any current events, then suspend if we are supposed to */
if (!nready) {
if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {

is the bit which means that lwip_select does not block if the timeout
duration is 0.

Jifl
--
eCosCentric Limited http://www.eCosCentric.com/ The eCos experts
Barnwell House, Barnwell Drive, Cambridge, UK. Tel: +44 1223 245571
Registered in England and Wales: Reg No 4422071.
------["Si fractum non sit, noli id reficere"]------ Opinions==mine

Chu, Zhenwei

unread,
Oct 6, 2008, 2:44:34 PM10/6/08
to Mailing list for lwIP users
The application calls select(), not lwip_select(). The original code is
ported from Linux version.

I think my problem is to set timeout as 0. Make timeout->tv_sec = 0 and
timeout->tv_usec=0, but not timeout, solve the problem.

Thanks for help.

Zhenwei


-----Original Message-----
From: lwip-users-bounces+zhenwei.chu=analo...@nongnu.org
[mailto:lwip-users-bounces+zhenwei.chu=analo...@nongnu.org] On Behalf
Of Jonathan Larmour
Sent: Monday, October 06, 2008 2:19 PM
To: Mailing list for lwIP users
Subject: Re: [lwip-users] lwip_select() blocks even if timeout is 0

Reply all
Reply to author
Forward
0 new messages