1 /*
2 * Copyright (c) 2017 Simon Goldschmidt
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
25 * OF SUCH DAMAGE.
26 *
27 * This file is part of the lwIP TCP/IP stack.
28 *
29 * Author: Simon Goldschmidt <goldsimon@gmx.de>
30 *
31 */
32
33 /* lwIP includes. */
34 #include "lwip/debug.h"
35 #include "lwip/def.h"
36 #include "lwip/sys.h"
37 #include "lwip/mem.h"
38 #include "lwip/stats.h"
39 #include "lwip/tcpip.h"
40 #include "FreeRTOS.h"
41 #include "semphr.h"
42 #include "task.h"
43
44 /** Set this to 1 if you want the stack size passed to sys_thread_new() to be
45 * interpreted as number of stack words (FreeRTOS-like).
46 * Default is that they are interpreted as byte count (lwIP-like).
47 */
48 #ifndef LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS
49 #define LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS 0
50 #endif
51
52 /** Set this to 1 to use a mutex for SYS_ARCH_PROTECT() critical regions.
53 * Default is 0 and locks interrupts/scheduler for SYS_ARCH_PROTECT().
54 */
55 #ifndef LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX
56 #define LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX 0
57 #endif
58
59 /** Set this to 1 to include a sanity check that SYS_ARCH_PROTECT() and
60 * SYS_ARCH_UNPROTECT() are called matching.
61 */
62 #ifndef LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK
63 #define LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK 0
64 #endif
65
66 /** Set this to 1 to let sys_mbox_free check that queues are empty when freed */
67 #ifndef LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE
68 #define LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE 0
69 #endif
70
71 /** Set this to 1 to enable core locking check functions in this port.
72 * For this to work, you'll have to define LWIP_ASSERT_CORE_LOCKED()
73 * and LWIP_MARK_TCPIP_THREAD() correctly in your lwipopts.h! */
74 #ifndef LWIP_FREERTOS_CHECK_CORE_LOCKING
75 #define LWIP_FREERTOS_CHECK_CORE_LOCKING 0
76 #endif
77
78 /** Set this to 0 to implement sys_now() yourself, e.g. using a hw timer.
79 * Default is 1, where FreeRTOS ticks are used to calculate back to ms.
80 */
81 #ifndef LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS
82 #define LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS 1
83 #endif
84
85 #if !configSUPPORT_DYNAMIC_ALLOCATION
86 # error "lwIP FreeRTOS port requires configSUPPORT_DYNAMIC_ALLOCATION"
87 #endif
88 #if !INCLUDE_vTaskDelay
89 # error "lwIP FreeRTOS port requires INCLUDE_vTaskDelay"
90 #endif
91 #if !INCLUDE_vTaskSuspend
92 # error "lwIP FreeRTOS port requires INCLUDE_vTaskSuspend"
93 #endif
94 #if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX || !LWIP_COMPAT_MUTEX
95 #if !configUSE_MUTEXES
96 # error "lwIP FreeRTOS port requires configUSE_MUTEXES"
97 #endif
98 #endif
99
100 #if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX
101 static SemaphoreHandle_t sys_arch_protect_mutex;
102 #endif
103 #if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK
104 static sys_prot_t sys_arch_protect_nesting;
105 #endif
106
107 /* Initialize this module (see description in sys.h) */
108 void
sys_init(void)109 sys_init(void)
110 {
111 #if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX
112 /* initialize sys_arch_protect global mutex */
113 sys_arch_protect_mutex = xSemaphoreCreateRecursiveMutex();
114 LWIP_ASSERT("failed to create sys_arch_protect mutex",
115 sys_arch_protect_mutex != NULL);
116 #endif /* SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */
117 }
118
119 #if configUSE_16_BIT_TICKS == 1
120 #error This port requires 32 bit ticks or timer overflow will fail
121 #endif
122
123 #if LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS
124 u32_t
sys_now(void)125 sys_now(void)
126 {
127 return xTaskGetTickCount() * portTICK_PERIOD_MS;
128 }
129 #endif
130
131 u32_t
sys_jiffies(void)132 sys_jiffies(void)
133 {
134 return xTaskGetTickCount();
135 }
136
137 #if SYS_LIGHTWEIGHT_PROT
138
139 sys_prot_t
sys_arch_protect(void)140 sys_arch_protect(void)
141 {
142 #if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX
143 BaseType_t ret;
144 LWIP_ASSERT("sys_arch_protect_mutex != NULL", sys_arch_protect_mutex != NULL);
145
146 ret = xSemaphoreTakeRecursive(sys_arch_protect_mutex, portMAX_DELAY);
147 LWIP_ASSERT("sys_arch_protect failed to take the mutex", ret == pdTRUE);
148 #else /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */
149 taskENTER_CRITICAL();
150 #endif /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */
151 #if LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK
152 {
153 /* every nested call to sys_arch_protect() returns an increased number */
154 sys_prot_t ret = sys_arch_protect_nesting;
155 sys_arch_protect_nesting++;
156 LWIP_ASSERT("sys_arch_protect overflow", sys_arch_protect_nesting > ret);
157 return ret;
158 }
159 #else
160 return 1;
161 #endif
162 }
163
164 void
sys_arch_unprotect(sys_prot_t pval)165 sys_arch_unprotect(sys_prot_t pval)
166 {
167 #if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX
168 BaseType_t ret;
169 #endif
170 #if LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK
171 LWIP_ASSERT("unexpected sys_arch_protect_nesting", sys_arch_protect_nesting > 0);
172 sys_arch_protect_nesting--;
173 LWIP_ASSERT("unexpected sys_arch_protect_nesting", sys_arch_protect_nesting == pval);
174 #endif
175
176 #if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX
177 LWIP_ASSERT("sys_arch_protect_mutex != NULL", sys_arch_protect_mutex != NULL);
178
179 ret = xSemaphoreGiveRecursive(sys_arch_protect_mutex);
180 LWIP_ASSERT("sys_arch_unprotect failed to give the mutex", ret == pdTRUE);
181 #else /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */
182 taskEXIT_CRITICAL();
183 #endif /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */
184 LWIP_UNUSED_ARG(pval);
185 }
186
187 #endif /* SYS_LIGHTWEIGHT_PROT */
188
189 void
sys_arch_msleep(u32_t delay_ms)190 sys_arch_msleep(u32_t delay_ms)
191 {
192 TickType_t delay_ticks = delay_ms / portTICK_RATE_MS;
193 vTaskDelay(delay_ticks);
194 }
195
196 #if !LWIP_COMPAT_MUTEX
197
198 /* Create a new mutex*/
199 err_t
sys_mutex_new(sys_mutex_t * mutex)200 sys_mutex_new(sys_mutex_t *mutex)
201 {
202 LWIP_ASSERT("mutex != NULL", mutex != NULL);
203
204 mutex->mut = xSemaphoreCreateRecursiveMutex();
205 if(mutex->mut == NULL) {
206 SYS_STATS_INC(mutex.err);
207 return ERR_MEM;
208 }
209 SYS_STATS_INC_USED(mutex);
210 return ERR_OK;
211 }
212
213 void
sys_mutex_lock(sys_mutex_t * mutex)214 sys_mutex_lock(sys_mutex_t *mutex)
215 {
216 BaseType_t ret;
217 LWIP_ASSERT("mutex != NULL", mutex != NULL);
218 LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);
219
220 ret = xSemaphoreTakeRecursive(mutex->mut, portMAX_DELAY);
221 LWIP_ASSERT("failed to take the mutex", ret == pdTRUE);
222 }
223
224 void
sys_mutex_unlock(sys_mutex_t * mutex)225 sys_mutex_unlock(sys_mutex_t *mutex)
226 {
227 BaseType_t ret;
228 LWIP_ASSERT("mutex != NULL", mutex != NULL);
229 LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);
230
231 ret = xSemaphoreGiveRecursive(mutex->mut);
232 LWIP_ASSERT("failed to give the mutex", ret == pdTRUE);
233 }
234
235 void
sys_mutex_free(sys_mutex_t * mutex)236 sys_mutex_free(sys_mutex_t *mutex)
237 {
238 LWIP_ASSERT("mutex != NULL", mutex != NULL);
239 LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);
240
241 SYS_STATS_DEC(mutex.used);
242 vSemaphoreDelete(mutex->mut);
243 mutex->mut = NULL;
244 }
245
246 #endif /* !LWIP_COMPAT_MUTEX */
247
248 err_t
sys_sem_new(sys_sem_t * sem,u8_t initial_count)249 sys_sem_new(sys_sem_t *sem, u8_t initial_count)
250 {
251 LWIP_ASSERT("sem != NULL", sem != NULL);
252 LWIP_ASSERT("initial_count invalid (not 0 or 1)",
253 (initial_count == 0) || (initial_count == 1));
254
255 sem->sem = xSemaphoreCreateBinary();
256 if(sem->sem == NULL) {
257 SYS_STATS_INC(sem.err);
258 return ERR_MEM;
259 }
260 SYS_STATS_INC_USED(sem);
261
262 if(initial_count == 1) {
263 BaseType_t ret = xSemaphoreGive(sem->sem);
264 LWIP_ASSERT("sys_sem_new: initial give failed", ret == pdTRUE);
265 }
266 return ERR_OK;
267 }
268
269 void
sys_sem_signal(sys_sem_t * sem)270 sys_sem_signal(sys_sem_t *sem)
271 {
272 BaseType_t ret;
273 LWIP_ASSERT("sem != NULL", sem != NULL);
274 LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL);
275
276 ret = xSemaphoreGive(sem->sem);
277 /* queue full is OK, this is a signal only... */
278 LWIP_ASSERT("sys_sem_signal: sane return value",
279 (ret == pdTRUE) || (ret == errQUEUE_FULL));
280 }
281
282 u32_t
sys_arch_sem_wait(sys_sem_t * sem,u32_t timeout_ms)283 sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout_ms)
284 {
285 BaseType_t ret;
286 LWIP_ASSERT("sem != NULL", sem != NULL);
287 LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL);
288
289 if(!timeout_ms) {
290 /* wait infinite */
291 ret = xSemaphoreTake(sem->sem, portMAX_DELAY);
292 LWIP_ASSERT("taking semaphore failed", ret == pdTRUE);
293 } else {
294 TickType_t timeout_ticks = timeout_ms / portTICK_RATE_MS;
295 ret = xSemaphoreTake(sem->sem, timeout_ticks);
296 if (ret == errQUEUE_EMPTY) {
297 /* timed out */
298 return SYS_ARCH_TIMEOUT;
299 }
300 LWIP_ASSERT("taking semaphore failed", ret == pdTRUE);
301 }
302
303 /* Old versions of lwIP required us to return the time waited.
304 This is not the case any more. Just returning != SYS_ARCH_TIMEOUT
305 here is enough. */
306 return 1;
307 }
308
309 void
sys_sem_free(sys_sem_t * sem)310 sys_sem_free(sys_sem_t *sem)
311 {
312 LWIP_ASSERT("sem != NULL", sem != NULL);
313 LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL);
314
315 SYS_STATS_DEC(sem.used);
316 vSemaphoreDelete(sem->sem);
317 sem->sem = NULL;
318 }
319
320 err_t
sys_mbox_new(sys_mbox_t * mbox,int size)321 sys_mbox_new(sys_mbox_t *mbox, int size)
322 {
323 LWIP_ASSERT("mbox != NULL", mbox != NULL);
324 LWIP_ASSERT("size > 0", size > 0);
325
326 mbox->mbx = xQueueCreate((UBaseType_t)size, sizeof(void *));
327 if(mbox->mbx == NULL) {
328 SYS_STATS_INC(mbox.err);
329 return ERR_MEM;
330 }
331 SYS_STATS_INC_USED(mbox);
332 return ERR_OK;
333 }
334
335 void
sys_mbox_post(sys_mbox_t * mbox,void * msg)336 sys_mbox_post(sys_mbox_t *mbox, void *msg)
337 {
338 BaseType_t ret;
339 LWIP_ASSERT("mbox != NULL", mbox != NULL);
340 LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
341
342 ret = xQueueSendToBack(mbox->mbx, &msg, portMAX_DELAY);
343 LWIP_ASSERT("mbox post failed", ret == pdTRUE);
344 }
345
346 err_t
sys_mbox_trypost(sys_mbox_t * mbox,void * msg)347 sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
348 {
349 BaseType_t ret;
350 LWIP_ASSERT("mbox != NULL", mbox != NULL);
351 LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
352
353 ret = xQueueSendToBack(mbox->mbx, &msg, 0);
354 if (ret == pdTRUE) {
355 return ERR_OK;
356 } else {
357 LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL);
358 SYS_STATS_INC(mbox.err);
359 return ERR_MEM;
360 }
361 }
362
363 err_t
sys_mbox_trypost_fromisr(sys_mbox_t * mbox,void * msg)364 sys_mbox_trypost_fromisr(sys_mbox_t *mbox, void *msg)
365 {
366 BaseType_t ret;
367 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
368 LWIP_ASSERT("mbox != NULL", mbox != NULL);
369 LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
370
371 ret = xQueueSendToBackFromISR(mbox->mbx, &msg, &xHigherPriorityTaskWoken);
372 if (ret == pdTRUE) {
373 if (xHigherPriorityTaskWoken == pdTRUE) {
374 return ERR_NEED_SCHED;
375 }
376 return ERR_OK;
377 } else {
378 LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL);
379 SYS_STATS_INC(mbox.err);
380 return ERR_MEM;
381 }
382 }
383
384 u32_t
sys_arch_mbox_fetch(sys_mbox_t * mbox,void ** msg,u32_t timeout_ms)385 sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout_ms)
386 {
387 BaseType_t ret;
388 void *msg_dummy;
389 LWIP_ASSERT("mbox != NULL", mbox != NULL);
390 LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
391
392 if (!msg) {
393 msg = &msg_dummy;
394 }
395
396 if (!timeout_ms) {
397 /* wait infinite */
398 ret = xQueueReceive(mbox->mbx, &(*msg), portMAX_DELAY);
399 LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
400 } else {
401 TickType_t timeout_ticks = timeout_ms / portTICK_RATE_MS;
402 ret = xQueueReceive(mbox->mbx, &(*msg), timeout_ticks);
403 if (ret == errQUEUE_EMPTY) {
404 /* timed out */
405 *msg = NULL;
406 return SYS_ARCH_TIMEOUT;
407 }
408 LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
409 }
410
411 /* Old versions of lwIP required us to return the time waited.
412 This is not the case any more. Just returning != SYS_ARCH_TIMEOUT
413 here is enough. */
414 return 1;
415 }
416
417 u32_t
sys_arch_mbox_tryfetch(sys_mbox_t * mbox,void ** msg)418 sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
419 {
420 BaseType_t ret;
421 void *msg_dummy;
422 LWIP_ASSERT("mbox != NULL", mbox != NULL);
423 LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
424
425 if (!msg) {
426 msg = &msg_dummy;
427 }
428
429 ret = xQueueReceive(mbox->mbx, &(*msg), 0);
430 if (ret == errQUEUE_EMPTY) {
431 *msg = NULL;
432 return SYS_MBOX_EMPTY;
433 }
434 LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
435
436 return 0;
437 }
438
439 void
sys_mbox_free(sys_mbox_t * mbox)440 sys_mbox_free(sys_mbox_t *mbox)
441 {
442 LWIP_ASSERT("mbox != NULL", mbox != NULL);
443 LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
444
445 #if LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE
446 {
447 UBaseType_t msgs_waiting = uxQueueMessagesWaiting(mbox->mbx);
448 LWIP_ASSERT("mbox quence not empty", msgs_waiting == 0);
449
450 if (msgs_waiting != 0) {
451 SYS_STATS_INC(mbox.err);
452 }
453 }
454 #endif
455
456 vQueueDelete(mbox->mbx);
457
458 SYS_STATS_DEC(mbox.used);
459 }
460
461 sys_thread_t
sys_thread_new(const char * name,lwip_thread_fn thread,void * arg,int stacksize,int prio)462 sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
463 {
464 TaskHandle_t rtos_task;
465 BaseType_t ret;
466 sys_thread_t lwip_thread;
467 size_t rtos_stacksize;
468
469 LWIP_ASSERT("invalid stacksize", stacksize > 0);
470 #if LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS
471 rtos_stacksize = (size_t)stacksize;
472 #else
473 rtos_stacksize = (size_t)stacksize / sizeof(StackType_t);
474 #endif
475
476 /* lwIP's lwip_thread_fn matches FreeRTOS' TaskFunction_t, so we can pass the
477 thread function without adaption here. */
478 ret = xTaskCreate(thread, name, (configSTACK_DEPTH_TYPE)rtos_stacksize, arg, prio, &rtos_task);
479 LWIP_ASSERT("task creation failed", ret == pdTRUE);
480
481 lwip_thread.thread_handle = rtos_task;
482 return lwip_thread;
483 }
484
485 #if LWIP_NETCONN_SEM_PER_THREAD
486 #if configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0
487
488 sys_sem_t *
sys_arch_netconn_sem_get(void)489 sys_arch_netconn_sem_get(void)
490 {
491 void* ret;
492 TaskHandle_t task = xTaskGetCurrentTaskHandle();
493 LWIP_ASSERT("task != NULL", task != NULL);
494
495 ret = pvTaskGetThreadLocalStoragePointer(task, 0);
496 return ret;
497 }
498
499 void
sys_arch_netconn_sem_alloc(void)500 sys_arch_netconn_sem_alloc(void)
501 {
502 void *ret;
503 TaskHandle_t task = xTaskGetCurrentTaskHandle();
504 LWIP_ASSERT("task != NULL", task != NULL);
505
506 ret = pvTaskGetThreadLocalStoragePointer(task, 0);
507 if(ret == NULL) {
508 sys_sem_t *sem;
509 err_t err;
510 /* need to allocate the memory for this semaphore */
511 sem = mem_malloc(sizeof(sys_sem_t));
512 LWIP_ASSERT("sem != NULL", sem != NULL);
513 err = sys_sem_new(sem, 0);
514 LWIP_ASSERT("err == ERR_OK", err == ERR_OK);
515 LWIP_ASSERT("sem invalid", sys_sem_valid(sem));
516 vTaskSetThreadLocalStoragePointer(task, 0, sem);
517 }
518 }
519
sys_arch_netconn_sem_free(void)520 void sys_arch_netconn_sem_free(void)
521 {
522 void* ret;
523 TaskHandle_t task = xTaskGetCurrentTaskHandle();
524 LWIP_ASSERT("task != NULL", task != NULL);
525
526 ret = pvTaskGetThreadLocalStoragePointer(task, 0);
527 if(ret != NULL) {
528 sys_sem_t *sem = ret;
529 sys_sem_free(sem);
530 mem_free(sem);
531 vTaskSetThreadLocalStoragePointer(task, 0, NULL);
532 }
533 }
534
535 #else /* configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 */
536 #error LWIP_NETCONN_SEM_PER_THREAD needs configNUM_THREAD_LOCAL_STORAGE_POINTERS
537 #endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 */
538
539 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
540
541 #if LWIP_FREERTOS_CHECK_CORE_LOCKING
542 #if LWIP_TCPIP_CORE_LOCKING
543
544 /** Flag the core lock held. A counter for recursive locks. */
545 static u8_t lwip_core_lock_count;
546 static TaskHandle_t lwip_core_lock_holder_thread;
547
548 void
sys_lock_tcpip_core(void)549 sys_lock_tcpip_core(void)
550 {
551 sys_mutex_lock(&lock_tcpip_core);
552 if (lwip_core_lock_count == 0) {
553 lwip_core_lock_holder_thread = xTaskGetCurrentTaskHandle();
554 }
555 lwip_core_lock_count++;
556 }
557
558 void
sys_unlock_tcpip_core(void)559 sys_unlock_tcpip_core(void)
560 {
561 lwip_core_lock_count--;
562 if (lwip_core_lock_count == 0) {
563 lwip_core_lock_holder_thread = 0;
564 }
565 sys_mutex_unlock(&lock_tcpip_core);
566 }
567
568 #endif /* LWIP_TCPIP_CORE_LOCKING */
569
570 #if !NO_SYS
571 static TaskHandle_t lwip_tcpip_thread;
572 #endif
573
574 void
sys_mark_tcpip_thread(void)575 sys_mark_tcpip_thread(void)
576 {
577 #if !NO_SYS
578 lwip_tcpip_thread = xTaskGetCurrentTaskHandle();
579 #endif
580 }
581
582 void
sys_check_core_locking(void)583 sys_check_core_locking(void)
584 {
585 /* Embedded systems should check we are NOT in an interrupt context here */
586 /* E.g. core Cortex-M3/M4 ports:
587 configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
588
589 Instead, we use more generic FreeRTOS functions here, which should fail from ISR: */
590 taskENTER_CRITICAL();
591 taskEXIT_CRITICAL();
592
593 #if !NO_SYS
594 if (lwip_tcpip_thread != 0) {
595 TaskHandle_t current_thread = xTaskGetCurrentTaskHandle();
596
597 #if LWIP_TCPIP_CORE_LOCKING
598 LWIP_ASSERT("Function called without core lock",
599 current_thread == lwip_core_lock_holder_thread && lwip_core_lock_count > 0);
600 #else /* LWIP_TCPIP_CORE_LOCKING */
601 LWIP_ASSERT("Function called from wrong thread", current_thread == lwip_tcpip_thread);
602 #endif /* LWIP_TCPIP_CORE_LOCKING */
603 }
604 #endif /* !NO_SYS */
605 }
606
607 #endif /* LWIP_FREERTOS_CHECK_CORE_LOCKING*/
608