3
3
* See file LICENSE for full license details.
4
4
*
5
5
*/
6
+ #include <errno.h>
6
7
#include <stdbool.h>
7
8
#include <stdlib.h>
8
9
#include <pthread.h>
14
15
#define MAX_LOG_LEVEL INFO_LOG_LEVEL
15
16
#include "logger.h"
16
17
#include "platform.h"
18
+ #include "reassembly.h"
19
+ #include "wpc_proto.h"
17
20
18
21
// Maximum number of indication to be retrieved from a single poll
19
22
#define MAX_NUMBER_INDICATION 30
20
23
21
24
// Polling interval to check for indication
22
25
#define POLLING_INTERVAL_MS 20
23
26
27
+ // Wakeup timeout for dispatch thread, mainly for garbage collection of fragments
28
+ #define DISPATCH_WAKEUP_TIMEOUT_MS 5000
29
+
24
30
// Mutex for sending, ie serial access
25
31
static pthread_mutex_t sending_mutex ;
26
32
27
33
// This thread is used to poll for indication
28
34
static pthread_t thread_polling ;
29
35
30
- // Set to false to stop polling thread execution
31
- static bool m_polling_thread_running ;
36
+ typedef enum {
37
+ POLLING_THREAD_RUN ,
38
+ POLLING_THREAD_STOP ,
39
+ POLLING_THREAD_STOP_REQUESTED
40
+ } polling_thread_state_t ;
41
+
42
+ // Request to handle polling thread state
43
+ static polling_thread_state_t m_polling_thread_state_request = POLLING_THREAD_STOP ;
32
44
33
45
// This thread is used to dispatch indication
34
46
static pthread_t thread_dispatch ;
@@ -85,13 +97,20 @@ static pthread_cond_t m_queue_not_empty_cond = PTHREAD_COND_INITIALIZER;
85
97
*/
86
98
static void * dispatch_indication (void * unused )
87
99
{
100
+ struct timespec ts ;
101
+
88
102
pthread_mutex_lock (& m_queue_mutex );
89
103
while (m_dispatch_thread_running )
90
104
{
91
105
if (m_queue_empty )
92
106
{
93
107
// Queue is empty, wait
94
- pthread_cond_wait (& m_queue_not_empty_cond , & m_queue_mutex );
108
+ clock_gettime (CLOCK_REALTIME , & ts );
109
+ ts .tv_sec += DISPATCH_WAKEUP_TIMEOUT_MS ; // 5 second timeout
110
+ pthread_cond_timedwait (& m_queue_not_empty_cond , & m_queue_mutex , & ts );
111
+
112
+ // Force a garbage collect (to be sure it's called even if no frag are received)
113
+ reassembly_garbage_collect ();
95
114
96
115
// Check if we wake up but nothing in queue
97
116
if (m_queue_empty )
@@ -170,10 +189,29 @@ static void * poll_for_indication(void * unused)
170
189
// Initially wait for 500ms before any polling
171
190
uint32_t wait_before_next_polling_ms = 500 ;
172
191
173
- while (m_polling_thread_running )
192
+ m_polling_thread_state_request = POLLING_THREAD_RUN ;
193
+
194
+ while (m_polling_thread_state_request != POLLING_THREAD_STOP )
174
195
{
175
196
usleep (wait_before_next_polling_ms * 1000 );
176
197
198
+ if (m_polling_thread_state_request == POLLING_THREAD_STOP_REQUESTED )
199
+ {
200
+ if (!m_queue_empty )
201
+ {
202
+ // Dispatch did not process all indications. Just wait for it to complete.
203
+ wait_before_next_polling_ms = POLLING_INTERVAL_MS ;
204
+ continue ;
205
+ }
206
+
207
+ if (reassembly_is_queue_empty ())
208
+ {
209
+ LOGI ("Reassembly queue is empty, exiting polling thread\n" );
210
+ m_polling_thread_state_request = POLLING_THREAD_STOP ;
211
+ break ;
212
+ }
213
+ }
214
+
177
215
// Get the number of free buffers in the indication queue
178
216
// Note: No need to lock the queue as only m_ind_queue_read can be updated
179
217
// and could still be modified when we release the lock after computing
@@ -207,16 +245,26 @@ static void * poll_for_indication(void * unused)
207
245
free_buffer_room = m_ind_queue_read - m_ind_queue_write ;
208
246
}
209
247
}
210
-
211
- max_num_indication = free_buffer_room > MAX_NUMBER_INDICATION ?
212
- MAX_NUMBER_INDICATION :
213
- free_buffer_room ;
248
+
249
+ if (m_polling_thread_state_request == POLLING_THREAD_STOP_REQUESTED )
250
+ {
251
+ // In case we are about to stop, let's poll only one by one to have more chance to
252
+ // finish uncomplete fragmented packet and not start to receive a new one
253
+ max_num_indication = 1 ;
254
+ LOGD ("Poll for one more fragment to empty reassembly queue\n" );
255
+ }
256
+ else
257
+ {
258
+ // Let's read max indications that can fit in the queue
259
+ max_num_indication = MIN (MAX_NUMBER_INDICATION , free_buffer_room );
260
+ }
214
261
215
262
LOGD ("Poll for %d indications\n" , max_num_indication );
216
263
217
264
get_ind_res = m_get_indication_f (max_num_indication , onIndicationReceivedLocked );
218
265
219
- if (get_ind_res == 1 )
266
+ if ((get_ind_res == 1 )
267
+ && (m_polling_thread_state_request != POLLING_THREAD_STOP_REQUESTED ))
220
268
{
221
269
// Still pending indication, only wait 1 ms to give a chance
222
270
// to other threads but not more to have better throughput
@@ -226,6 +274,7 @@ static void * poll_for_indication(void * unused)
226
274
{
227
275
// In case of error or if no more indication, just wait
228
276
// the POLLING INTERVAL to avoid polling all the time
277
+ // In case of stop request, wait for to give time to push data received
229
278
wait_before_next_polling_ms = POLLING_INTERVAL_MS ;
230
279
}
231
280
}
@@ -242,7 +291,14 @@ bool Platform_lock_request()
242
291
{
243
292
// It must never happen but add a check and
244
293
// return to avoid a deadlock
245
- LOGE ("Mutex already locked %d\n" , res );
294
+ if (res == EINVAL )
295
+ {
296
+ LOGW ("Mutex no longer exists (destroyed)\n" );
297
+ }
298
+ else
299
+ {
300
+ LOGE ("Mutex lock failed %d\n" , res );
301
+ }
246
302
return false;
247
303
}
248
304
return true;
@@ -320,7 +376,6 @@ bool Platform_init(Platform_get_indication_f get_indication_f,
320
376
goto error2 ;
321
377
}
322
378
323
- m_polling_thread_running = true;
324
379
// Start a thread to poll for indication
325
380
if (pthread_create (& thread_polling , NULL , poll_for_indication , NULL ) != 0 )
326
381
{
@@ -352,21 +407,23 @@ void Platform_close()
352
407
{
353
408
void * res ;
354
409
pthread_t cur_thread = pthread_self ();
355
- // Signal our dispatch thread to stop
356
- m_dispatch_thread_running = false;
357
- // Signal condition to wakeup thread
358
- pthread_cond_signal (& m_queue_not_empty_cond );
359
410
360
411
// Signal our polling thread to stop
361
412
// No need to signal it as it will wakeup periodically
362
- m_polling_thread_running = false ;
413
+ m_polling_thread_state_request = POLLING_THREAD_STOP_REQUESTED ;
363
414
364
- // Wait for both tread to finish
415
+ // Wait for polling tread to finish
365
416
if (cur_thread != thread_polling )
366
417
{
367
418
pthread_join (thread_polling , & res );
368
419
}
369
420
421
+ // Signal our dispatch thread to stop
422
+ m_dispatch_thread_running = false;
423
+ // Signal condition to wakeup thread
424
+ pthread_cond_signal (& m_queue_not_empty_cond );
425
+
426
+ // Wait for dispatch tread to finish
370
427
if (cur_thread != thread_dispatch )
371
428
{
372
429
pthread_join (thread_dispatch , & res );
0 commit comments