Skip to content

Commit 5423c6a

Browse files
committed
fixup! gnrc/netapi/netnotify: ACK notify event directly
Use mutex, counter and condvar to collect the exact count of acknowledgements for a notify event. With this, we can now block for all replies after dispatching to all receivers and after releasing the lock on netreg. This a) maintains the receivers priority order and b) prevents possible deadlocks that could happen if we hold the netreg lock while blocking for an ACK.
1 parent bee053b commit 5423c6a

File tree

5 files changed

+67
-50
lines changed

5 files changed

+67
-50
lines changed

sys/include/net/gnrc/netapi/notify.h

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@
2626
*
2727
* @note Notification events are associated with type-dependent event data.
2828
* Receivers should not access the data directly, but instead use the
29-
* the dedicated API functions.
30-
* If the data is read directly, the receiver is responsible for setting
31-
* the @ref NETAPI_NOTIFY_FLAG_ACK flag for the sending thread.
32-
*
29+
* the dedicated API functions to copy the data from the sender's.
30+
* If the data is read manually, the receiver is responsible for
31+
* calling @ref gnrc_netapi_notify_ack to unblock the sender.
3332
*
3433
* @author Elena Frank <[email protected]>
3534
*/
@@ -39,15 +38,8 @@ extern "C" {
3938
#endif
4039

4140
#include "net/ipv6/addr.h"
42-
#include "sched.h"
43-
44-
/**
45-
* @brief Thread flag for acknowledging a received notify even.
46-
*
47-
* @note The flag should only be set after all event data was copied
48-
* by receiver and can be freed by the sender.
49-
*/
50-
#define NETAPI_NOTIFY_FLAG_ACK (1u << 10)
41+
#include "cond.h"
42+
#include "mutex.h"
5143

5244
/**
5345
* @brief Definition of notification event types in the network stack.
@@ -64,13 +56,23 @@ typedef enum {
6456
NETAPI_NOTIFY_L3_UNREACHABLE, /**< Node became unreachable on the network layer. */
6557
} netapi_notify_t;
6658

59+
/**
60+
* @brief Data structure to acknowledge netapi notification events.
61+
*/
62+
typedef struct {
63+
int counter; /**< ACK counter */
64+
cond_t cond; /**< condition variable to signal change in count */
65+
mutex_t lock; /**< lock for counter */
66+
} gnrc_netapi_notify_ack_t;
67+
6768
/**
6869
* @brief Data structure to be sent for netapi notification events.
6970
*/
7071
typedef struct {
71-
netapi_notify_t event; /**< the type of event */
72-
void *_data; /**< associated event data. */
73-
uint16_t _data_len; /**< size of the event data */
72+
netapi_notify_t event; /**< the type of event */
73+
void *_data; /**< associated event data. */
74+
uint16_t _data_len; /**< size of the event data */
75+
gnrc_netapi_notify_ack_t *ack; /**< acknowledge event */
7476
} gnrc_netapi_notify_t;
7577

7678
/**
@@ -83,13 +85,26 @@ typedef struct {
8385
kernel_pid_t if_pid; /**< PID of network interface */
8486
} netapi_notify_l2_connection_t;
8587

88+
/**
89+
* @brief Acknowledge that a notify event was received and its data read.
90+
*
91+
* @param[in] ack Pointer to the event's acknowledgment structure.
92+
*/
93+
static inline void gnrc_netapi_notify_ack(gnrc_netapi_notify_ack_t *ack)
94+
{
95+
mutex_lock(&ack->lock);
96+
ack->counter++;
97+
/* Signal that the counter changed. */
98+
cond_signal(&ack->cond);
99+
mutex_unlock(&ack->lock);
100+
}
101+
86102
/**
87103
* @brief Parse the connection event data associated with @ref NETAPI_NOTIFY_L2_CONNECTED
88104
* and @ref NETAPI_NOTIFY_L2_DISCONNECTED events.
89105
*
90106
* @note This will set the @ref NETAPI_NOTIFY_FLAG_ACK for the sending thread.
91107
*
92-
* @param[in] sender_pid PID of the netapi sender.
93108
* @param[in] notify Pointer to the received notify event.
94109
* @param[out] data Connection data received in the @p notify event.
95110
* data.l2addr_len should be set to the size of the l2addr buffer.
@@ -99,24 +114,21 @@ typedef struct {
99114
* @retval -ENOBUFS if the length of l2addr in @p data is smaller than the
100115
* received l2addr.
101116
*/
102-
uint8_t gnrc_netapi_notify_copy_l2_connection_data(kernel_pid_t sender_pid,
103-
gnrc_netapi_notify_t *notify,
117+
uint8_t gnrc_netapi_notify_copy_l2_connection_data(gnrc_netapi_notify_t *notify,
104118
netapi_notify_l2_connection_t *data);
105119
/**
106120
* @brief Parse the ipv6 address associated with @ref NETAPI_NOTIFY_L3_DISCOVERED and
107121
* @ref NETAPI_NOTIFY_L3_UNREACHABLE events.
108122
*
109123
* @note This will set the @ref NETAPI_NOTIFY_FLAG_ACK for the sending thread.
110124
*
111-
* @param[in] sender_pid PID of the netapi sender.
112125
* @param[in] notify Pointer to the received notify event.
113126
* @param[out] addr IPv6 address of the remote.
114127
*
115128
* @retval sizeof(ipv6_addr_t) on success.
116129
* @retval -EINVAL if @p notify is of a wrong @ref netapi_notify_t type.
117130
*/
118-
int gnrc_netapi_notify_copy_l3_address(kernel_pid_t sender_pid, gnrc_netapi_notify_t *notify,
119-
ipv6_addr_t *addr);
131+
int gnrc_netapi_notify_copy_l3_address(gnrc_netapi_notify_t *notify, ipv6_addr_t *addr);
120132

121133
#ifdef __cplusplus
122134
}

sys/net/gnrc/netapi/gnrc_netapi.c

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
#include "net/gnrc/netapi/notify.h"
2828
#include "net/gnrc/pktbuf.h"
2929
#include "net/gnrc/netapi.h"
30-
#include "thread.h"
30+
#include "cond.h"
31+
#include "mutex.h"
3132

3233
#define ENABLE_DEBUG 0
3334
#include "debug.h"
@@ -152,10 +153,16 @@ int gnrc_netapi_dispatch(gnrc_nettype_t type, uint32_t demux_ctx,
152153
int gnrc_netapi_notify(gnrc_nettype_t type, uint32_t demux_ctx, netapi_notify_t event,
153154
void *data, size_t data_len)
154155
{
156+
gnrc_netapi_notify_ack_t ack = {
157+
.counter = 0,
158+
.cond = COND_INIT,
159+
.lock = MUTEX_INIT,
160+
};
155161
gnrc_netapi_notify_t notify = {
156162
.event = event,
157163
._data = data,
158164
._data_len = data_len,
165+
.ack = &ack
159166
};
160167

161168
gnrc_netreg_acquire_shared();
@@ -166,24 +173,27 @@ int gnrc_netapi_notify(gnrc_nettype_t type, uint32_t demux_ctx, netapi_notify_t
166173
/* Look up the registered threads for this message type. */
167174
gnrc_netreg_entry_t *sendto = gnrc_netreg_lookup(type, demux_ctx);
168175

169-
/* Make sure the ACK flag isn't already set. */
170-
thread_flags_clear(NETAPI_NOTIFY_FLAG_ACK);
171-
172176
/* Dispatch to all registered threads sequentially. */
173177
while (sendto) {
174-
uint32_t status = _dispatch_single(sendto, GNRC_NETAPI_MSG_TYPE_NOTIFY, &notify);
175-
176-
/* Need to wait for an ACK to ensure that the data was read and that
177-
there won't be any dangling pointers after the function returned. */
178-
if (data != NULL && status == 0) {
179-
thread_flags_wait_all(NETAPI_NOTIFY_FLAG_ACK);
178+
int status = _dispatch_single(sendto, GNRC_NETAPI_MSG_TYPE_NOTIFY, &notify);
179+
if (status < 0) {
180+
numof--;
180181
}
181-
182182
sendto = gnrc_netreg_getnext(sendto);
183183
}
184184
}
185185

186186
gnrc_netreg_release_shared();
187187

188+
if (data != NULL) {
189+
/* Wait for ACK from all receivers to ensure that the data was read and
190+
that there won't be any dangling pointers after the function returned. */
191+
mutex_lock(&ack.lock);
192+
while (ack.counter < numof) {
193+
cond_wait(&ack.cond, &ack.lock);
194+
}
195+
mutex_unlock(&ack.lock);
196+
}
197+
188198
return numof;
189199
}

sys/net/gnrc/netapi/notify/gnrc_netapi_notify.c

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,9 @@
1616

1717
#include "net/gnrc/netapi/notify.h"
1818
#include "net/ipv6/addr.h"
19-
#include "sched.h"
20-
#include "thread.h"
2119
#include <sys/errno.h>
2220

23-
uint8_t gnrc_netapi_notify_copy_l2_connection_data(kernel_pid_t sender_pid,
24-
gnrc_netapi_notify_t *notify,
21+
uint8_t gnrc_netapi_notify_copy_l2_connection_data(gnrc_netapi_notify_t *notify,
2522
netapi_notify_l2_connection_t *data)
2623
{
2724
int data_len;
@@ -51,14 +48,13 @@ uint8_t gnrc_netapi_notify_copy_l2_connection_data(kernel_pid_t sender_pid,
5148
break;
5249
}
5350

54-
/* Unblock the sending thread now that all data was copied over. */
55-
thread_flags_set(thread_get(sender_pid), NETAPI_NOTIFY_FLAG_ACK);
51+
/* Acknowledge the read data */
52+
gnrc_netapi_notify_ack(notify->ack);
5653

5754
return data_len;
5855
}
5956

60-
int gnrc_netapi_notify_copy_l3_address(kernel_pid_t sender_pid, gnrc_netapi_notify_t *notify,
61-
ipv6_addr_t *addr)
57+
int gnrc_netapi_notify_copy_l3_address(gnrc_netapi_notify_t *notify, ipv6_addr_t *addr)
6258
{
6359
int data_len;
6460

@@ -77,8 +73,8 @@ int gnrc_netapi_notify_copy_l3_address(kernel_pid_t sender_pid, gnrc_netapi_noti
7773
break;
7874
}
7975

80-
/* Unblock the sending thread now that all data was copied over. */
81-
thread_flags_set(thread_get(sender_pid), NETAPI_NOTIFY_FLAG_ACK);
76+
/* Acknowledge the read data */
77+
gnrc_netapi_notify_ack(notify->ack);
8278

8379
return data_len;
8480
}

sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ static inline void _on_l2_disconnected(kernel_pid_t if_pid, uint8_t *l2addr, uin
241241
*
242242
* @param[in] notify The type of notification.
243243
*/
244-
static inline void _netapi_notify_event(kernel_pid_t sender_pid, gnrc_netapi_notify_t *notify)
244+
static inline void _netapi_notify_event(gnrc_netapi_notify_t *notify)
245245
{
246246
uint8_t l2addr[CONFIG_GNRC_IPV6_NIB_L2ADDR_MAX_LEN];
247247
netapi_notify_l2_connection_t data = {
@@ -251,7 +251,7 @@ static inline void _netapi_notify_event(kernel_pid_t sender_pid, gnrc_netapi_not
251251
};
252252
netapi_notify_t type = notify->event;
253253

254-
if (gnrc_netapi_notify_copy_l2_connection_data(sender_pid, notify, &data) <= 0) {
254+
if (gnrc_netapi_notify_copy_l2_connection_data(notify, &data) <= 0) {
255255
DEBUG("ipv6: invalid data on netapi notify event.\n");
256256
return;
257257
}
@@ -320,7 +320,7 @@ static void *_event_loop(void *args)
320320
break;
321321
case GNRC_NETAPI_MSG_TYPE_NOTIFY:
322322
DEBUG("ipv6: GNRC_NETAPI_MSG_TYPE_NOTIFY received\n");
323-
_netapi_notify_event(msg.sender_pid, msg.content.ptr);
323+
_netapi_notify_event(msg.content.ptr);
324324
break;
325325

326326
#ifdef MODULE_GNRC_IPV6_EXT_FRAG

sys/net/gnrc/routing/rpl/gnrc_rpl.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -314,13 +314,12 @@ static inline void _handle_unreachable_neighbor(ipv6_addr_t *addr)
314314
*
315315
* @param[in] notify The type of notification.
316316
*/
317-
static inline void _netapi_notify_event(kernel_pid_t sender_pid, gnrc_netapi_notify_t *notify)
317+
static inline void _netapi_notify_event(gnrc_netapi_notify_t *notify)
318318
{
319319
ipv6_addr_t neigh_addr;
320320
netapi_notify_t type = notify->event;
321321

322-
if (gnrc_netapi_notify_copy_l3_address(sender_pid, notify,
323-
&neigh_addr) != sizeof(ipv6_addr_t)) {
322+
if (gnrc_netapi_notify_copy_l3_address(notify, &neigh_addr) != sizeof(ipv6_addr_t)) {
324323
DEBUG("RPL: Received invalid data for netapi notify event.\n");
325324
return;
326325
}
@@ -408,7 +407,7 @@ static void *_event_loop(void *args)
408407
break;
409408
case GNRC_NETAPI_MSG_TYPE_NOTIFY:
410409
DEBUG("RPL: GNRC_NETAPI_MSG_TYPE_NOTIFY received\n");
411-
_netapi_notify_event(msg.sender_pid, msg.content.ptr);
410+
_netapi_notify_event(msg.content.ptr);
412411
break;
413412
default:
414413
break;

0 commit comments

Comments
 (0)