Skip to content

Commit 04e4d9f

Browse files
c1728p9geky
authored andcommitted
Fix async NSAPI race condition
Remove read and write mutexes since multiple calls to send or multiple calls to recv on different threads is undefined behavior. This is because the size of data sent or received by these calls is undefined and could lead to the data being interleaved. The code now asserts that there are not multiple threads calling send at the same or calling recv at the same time. Note that calling send and recv from different threads at the same time is still safe and well defined behavior. By removing the read and write mutexes and associated timeout it guarantees that a stack call will always be made and thus the value NSAPI_ERROR_TIMEOUT cannot get falsely returned.
1 parent 90cd978 commit 04e4d9f

File tree

4 files changed

+42
-26
lines changed

4 files changed

+42
-26
lines changed

TCPSocket.cpp

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,25 @@
1616

1717
#include "TCPSocket.h"
1818
#include "Timer.h"
19+
#include "mbed_assert.h"
1920

2021
TCPSocket::TCPSocket()
21-
: _pending(0), _read_sem(0), _write_sem(0)
22+
: _pending(0), _read_sem(0), _write_sem(0),
23+
_read_in_progress(false), _write_in_progress(false)
2224
{
2325
}
2426

2527
TCPSocket::TCPSocket(NetworkStack *iface)
26-
: _pending(0), _read_sem(0), _write_sem(0)
28+
: _pending(0), _read_sem(0), _write_sem(0),
29+
_read_in_progress(false), _write_in_progress(false)
2730
{
2831
// TCPSocket::open is thread safe
2932
open(iface);
3033
}
3134

3235
TCPSocket::TCPSocket(NetworkInterface *iface)
33-
: _pending(0), _read_sem(0), _write_sem(0)
36+
: _pending(0), _read_sem(0), _write_sem(0),
37+
_read_in_progress(false), _write_in_progress(false)
3438
{
3539
// TCPSocket::open is thread safe
3640
open(iface->get_stack());
@@ -82,10 +86,12 @@ int TCPSocket::connect(const char *host, uint16_t port)
8286

8387
int TCPSocket::send(const void *data, unsigned size)
8488
{
85-
if (osOK != _write_lock.lock(_timeout)) {
86-
return NSAPI_ERROR_WOULD_BLOCK;
87-
}
8889
_lock.lock();
90+
// If this assert is hit then there are two threads
91+
// performing a send at the same time which is undefined
92+
// behavior
93+
MBED_ASSERT(!_write_in_progress);
94+
_write_in_progress = true;
8995

9096
int ret;
9197
while (true) {
@@ -116,17 +122,19 @@ int TCPSocket::send(const void *data, unsigned size)
116122
}
117123
}
118124

125+
_write_in_progress = false;
119126
_lock.unlock();
120-
_write_lock.unlock();
121127
return ret;
122128
}
123129

124130
int TCPSocket::recv(void *data, unsigned size)
125131
{
126-
if (osOK != _read_lock.lock(_timeout)) {
127-
return NSAPI_ERROR_WOULD_BLOCK;
128-
}
129132
_lock.lock();
133+
// If this assert is hit then there are two threads
134+
// performing a recv at the same time which is undefined
135+
// behavior
136+
MBED_ASSERT(!_read_in_progress);
137+
_read_in_progress = true;
130138

131139
int ret;
132140
while (true) {
@@ -157,8 +165,8 @@ int TCPSocket::recv(void *data, unsigned size)
157165
}
158166
}
159167

168+
_read_in_progress = false;
160169
_lock.unlock();
161-
_read_lock.unlock();
162170
return ret;
163171
}
164172

TCPSocket.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,10 @@ class TCPSocket : public Socket {
132132
protected:
133133
virtual void event();
134134
volatile unsigned _pending;
135-
rtos::Mutex _read_lock;
136135
rtos::Semaphore _read_sem;
137-
rtos::Mutex _write_lock;
138136
rtos::Semaphore _write_sem;
137+
bool _read_in_progress;
138+
bool _write_in_progress;
139139
friend class TCPServer;
140140
};
141141

UDPSocket.cpp

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,24 @@
1616

1717
#include "UDPSocket.h"
1818
#include "Timer.h"
19+
#include "mbed_assert.h"
1920

2021
UDPSocket::UDPSocket()
21-
: _pending(0), _read_sem(0), _write_sem(0)
22+
: _pending(0), _read_sem(0), _write_sem(0),
23+
_read_in_progress(false), _write_in_progress(false)
2224
{
2325
}
2426

2527
UDPSocket::UDPSocket(NetworkStack *iface)
26-
: _pending(0), _read_sem(0), _write_sem(0)
28+
: _pending(0), _read_sem(0), _write_sem(0),
29+
_read_in_progress(false), _write_in_progress(false)
2730
{
2831
open(iface);
2932
}
3033

3134
UDPSocket::UDPSocket(NetworkInterface *iface)
32-
: _pending(0), _read_sem(0), _write_sem(0)
35+
: _pending(0), _read_sem(0), _write_sem(0),
36+
_read_in_progress(false), _write_in_progress(false)
3337
{
3438
open(iface->get_stack());
3539
}
@@ -64,10 +68,12 @@ int UDPSocket::sendto(const char *host, uint16_t port, const void *data, unsigne
6468

6569
int UDPSocket::sendto(const SocketAddress &address, const void *data, unsigned size)
6670
{
67-
if (osOK != _write_lock.lock(_timeout)) {
68-
return NSAPI_ERROR_WOULD_BLOCK;
69-
}
7071
_lock.lock();
72+
// If this assert is hit then there are two threads
73+
// performing a send at the same time which is undefined
74+
// behavior
75+
MBED_ASSERT(!_write_in_progress);
76+
_write_in_progress = true;
7177

7278
int ret;
7379
while (true) {
@@ -98,17 +104,19 @@ int UDPSocket::sendto(const SocketAddress &address, const void *data, unsigned s
98104
}
99105
}
100106

107+
_write_in_progress = false;
101108
_lock.unlock();
102-
_write_lock.unlock();
103109
return ret;
104110
}
105111

106112
int UDPSocket::recvfrom(SocketAddress *address, void *buffer, unsigned size)
107113
{
108-
if (osOK != _read_lock.lock(_timeout)) {
109-
return NSAPI_ERROR_WOULD_BLOCK;
110-
}
111114
_lock.lock();
115+
// If this assert is hit then there are two threads
116+
// performing a recv at the same time which is undefined
117+
// behavior
118+
MBED_ASSERT(!_read_in_progress);
119+
_read_in_progress = true;
112120

113121
int ret;
114122
while (true) {
@@ -139,8 +147,8 @@ int UDPSocket::recvfrom(SocketAddress *address, void *buffer, unsigned size)
139147
}
140148
}
141149

150+
_read_in_progress = false;
142151
_lock.unlock();
143-
_read_lock.unlock();
144152
return ret;
145153
}
146154

UDPSocket.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,10 @@ class UDPSocket : public Socket {
131131
protected:
132132
virtual void event();
133133
volatile unsigned _pending;
134-
rtos::Mutex _read_lock;
135134
rtos::Semaphore _read_sem;
136-
rtos::Mutex _write_lock;
137135
rtos::Semaphore _write_sem;
136+
bool _read_in_progress;
137+
bool _write_in_progress;
138138
};
139139

140140
#endif

0 commit comments

Comments
 (0)