• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
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: Adam Dunkels <adam@sics.se>
30  *
31  */
32 
33 /* lwIP includes. */
34 
35 #include <pthread.h>
36 #include "lwip/debug.h"
37 #include "lwip/def.h"
38 #include "lwip/sys.h"
39 #include "lwip/mem.h"
40 #include "arch/sys_arch.h"
41 #include "lwip/stats.h"
42 #include "esp_log.h"
43 #include "esp_compiler.h"
44 
45 static const char* TAG = "lwip_arch";
46 
47 static sys_mutex_t g_lwip_protect_mutex = NULL;
48 
49 static pthread_key_t sys_thread_sem_key;
50 static void sys_thread_sem_free(void* data);
51 
52 #if !LWIP_COMPAT_MUTEX
53 
54 /**
55  * @brief Create a new mutex
56  *
57  * @param pxMutex pointer of the mutex to create
58  * @return ERR_OK on success, ERR_MEM when out of memory
59  */
60 err_t
sys_mutex_new(sys_mutex_t * pxMutex)61 sys_mutex_new(sys_mutex_t *pxMutex)
62 {
63   *pxMutex = xSemaphoreCreateMutex();
64   if (*pxMutex == NULL) {
65     LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mutex_new: out of mem\r\n"));
66     return ERR_MEM;
67   }
68 
69   LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mutex_new: m=%p\n", *pxMutex));
70 
71   return ERR_OK;
72 }
73 
74 /**
75  * @brief Lock a mutex
76  *
77  * @param pxMutex pointer of mutex to lock
78  */
79 void
sys_mutex_lock(sys_mutex_t * pxMutex)80 sys_mutex_lock(sys_mutex_t *pxMutex)
81 {
82   BaseType_t ret = xSemaphoreTake(*pxMutex, portMAX_DELAY);
83 
84   LWIP_ASSERT("failed to take the mutex", ret == pdTRUE);
85 }
86 
87 /**
88  * @brief Unlock a mutex
89  *
90  * @param pxMutex pointer of mutex to unlock
91  */
92 void
sys_mutex_unlock(sys_mutex_t * pxMutex)93 sys_mutex_unlock(sys_mutex_t *pxMutex)
94 {
95   BaseType_t ret = xSemaphoreGive(*pxMutex);
96 
97   LWIP_ASSERT("failed to give the mutex", ret == pdTRUE);
98 }
99 
100 /**
101  * @brief Delete a mutex
102  *
103  * @param pxMutex pointer of mutex to delete
104  */
105 void
sys_mutex_free(sys_mutex_t * pxMutex)106 sys_mutex_free(sys_mutex_t *pxMutex)
107 {
108   LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mutex_free: m=%p\n", *pxMutex));
109   vSemaphoreDelete(*pxMutex);
110   *pxMutex = NULL;
111 }
112 
113 #endif /* !LWIP_COMPAT_MUTEX */
114 
115 /**
116  * @brief Creates a new semaphore
117  *
118  * @param sem pointer of the semaphore
119  * @param count initial state of the semaphore
120  * @return err_t
121  */
122 err_t
sys_sem_new(sys_sem_t * sem,u8_t count)123 sys_sem_new(sys_sem_t *sem, u8_t count)
124 {
125   LWIP_ASSERT("initial_count invalid (neither 0 nor 1)",
126              (count == 0) || (count == 1));
127 
128   *sem = xSemaphoreCreateBinary();
129   if (*sem == NULL) {
130       LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_sem_new: out of mem\r\n"));
131       return ERR_MEM;
132   }
133 
134   if (count == 1) {
135       BaseType_t ret = xSemaphoreGive(*sem);
136       LWIP_ASSERT("sys_sem_new: initial give failed", ret == pdTRUE);
137   }
138 
139   return ERR_OK;
140 }
141 
142 /**
143  * @brief Signals a semaphore
144  *
145  * @param sem pointer of the semaphore
146  */
147 void
sys_sem_signal(sys_sem_t * sem)148 sys_sem_signal(sys_sem_t *sem)
149 {
150   BaseType_t ret = xSemaphoreGive(*sem);
151   /* queue full is OK, this is a signal only... */
152   LWIP_ASSERT("sys_sem_signal: sane return value",
153              (ret == pdTRUE) || (ret == errQUEUE_FULL));
154 }
155 
156 /*-----------------------------------------------------------------------------------*/
157 // Signals a semaphore (from ISR)
158 int
sys_sem_signal_isr(sys_sem_t * sem)159 sys_sem_signal_isr(sys_sem_t *sem)
160 {
161     BaseType_t woken = pdFALSE;
162     xSemaphoreGiveFromISR(*sem, &woken);
163     return woken == pdTRUE;
164 }
165 
166 /**
167  * @brief Wait for a semaphore to be signaled
168  *
169  * @param sem pointer of the semaphore
170  * @param timeout if zero, will wait infinitely, or will wait for milliseconds specify by this argument
171  * @return SYS_ARCH_TIMEOUT when timeout, 0 otherwise
172  */
173 u32_t
sys_arch_sem_wait(sys_sem_t * sem,u32_t timeout)174 sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
175 {
176   BaseType_t ret;
177 
178   if (!timeout) {
179     /* wait infinite */
180     ret = xSemaphoreTake(*sem, portMAX_DELAY);
181     LWIP_ASSERT("taking semaphore failed", ret == pdTRUE);
182   } else {
183     TickType_t timeout_ticks = timeout / portTICK_RATE_MS;
184     ret = xSemaphoreTake(*sem, timeout_ticks);
185     if (ret == errQUEUE_EMPTY) {
186       /* timed out */
187       return SYS_ARCH_TIMEOUT;
188     }
189     LWIP_ASSERT("taking semaphore failed", ret == pdTRUE);
190   }
191 
192   return 0;
193 }
194 
195 /**
196  * @brief Delete a semaphore
197  *
198  * @param sem pointer of the semaphore to delete
199  */
200 void
sys_sem_free(sys_sem_t * sem)201 sys_sem_free(sys_sem_t *sem)
202 {
203   vSemaphoreDelete(*sem);
204   *sem = NULL;
205 }
206 
207 /**
208  * @brief Create an empty mailbox.
209  *
210  * @param mbox pointer of the mailbox
211  * @param size size of the mailbox
212  * @return ERR_OK on success, ERR_MEM when out of memory
213  */
214 err_t
sys_mbox_new(sys_mbox_t * mbox,int size)215 sys_mbox_new(sys_mbox_t *mbox, int size)
216 {
217   *mbox = mem_malloc(sizeof(struct sys_mbox_s));
218   if (*mbox == NULL){
219     LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("fail to new *mbox\n"));
220     return ERR_MEM;
221   }
222 
223   (*mbox)->os_mbox = xQueueCreate(size, sizeof(void *));
224 
225   if ((*mbox)->os_mbox == NULL) {
226     LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("fail to new (*mbox)->os_mbox\n"));
227     free(*mbox);
228     return ERR_MEM;
229   }
230 
231 #if ESP_THREAD_SAFE
232   (*mbox)->owner = NULL;
233 #endif
234 
235   LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("new *mbox ok mbox=%p os_mbox=%p\n", *mbox, (*mbox)->os_mbox));
236   return ERR_OK;
237 }
238 
239 /**
240  * @brief Send message to mailbox
241  *
242  * @param mbox pointer of the mailbox
243  * @param msg pointer of the message to send
244  */
245 void
sys_mbox_post(sys_mbox_t * mbox,void * msg)246 sys_mbox_post(sys_mbox_t *mbox, void *msg)
247 {
248   BaseType_t ret = xQueueSendToBack((*mbox)->os_mbox, &msg, portMAX_DELAY);
249   LWIP_ASSERT("mbox post failed", ret == pdTRUE);
250 }
251 
252 /**
253  * @brief Try to post a message to mailbox
254  *
255  * @param mbox pointer of the mailbox
256  * @param msg pointer of the message to send
257  * @return ERR_OK on success, ERR_MEM when mailbox is full
258  */
259 err_t
sys_mbox_trypost(sys_mbox_t * mbox,void * msg)260 sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
261 {
262   err_t xReturn;
263 
264   if (xQueueSend((*mbox)->os_mbox, &msg, 0) == pdTRUE) {
265     xReturn = ERR_OK;
266   } else {
267     LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("trypost mbox=%p fail\n", (*mbox)->os_mbox));
268     xReturn = ERR_MEM;
269   }
270 
271   return xReturn;
272 }
273 
274 /**
275  * @brief Try to post a message to mailbox from ISR
276  *
277  * @param mbox pointer of the mailbox
278  * @param msg pointer of the message to send
279  * @return  ERR_OK on success
280  *          ERR_MEM when mailbox is full
281  *          ERR_NEED_SCHED when high priority task wakes up
282  */
283 err_t
sys_mbox_trypost_fromisr(sys_mbox_t * mbox,void * msg)284 sys_mbox_trypost_fromisr(sys_mbox_t *mbox, void *msg)
285 {
286   BaseType_t ret;
287   BaseType_t xHigherPriorityTaskWoken = pdFALSE;
288 
289   ret = xQueueSendFromISR((*mbox)->os_mbox, &msg, &xHigherPriorityTaskWoken);
290   if (ret == pdTRUE) {
291     if (xHigherPriorityTaskWoken == pdTRUE) {
292       return ERR_NEED_SCHED;
293     }
294     return ERR_OK;
295   } else {
296     LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL);
297     return ERR_MEM;
298   }
299 }
300 
301 /**
302  * @brief Fetch message from mailbox
303  *
304  * @param mbox pointer of mailbox
305  * @param msg pointer of the received message, could be NULL to indicate the message should be dropped
306  * @param timeout if zero, will wait infinitely; or will wait milliseconds specify by this argument
307  * @return SYS_ARCH_TIMEOUT when timeout, 0 otherwise
308  */
309 u32_t
sys_arch_mbox_fetch(sys_mbox_t * mbox,void ** msg,u32_t timeout)310 sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
311 {
312   BaseType_t ret;
313   void *msg_dummy;
314 
315   if (msg == NULL) {
316     msg = &msg_dummy;
317   }
318 
319   if (timeout == 0) {
320     /* wait infinite */
321     ret = xQueueReceive((*mbox)->os_mbox, &(*msg), portMAX_DELAY);
322     LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
323   } else {
324     TickType_t timeout_ticks = timeout / portTICK_RATE_MS;
325     ret = xQueueReceive((*mbox)->os_mbox, &(*msg), timeout_ticks);
326     if (ret == errQUEUE_EMPTY) {
327       /* timed out */
328       *msg = NULL;
329       return SYS_ARCH_TIMEOUT;
330     }
331     LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
332   }
333 
334   return 0;
335 }
336 
337 /**
338  * @brief try to fetch message from mailbox
339  *
340  * @param mbox pointer of mailbox
341  * @param msg pointer of the received message
342  * @return SYS_MBOX_EMPTY if mailbox is empty, 1 otherwise
343  */
344 u32_t
sys_arch_mbox_tryfetch(sys_mbox_t * mbox,void ** msg)345 sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
346 {
347   BaseType_t ret;
348   void *msg_dummy;
349 
350   if (msg == NULL) {
351     msg = &msg_dummy;
352   }
353   ret = xQueueReceive((*mbox)->os_mbox, &(*msg), 0);
354   if (ret == errQUEUE_EMPTY) {
355     *msg = NULL;
356     return SYS_MBOX_EMPTY;
357   }
358   LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
359 
360   return 0;
361 }
362 
363 void
sys_mbox_set_owner(sys_mbox_t * mbox,void * owner)364 sys_mbox_set_owner(sys_mbox_t *mbox, void* owner)
365 {
366   if (mbox && *mbox) {
367     (*mbox)->owner = owner;
368     LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("set mbox=%p owner=%p", *mbox, owner));
369   }
370 }
371 
372 /**
373  * @brief Delete a mailbox
374  *
375  * @param mbox pointer of the mailbox to delete
376  */
377 void
sys_mbox_free(sys_mbox_t * mbox)378 sys_mbox_free(sys_mbox_t *mbox)
379 {
380   if ((NULL == mbox) || (NULL == *mbox)) {
381     return;
382   }
383   UBaseType_t msgs_waiting = uxQueueMessagesWaiting((*mbox)->os_mbox);
384   LWIP_ASSERT("mbox quence not empty", msgs_waiting == 0);
385 
386   vQueueDelete((*mbox)->os_mbox);
387   free(*mbox);
388   *mbox = NULL;
389 }
390 
391 /**
392  * @brief Create a new thread
393  *
394  * @param name thread name
395  * @param thread thread function
396  * @param arg thread arguments
397  * @param stacksize stacksize of the thread
398  * @param prio priority of the thread
399  * @return thread ID
400  */
401 sys_thread_t
sys_thread_new(const char * name,lwip_thread_fn thread,void * arg,int stacksize,int prio)402 sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
403 {
404   TaskHandle_t rtos_task;
405   BaseType_t ret;
406 
407   /* LwIP's lwip_thread_fn matches FreeRTOS' TaskFunction_t, so we can pass the
408      thread function without adaption here. */
409   ret = xTaskCreatePinnedToCore(thread, name, stacksize, arg, prio, &rtos_task,
410           CONFIG_LWIP_TCPIP_TASK_AFFINITY);
411 
412   if (ret != pdTRUE) {
413     return NULL;
414   }
415 
416   return (sys_thread_t)rtos_task;
417 }
418 
419 /**
420  * @brief Initialize the sys_arch layer
421  *
422  */
423 void
sys_init(void)424 sys_init(void)
425 {
426   if (!g_lwip_protect_mutex) {
427     if (ERR_OK != sys_mutex_new(&g_lwip_protect_mutex)) {
428       ESP_LOGE(TAG, "sys_init: failed to init lwip protect mutex\n");
429     }
430   }
431 
432   // Create the pthreads key for the per-thread semaphore storage
433   pthread_key_create(&sys_thread_sem_key, sys_thread_sem_free);
434 
435   esp_vfs_lwip_sockets_register();
436 }
437 
438 /**
439  * @brief Get system ticks
440  *
441  * @return system tick counts
442  */
443 u32_t
sys_jiffies(void)444 sys_jiffies(void)
445 {
446   return xTaskGetTickCount();
447 }
448 
449 /**
450  * @brief Get current time, in miliseconds
451  *
452  * @return current time
453  */
454 u32_t
sys_now(void)455 sys_now(void)
456 {
457   return xTaskGetTickCount() * portTICK_PERIOD_MS;
458 }
459 
460 /**
461  * @brief Protect critical region
462  *
463  * @note This function is only called during very short critical regions.
464  *
465  * @return previous protection level
466  */
467 sys_prot_t
sys_arch_protect(void)468 sys_arch_protect(void)
469 {
470   if (unlikely(!g_lwip_protect_mutex)) {
471     sys_mutex_new(&g_lwip_protect_mutex);
472   }
473   sys_mutex_lock(&g_lwip_protect_mutex);
474   return (sys_prot_t) 1;
475 }
476 
477 /**
478  * @brief Unprotect critical region
479  *
480  * @param pval protection level
481  */
482 void
sys_arch_unprotect(sys_prot_t pval)483 sys_arch_unprotect(sys_prot_t pval)
484 {
485   LWIP_UNUSED_ARG(pval);
486   sys_mutex_unlock(&g_lwip_protect_mutex);
487 }
488 
489 /*
490  * get per thread semaphore
491  */
492 sys_sem_t*
sys_thread_sem_get(void)493 sys_thread_sem_get(void)
494 {
495   sys_sem_t *sem = pthread_getspecific(sys_thread_sem_key);
496 
497   if (!sem) {
498       sem = sys_thread_sem_init();
499   }
500   LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sem_get s=%p\n", sem));
501   return sem;
502 }
503 
504 static void
sys_thread_sem_free(void * data)505 sys_thread_sem_free(void* data) // destructor for TLS semaphore
506 {
507   sys_sem_t *sem = (sys_sem_t*)(data);
508 
509   if (sem && *sem){
510     LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sem del, sem=%p\n", *sem));
511     vSemaphoreDelete(*sem);
512   }
513 
514   if (sem) {
515     LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sem pointer del, sem_p=%p\n", sem));
516     free(sem);
517   }
518 }
519 
520 sys_sem_t*
sys_thread_sem_init(void)521 sys_thread_sem_init(void)
522 {
523   sys_sem_t *sem = (sys_sem_t*)mem_malloc(sizeof(sys_sem_t*));
524 
525   if (!sem){
526     ESP_LOGE(TAG, "thread_sem_init: out of memory");
527     return 0;
528   }
529 
530   *sem = xSemaphoreCreateBinary();
531   if (!(*sem)){
532     free(sem);
533     ESP_LOGE(TAG, "thread_sem_init: out of memory");
534     return 0;
535   }
536 
537   pthread_setspecific(sys_thread_sem_key, sem);
538   return sem;
539 }
540 
541 void
sys_thread_sem_deinit(void)542 sys_thread_sem_deinit(void)
543 {
544   sys_sem_t *sem = pthread_getspecific(sys_thread_sem_key);
545   if (sem != NULL) {
546     sys_thread_sem_free(sem);
547     pthread_setspecific(sys_thread_sem_key, NULL);
548   }
549 }
550 
551 void
sys_delay_ms(uint32_t ms)552 sys_delay_ms(uint32_t ms)
553 {
554   vTaskDelay(ms / portTICK_PERIOD_MS);
555 }
556