• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // This module implements pthread API on top of FreeRTOS. API is implemented to the level allowing
16 // libstdcxx threading framework to operate correctly. So not all original pthread routines are supported.
17 //
18 
19 #include <time.h>
20 #include <errno.h>
21 #include <pthread.h>
22 #include <string.h>
23 #include "esp_err.h"
24 #include "esp_attr.h"
25 #include "sys/queue.h"
26 #include "esp_osal/esp_osal.h"
27 #include "esp_osal/task.h"
28 #include "esp_osal/semphr.h"
29 #include "soc/soc_memory_layout.h"
30 
31 #include "pthread_internal.h"
32 #include "esp_pthread.h"
33 
34 #define LOG_LOCAL_LEVEL CONFIG_LOG_DEFAULT_LEVEL
35 #include "esp_log.h"
36 const static char *TAG = "pthread";
37 #if 0
38 /** task state */
39 enum esp_pthread_task_state {
40     PTHREAD_TASK_STATE_RUN,
41     PTHREAD_TASK_STATE_EXIT
42 };
43 
44 /** pthread thread FreeRTOS wrapper */
45 typedef struct esp_pthread_entry {
46     SLIST_ENTRY(esp_pthread_entry)  list_node;  ///< Tasks list node struct.
47     TaskHandle_t                handle;         ///< FreeRTOS task handle
48     TaskHandle_t                join_task;      ///< Handle of the task waiting to join
49     enum esp_pthread_task_state state;          ///< pthread task state
50     bool                        detached;       ///< True if pthread is detached
51     void                       *retval;         ///< Value supplied to calling thread during join
52     void                       *task_arg;       ///< Task arguments
53 } esp_pthread_t;
54 
55 /** pthread wrapper task arg */
56 typedef struct {
57     void *(*func)(void *);  ///< user task entry
58     void *arg;              ///< user task argument
59     esp_pthread_cfg_t cfg;  ///< pthread configuration
60 } esp_pthread_task_arg_t;
61 
62 /** pthread mutex FreeRTOS wrapper */
63 typedef struct {
64     SemaphoreHandle_t   sem;        ///< Handle of the task waiting to join
65     int                 type;       ///< Mutex type. Currently supported PTHREAD_MUTEX_NORMAL and PTHREAD_MUTEX_RECURSIVE
66 } esp_pthread_mutex_t;
67 
68 
69 static SemaphoreHandle_t s_threads_mux  = NULL;
70 static portMUX_TYPE s_mutex_init_lock   = portMUX_INITIALIZER_UNLOCKED;
71 static SLIST_HEAD(esp_thread_list_head, esp_pthread_entry) s_threads_list
72                                         = SLIST_HEAD_INITIALIZER(s_threads_list);
73 static pthread_key_t s_pthread_cfg_key;
74 
75 
76 static int IRAM_ATTR pthread_mutex_lock_internal(esp_pthread_mutex_t *mux, TickType_t tmo);
77 
78 static void esp_pthread_cfg_key_destructor(void *value)
79 {
80     free(value);
81 }
82 
83 esp_err_t esp_pthread_init(void)
84 {
85     if (pthread_key_create(&s_pthread_cfg_key, esp_pthread_cfg_key_destructor) != 0) {
86         return ESP_ERR_NO_MEM;
87     }
88     s_threads_mux = xSemaphoreCreateMutex();
89     if (s_threads_mux == NULL) {
90         pthread_key_delete(s_pthread_cfg_key);
91         return ESP_ERR_NO_MEM;
92     }
93     return ESP_OK;
94 }
95 
96 static void *pthread_list_find_item(void *(*item_check)(esp_pthread_t *, void *arg), void *check_arg)
97 {
98     esp_pthread_t *it;
99     SLIST_FOREACH(it, &s_threads_list, list_node) {
100         void *val = item_check(it, check_arg);
101         if (val) {
102             return val;
103         }
104     }
105     return NULL;
106 }
107 
108 static void *pthread_get_handle_by_desc(esp_pthread_t *item, void *desc)
109 {
110     if (item == desc) {
111         return item->handle;
112     }
113     return NULL;
114 }
115 
116 static void *pthread_get_desc_by_handle(esp_pthread_t *item, void *hnd)
117 {
118     if (hnd == item->handle) {
119         return item;
120     }
121     return NULL;
122 }
123 
124 static inline TaskHandle_t pthread_find_handle(pthread_t thread)
125 {
126     return pthread_list_find_item(pthread_get_handle_by_desc, (void *)thread);
127 }
128 
129 static esp_pthread_t *pthread_find(TaskHandle_t task_handle)
130 {
131     return pthread_list_find_item(pthread_get_desc_by_handle, task_handle);
132 }
133 
134 static void pthread_delete(esp_pthread_t *pthread)
135 {
136     SLIST_REMOVE(&s_threads_list, pthread, esp_pthread_entry, list_node);
137     free(pthread);
138 }
139 
140 /* Call this function to configure pthread stacks in Pthreads */
141 esp_err_t esp_pthread_set_cfg(const esp_pthread_cfg_t *cfg)
142 {
143     if (cfg->stack_size < PTHREAD_STACK_MIN) {
144         return ESP_ERR_INVALID_ARG;
145     }
146 
147     /* If a value is already set, update that value */
148     esp_pthread_cfg_t *p = pthread_getspecific(s_pthread_cfg_key);
149     if (!p) {
150         p = malloc(sizeof(esp_pthread_cfg_t));
151         if (!p) {
152             return ESP_ERR_NO_MEM;
153         }
154     }
155     *p = *cfg;
156     pthread_setspecific(s_pthread_cfg_key, p);
157     return 0;
158 }
159 
160 esp_err_t esp_pthread_get_cfg(esp_pthread_cfg_t *p)
161 {
162     esp_pthread_cfg_t *cfg = pthread_getspecific(s_pthread_cfg_key);
163     if (cfg) {
164         *p = *cfg;
165         return ESP_OK;
166     }
167     memset(p, 0, sizeof(*p));
168     return ESP_ERR_NOT_FOUND;
169 }
170 
171 static int get_default_pthread_core(void)
172 {
173     return CONFIG_PTHREAD_TASK_CORE_DEFAULT == -1 ? tskNO_AFFINITY : CONFIG_PTHREAD_TASK_CORE_DEFAULT;
174 }
175 
176 esp_pthread_cfg_t esp_pthread_get_default_config(void)
177 {
178     esp_pthread_cfg_t cfg = {
179         .stack_size = CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT,
180         .prio = CONFIG_PTHREAD_TASK_PRIO_DEFAULT,
181         .inherit_cfg = false,
182         .thread_name = NULL,
183         .pin_to_core = get_default_pthread_core()
184     };
185 
186     return cfg;
187 }
188 
189 static void pthread_task_func(void *arg)
190 {
191     void *rval = NULL;
192     esp_pthread_task_arg_t *task_arg = (esp_pthread_task_arg_t *)arg;
193 
194     ESP_LOGV(TAG, "%s ENTER %p", __FUNCTION__, task_arg->func);
195 
196     // wait for start
197     xTaskNotifyWait(0, 0, NULL, portMAX_DELAY);
198 
199     if (task_arg->cfg.inherit_cfg) {
200         /* If inherit option is set, then do a set_cfg() ourselves for future forks,
201         but first set thread_name to NULL to enable inheritance of the name too.
202         (This also to prevents dangling pointers to name of tasks that might
203         possibly have been deleted when we use the configuration).*/
204         esp_pthread_cfg_t *cfg = &task_arg->cfg;
205         cfg->thread_name = NULL;
206         esp_pthread_set_cfg(cfg);
207     }
208     ESP_LOGV(TAG, "%s START %p", __FUNCTION__, task_arg->func);
209     rval = task_arg->func(task_arg->arg);
210     ESP_LOGV(TAG, "%s END %p", __FUNCTION__, task_arg->func);
211 
212     pthread_exit(rval);
213 
214     ESP_LOGV(TAG, "%s EXIT", __FUNCTION__);
215 }
216 
217 int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
218                    void *(*start_routine) (void *), void *arg)
219 {
220     TaskHandle_t xHandle = NULL;
221 
222     ESP_LOGV(TAG, "%s", __FUNCTION__);
223     esp_pthread_task_arg_t *task_arg = calloc(1, sizeof(esp_pthread_task_arg_t));
224     if (task_arg == NULL) {
225         ESP_LOGE(TAG, "Failed to allocate task args!");
226         return ENOMEM;
227     }
228 
229     esp_pthread_t *pthread = calloc(1, sizeof(esp_pthread_t));
230     if (pthread == NULL) {
231         ESP_LOGE(TAG, "Failed to allocate pthread data!");
232         free(task_arg);
233         return ENOMEM;
234     }
235 
236     uint32_t stack_size = CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT;
237     BaseType_t prio = CONFIG_PTHREAD_TASK_PRIO_DEFAULT;
238     BaseType_t core_id = get_default_pthread_core();
239     const char *task_name = CONFIG_PTHREAD_TASK_NAME_DEFAULT;
240 
241     esp_pthread_cfg_t *pthread_cfg = pthread_getspecific(s_pthread_cfg_key);
242     if (pthread_cfg) {
243         if (pthread_cfg->stack_size) {
244             stack_size = pthread_cfg->stack_size;
245         }
246         if (pthread_cfg->prio && pthread_cfg->prio < configMAX_PRIORITIES) {
247             prio = pthread_cfg->prio;
248         }
249 
250         if (pthread_cfg->inherit_cfg) {
251             if (pthread_cfg->thread_name == NULL) {
252                 // Inherit task name from current task.
253                 task_name = pcTaskGetTaskName(NULL);
254             } else {
255                 // Inheriting, but new task name.
256                 task_name = pthread_cfg->thread_name;
257             }
258         } else if (pthread_cfg->thread_name == NULL) {
259             task_name = CONFIG_PTHREAD_TASK_NAME_DEFAULT;
260         } else {
261             task_name = pthread_cfg->thread_name;
262         }
263 
264         if (pthread_cfg->pin_to_core >= 0 && pthread_cfg->pin_to_core < portNUM_PROCESSORS) {
265             core_id = pthread_cfg->pin_to_core;
266         }
267 
268         task_arg->cfg = *pthread_cfg;
269     }
270 
271     if (attr) {
272         /* Overwrite attributes */
273         stack_size = attr->stacksize;
274 
275         switch (attr->detachstate) {
276         case PTHREAD_CREATE_DETACHED:
277             pthread->detached = true;
278             break;
279         case PTHREAD_CREATE_JOINABLE:
280         default:
281             pthread->detached = false;
282         }
283     }
284 
285     task_arg->func = start_routine;
286     task_arg->arg = arg;
287     pthread->task_arg = task_arg;
288     BaseType_t res = xTaskCreatePinnedToCore(&pthread_task_func,
289                                              task_name,
290                                              // stack_size is in bytes. This transformation ensures that the units are
291                                              // transformed to the units used in FreeRTOS.
292                                              // Note: float division of ceil(m / n) ==
293                                              //       integer division of (m + n - 1) / n
294                                              (stack_size + sizeof(StackType_t) - 1) / sizeof(StackType_t),
295                                              task_arg,
296                                              prio,
297                                              &xHandle,
298                                              core_id);
299 
300     if (res != pdPASS) {
301         ESP_LOGE(TAG, "Failed to create task!");
302         free(pthread);
303         free(task_arg);
304         if (res == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY) {
305             return ENOMEM;
306         } else {
307             return EAGAIN;
308         }
309     }
310     pthread->handle = xHandle;
311 
312     if (xSemaphoreTake(s_threads_mux, portMAX_DELAY) != pdTRUE) {
313         assert(false && "Failed to lock threads list!");
314     }
315     SLIST_INSERT_HEAD(&s_threads_list, pthread, list_node);
316     xSemaphoreGive(s_threads_mux);
317 
318     // start task
319     xTaskNotify(xHandle, 0, eNoAction);
320 
321     *thread = (pthread_t)pthread; // pointer value fit into pthread_t (uint32_t)
322 
323     ESP_LOGV(TAG, "Created task %x", (uint32_t)xHandle);
324 
325     return 0;
326 }
327 
328 int pthread_join(pthread_t thread, void **retval)
329 {
330     esp_pthread_t *pthread = (esp_pthread_t *)thread;
331     int ret = 0;
332     bool wait = false;
333     void *child_task_retval = 0;
334 
335     ESP_LOGV(TAG, "%s %p", __FUNCTION__, pthread);
336 
337     // find task
338     if (xSemaphoreTake(s_threads_mux, portMAX_DELAY) != pdTRUE) {
339         assert(false && "Failed to lock threads list!");
340     }
341     TaskHandle_t handle = pthread_find_handle(thread);
342     if (!handle) {
343         // not found
344         ret = ESRCH;
345     } else if (pthread->detached) {
346         // Thread is detached
347         ret = EDEADLK;
348     } else if (pthread->join_task) {
349         // already have waiting task to join
350         ret = EINVAL;
351     } else if (handle == xTaskGetCurrentTaskHandle()) {
352         // join to self not allowed
353         ret = EDEADLK;
354     } else {
355         esp_pthread_t *cur_pthread = pthread_find(xTaskGetCurrentTaskHandle());
356         if (cur_pthread && cur_pthread->join_task == handle) {
357             // join to each other not allowed
358             ret = EDEADLK;
359         } else {
360             if (pthread->state == PTHREAD_TASK_STATE_RUN) {
361                 pthread->join_task = xTaskGetCurrentTaskHandle();
362                 wait = true;
363             } else { // thread has exited and task is already suspended, or about to be suspended
364                 child_task_retval = pthread->retval;
365                 pthread_delete(pthread);
366             }
367         }
368     }
369     xSemaphoreGive(s_threads_mux);
370 
371     if (ret == 0) {
372         if (wait) {
373             xTaskNotifyWait(0, 0, NULL, portMAX_DELAY);
374             if (xSemaphoreTake(s_threads_mux, portMAX_DELAY) != pdTRUE) {
375                 assert(false && "Failed to lock threads list!");
376             }
377             child_task_retval = pthread->retval;
378             pthread_delete(pthread);
379             xSemaphoreGive(s_threads_mux);
380         }
381         vTaskDelete(handle);
382     }
383 
384     if (retval) {
385         *retval = child_task_retval;
386     }
387 
388     ESP_LOGV(TAG, "%s %p EXIT %d", __FUNCTION__, pthread, ret);
389     return ret;
390 }
391 
392 int pthread_detach(pthread_t thread)
393 {
394     esp_pthread_t *pthread = (esp_pthread_t *)thread;
395     int ret = 0;
396 
397     if (xSemaphoreTake(s_threads_mux, portMAX_DELAY) != pdTRUE) {
398         assert(false && "Failed to lock threads list!");
399     }
400     TaskHandle_t handle = pthread_find_handle(thread);
401     if (!handle) {
402         ret = ESRCH;
403     } else if (pthread->detached) {
404         // already detached
405         ret = EINVAL;
406     } else if (pthread->join_task) {
407         // already have waiting task to join
408         ret = EINVAL;
409     } else if (pthread->state == PTHREAD_TASK_STATE_RUN) {
410         // pthread still running
411         pthread->detached = true;
412     } else {
413         // pthread already stopped
414         pthread_delete(pthread);
415         vTaskDelete(handle);
416     }
417     xSemaphoreGive(s_threads_mux);
418     ESP_LOGV(TAG, "%s %p EXIT %d", __FUNCTION__, pthread, ret);
419     return ret;
420 }
421 
422 void pthread_exit(void *value_ptr)
423 {
424     bool detached = false;
425     /* preemptively clean up thread local storage, rather than
426        waiting for the idle task to clean up the thread */
427     pthread_internal_local_storage_destructor_callback();
428 
429     if (xSemaphoreTake(s_threads_mux, portMAX_DELAY) != pdTRUE) {
430         assert(false && "Failed to lock threads list!");
431     }
432     esp_pthread_t *pthread = pthread_find(xTaskGetCurrentTaskHandle());
433     if (!pthread) {
434         assert(false && "Failed to find pthread for current task!");
435     }
436     if (pthread->task_arg) {
437         free(pthread->task_arg);
438     }
439     if (pthread->detached) {
440         // auto-free for detached threads
441         pthread_delete(pthread);
442         detached = true;
443     } else {
444         // Set return value
445         pthread->retval = value_ptr;
446         // Remove from list, it indicates that task has exited
447         if (pthread->join_task) {
448             // notify join
449             xTaskNotify(pthread->join_task, 0, eNoAction);
450         } else {
451             pthread->state = PTHREAD_TASK_STATE_EXIT;
452         }
453     }
454 
455     ESP_LOGD(TAG, "Task stk_wm = %d", uxTaskGetStackHighWaterMark(NULL));
456 
457     xSemaphoreGive(s_threads_mux);
458     // note: if this thread is joinable then after giving back s_threads_mux
459     // this task could be deleted at any time, so don't take another lock or
460     // do anything that might lock (such as printing to stdout)
461 
462     if (detached) {
463         vTaskDelete(NULL);
464     } else {
465         vTaskSuspend(NULL);
466     }
467 
468     // Should never be reached
469     abort();
470 }
471 
472 int pthread_cancel(pthread_t thread)
473 {
474     ESP_LOGE(TAG, "%s: not supported!", __FUNCTION__);
475     return ENOSYS;
476 }
477 
478 int sched_yield( void )
479 {
480     vTaskDelay(0);
481     return 0;
482 }
483 
484 pthread_t pthread_self(void)
485 {
486     if (xSemaphoreTake(s_threads_mux, portMAX_DELAY) != pdTRUE) {
487         assert(false && "Failed to lock threads list!");
488     }
489     esp_pthread_t *pthread = pthread_find(xTaskGetCurrentTaskHandle());
490     if (!pthread) {
491         assert(false && "Failed to find current thread ID!");
492     }
493     xSemaphoreGive(s_threads_mux);
494     return (pthread_t)pthread;
495 }
496 
497 int pthread_equal(pthread_t t1, pthread_t t2)
498 {
499     return t1 == t2 ? 1 : 0;
500 }
501 
502 /***************** ONCE ******************/
503 int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
504 {
505     if (once_control == NULL || init_routine == NULL || !once_control->is_initialized) {
506         ESP_LOGE(TAG, "%s: Invalid args!", __FUNCTION__);
507         return EINVAL;
508     }
509 
510     uint32_t res = 1;
511 #if defined(CONFIG_SPIRAM)
512     if (esp_ptr_external_ram(once_control)) {
513         uxPortCompareSetExtram((uint32_t *) &once_control->init_executed, 0, &res);
514     } else {
515 #endif
516         uxPortCompareSet((uint32_t *) &once_control->init_executed, 0, &res);
517 #if defined(CONFIG_SPIRAM)
518     }
519 #endif
520     // Check if compare and set was successful
521     if (res == 0) {
522         ESP_LOGV(TAG, "%s: call init_routine %p", __FUNCTION__, once_control);
523         init_routine();
524     }
525 
526     return 0;
527 }
528 
529 /***************** MUTEX ******************/
530 static int mutexattr_check(const pthread_mutexattr_t *attr)
531 {
532     if (attr->type != PTHREAD_MUTEX_NORMAL &&
533         attr->type != PTHREAD_MUTEX_RECURSIVE &&
534         attr->type != PTHREAD_MUTEX_ERRORCHECK) {
535         return EINVAL;
536     }
537     return 0;
538 }
539 
540 int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
541 {
542     int type = PTHREAD_MUTEX_NORMAL;
543 
544     if (!mutex) {
545         return EINVAL;
546     }
547 
548     if (attr) {
549         if (!attr->is_initialized) {
550             return EINVAL;
551         }
552         int res = mutexattr_check(attr);
553         if (res) {
554             return res;
555         }
556         type = attr->type;
557     }
558 
559     esp_pthread_mutex_t *mux = (esp_pthread_mutex_t *)malloc(sizeof(esp_pthread_mutex_t));
560     if (!mux) {
561         return ENOMEM;
562     }
563     mux->type = type;
564 
565     if (mux->type == PTHREAD_MUTEX_RECURSIVE) {
566         mux->sem = xSemaphoreCreateRecursiveMutex();
567     } else {
568         mux->sem = xSemaphoreCreateMutex();
569     }
570     if (!mux->sem) {
571         free(mux);
572         return EAGAIN;
573     }
574 
575     *mutex = (pthread_mutex_t)mux; // pointer value fit into pthread_mutex_t (uint32_t)
576 
577     return 0;
578 }
579 
580 int pthread_mutex_destroy(pthread_mutex_t *mutex)
581 {
582     esp_pthread_mutex_t *mux;
583 
584     ESP_LOGV(TAG, "%s %p", __FUNCTION__, mutex);
585 
586     if (!mutex) {
587         return EINVAL;
588     }
589     mux = (esp_pthread_mutex_t *)*mutex;
590     if (!mux) {
591         return EINVAL;
592     }
593 
594     // check if mux is busy
595     int res = pthread_mutex_lock_internal(mux, 0);
596     if (res == EBUSY) {
597         return EBUSY;
598     }
599 
600     if (mux->type == PTHREAD_MUTEX_RECURSIVE) {
601         res = xSemaphoreGiveRecursive(mux->sem);
602     } else {
603         res = xSemaphoreGive(mux->sem);
604     }
605     if (res != pdTRUE) {
606         assert(false && "Failed to release mutex!");
607     }
608     vSemaphoreDelete(mux->sem);
609     free(mux);
610 
611     return 0;
612 }
613 
614 static int IRAM_ATTR pthread_mutex_lock_internal(esp_pthread_mutex_t *mux, TickType_t tmo)
615 {
616     if (!mux) {
617         return EINVAL;
618     }
619 
620     if ((mux->type == PTHREAD_MUTEX_ERRORCHECK) &&
621         (xSemaphoreGetMutexHolder(mux->sem) == xTaskGetCurrentTaskHandle())) {
622         return EDEADLK;
623     }
624 
625     if (mux->type == PTHREAD_MUTEX_RECURSIVE) {
626         if (xSemaphoreTakeRecursive(mux->sem, tmo) != pdTRUE) {
627             return EBUSY;
628         }
629     } else {
630         if (xSemaphoreTake(mux->sem, tmo) != pdTRUE) {
631             return EBUSY;
632         }
633     }
634 
635     return 0;
636 }
637 
638 static int pthread_mutex_init_if_static(pthread_mutex_t *mutex)
639 {
640     int res = 0;
641     if ((intptr_t) *mutex == PTHREAD_MUTEX_INITIALIZER) {
642         portENTER_CRITICAL(&s_mutex_init_lock);
643         if ((intptr_t) *mutex == PTHREAD_MUTEX_INITIALIZER) {
644             res = pthread_mutex_init(mutex, NULL);
645         }
646         portEXIT_CRITICAL(&s_mutex_init_lock);
647     }
648     return res;
649 }
650 
651 int IRAM_ATTR pthread_mutex_lock(pthread_mutex_t *mutex)
652 {
653     if (!mutex) {
654         return EINVAL;
655     }
656     int res = pthread_mutex_init_if_static(mutex);
657     if (res != 0) {
658         return res;
659     }
660     return pthread_mutex_lock_internal((esp_pthread_mutex_t *)*mutex, portMAX_DELAY);
661 }
662 
663 int IRAM_ATTR pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *timeout)
664 {
665     if (!mutex) {
666         return EINVAL;
667     }
668     int res = pthread_mutex_init_if_static(mutex);
669     if (res != 0) {
670         return res;
671     }
672 
673     struct timespec currtime;
674     clock_gettime(CLOCK_REALTIME, &currtime);
675     TickType_t tmo = ((timeout->tv_sec - currtime.tv_sec)*1000 +
676                      (timeout->tv_nsec - currtime.tv_nsec)/1000000)/portTICK_PERIOD_MS;
677 
678     res = pthread_mutex_lock_internal((esp_pthread_mutex_t *)*mutex, tmo);
679     if (res == EBUSY) {
680         return ETIMEDOUT;
681     }
682     return res;
683 }
684 
685 int IRAM_ATTR pthread_mutex_trylock(pthread_mutex_t *mutex)
686 {
687     if (!mutex) {
688         return EINVAL;
689     }
690     int res = pthread_mutex_init_if_static(mutex);
691     if (res != 0) {
692         return res;
693     }
694     return pthread_mutex_lock_internal((esp_pthread_mutex_t *)*mutex, 0);
695 }
696 
697 int IRAM_ATTR pthread_mutex_unlock(pthread_mutex_t *mutex)
698 {
699     esp_pthread_mutex_t *mux;
700 
701     if (!mutex) {
702         return EINVAL;
703     }
704     mux = (esp_pthread_mutex_t *)*mutex;
705     if (!mux) {
706         return EINVAL;
707     }
708 
709     if (((mux->type == PTHREAD_MUTEX_RECURSIVE) ||
710         (mux->type == PTHREAD_MUTEX_ERRORCHECK)) &&
711         (xSemaphoreGetMutexHolder(mux->sem) != xTaskGetCurrentTaskHandle())) {
712         return EPERM;
713     }
714 
715     int ret;
716     if (mux->type == PTHREAD_MUTEX_RECURSIVE) {
717         ret = xSemaphoreGiveRecursive(mux->sem);
718     } else {
719         ret = xSemaphoreGive(mux->sem);
720     }
721     if (ret != pdTRUE) {
722         assert(false && "Failed to unlock mutex!");
723     }
724     return 0;
725 }
726 
727 int pthread_mutexattr_init(pthread_mutexattr_t *attr)
728 {
729     if (!attr) {
730         return EINVAL;
731     }
732     attr->type = PTHREAD_MUTEX_NORMAL;
733     attr->is_initialized = 1;
734     return 0;
735 }
736 
737 int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
738 {
739     if (!attr) {
740         return EINVAL;
741     }
742     attr->is_initialized = 0;
743     return 0;
744 }
745 
746 int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
747 {
748     if (!attr) {
749         return EINVAL;
750     }
751     *type = attr->type;
752     return 0;
753 }
754 
755 int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
756 {
757     if (!attr) {
758         return EINVAL;
759     }
760     pthread_mutexattr_t tmp_attr = {.type = type};
761     int res = mutexattr_check(&tmp_attr);
762     if (!res) {
763         attr->type = type;
764     }
765     return res;
766 }
767 
768 /***************** ATTRIBUTES ******************/
769 int pthread_attr_init(pthread_attr_t *attr)
770 {
771     if (attr) {
772         /* Nothing to allocate. Set everything to default */
773         attr->stacksize   = CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT;
774         attr->detachstate = PTHREAD_CREATE_JOINABLE;
775         return 0;
776     }
777     return EINVAL;
778 }
779 
780 int pthread_attr_destroy(pthread_attr_t *attr)
781 {
782     if (attr) {
783         /* Nothing to deallocate. Reset everything to default */
784         attr->stacksize   = CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT;
785         attr->detachstate = PTHREAD_CREATE_JOINABLE;
786         return 0;
787     }
788     return EINVAL;
789 }
790 
791 int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
792 {
793     if (attr) {
794         *stacksize = attr->stacksize;
795         return 0;
796     }
797     return EINVAL;
798 }
799 
800 int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
801 {
802     if (attr && !(stacksize < PTHREAD_STACK_MIN)) {
803         attr->stacksize = stacksize;
804         return 0;
805     }
806     return EINVAL;
807 }
808 
809 int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
810 {
811     if (attr) {
812         *detachstate = attr->detachstate;
813         return 0;
814     }
815     return EINVAL;
816 }
817 
818 int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
819 {
820     if (attr) {
821         switch (detachstate) {
822         case PTHREAD_CREATE_DETACHED:
823             attr->detachstate = PTHREAD_CREATE_DETACHED;
824             break;
825         case PTHREAD_CREATE_JOINABLE:
826             attr->detachstate = PTHREAD_CREATE_JOINABLE;
827             break;
828         default:
829             return EINVAL;
830         }
831         return 0;
832     }
833     return EINVAL;
834 }
835 
836 /* Hook function to force linking this file */
837 void pthread_include_pthread_impl(void)
838 {
839 }
840 #elif 1
841 #include "los_config.h"
842 #include <string.h>
843 #include <stdlib.h>
844 typedef struct{
845 	UINT32 id;
846 	char type;
847 }s_pthreadSt;
848 static pthread_key_t s_pthread_cfg_key;
849 static char pthreadName[] = {"posix_pthread"};
esp_pthread_cfg_key_destructor(void * value)850 static void esp_pthread_cfg_key_destructor(void *value)
851 {
852     free(value);
853 }
esp_pthread_init(void)854 esp_err_t esp_pthread_init(void)
855 {
856     if (pthread_key_create(&s_pthread_cfg_key, esp_pthread_cfg_key_destructor) != 0) {
857         return ESP_ERR_NO_MEM;
858     }
859     return ESP_OK;
860 }
pthread_mutex_lock(pthread_mutex_t * mutex)861 int pthread_mutex_lock(pthread_mutex_t *mutex)
862 {
863 	char type;
864 	UINT32 id;
865 	s_pthreadSt *sem = (s_pthreadSt *)mutex;
866 	if(!mutex) return EINVAL;
867     if ((intptr_t) *mutex == PTHREAD_MUTEX_INITIALIZER) {
868 		ESP_LOGE(TAG,"pthread_mutex_lock(PTHREAD_MUTEX_INITIALIZER)");
869 		pthread_mutex_init(mutex,NULL);
870     }
871 	type = sem->type;
872 	id   = sem->id;
873 	if(0x50 == type) {
874 		return (LOS_OK != LOS_MuxPend(id, LOS_WAIT_FOREVER)) ? EBUSY : 0;
875 	}else
876 	if(0x51 == type) {
877 		return (LOS_OK != LOS_SemPend(id, LOS_WAIT_FOREVER)) ? EBUSY : 0;
878 	}
879 	return EINVAL;
880 }
pthread_mutex_unlock(pthread_mutex_t * mutex)881 int pthread_mutex_unlock(pthread_mutex_t *mutex)
882 {
883 	char type;
884 	UINT32 id;
885 	s_pthreadSt *sem = (s_pthreadSt *)mutex;
886 	if(!mutex) return EINVAL;
887 	if((intptr_t) *mutex == PTHREAD_MUTEX_INITIALIZER) return EINVAL;
888 	type = sem->type;
889 	id   = sem->id;
890 	if(0x50 == type) {
891 		return (LOS_OK != LOS_MuxPost(id)) ? EPERM : 0;
892 	}else
893 	if(0x51 == type) {
894 		return (LOS_OK != LOS_SemPost(id)) ? EPERM : 0;
895 	}
896 	return 0;
897 }
pthread_mutex_init(pthread_mutex_t * mutex,const pthread_mutexattr_t * attr)898 int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
899 {
900     int type = PTHREAD_MUTEX_NORMAL;
901 
902     if (!mutex) {
903         return EINVAL;
904     }
905 
906     if (attr) {
907         if (!attr->is_initialized) {
908             return EINVAL;
909         }
910 		type = attr->type;
911 	    if (type != PTHREAD_MUTEX_NORMAL &&
912 	        type != PTHREAD_MUTEX_RECURSIVE &&
913 	        type != PTHREAD_MUTEX_ERRORCHECK) {
914 	        return EINVAL;
915 	    }
916     }
917 
918     s_pthreadSt *mux = (s_pthreadSt *)malloc(sizeof(s_pthreadSt));
919     if (!mux) {
920         return ENOMEM;
921     }
922 
923 	mux->id = 0;
924     if (type == PTHREAD_MUTEX_RECURSIVE) {
925 		mux->type = 0x50;
926 		if(LOS_OK != LOS_MuxCreate(&mux->id)){
927 			free(mux);
928 			return EAGAIN;
929 		}
930     } else {
931 		mux->type = 0x51;
932 		if(LOS_OK != LOS_BinarySemCreate(1,&mux->id)){
933 			free(mux);
934 			return EAGAIN;
935 		}
936     }
937     *mutex = (pthread_mutex_t)mux; // pointer value fit into pthread_mutex_t (uint32_t)
938     return 0;
939 }
pthread_mutex_destroy(pthread_mutex_t * mutex)940 int pthread_mutex_destroy(pthread_mutex_t *mutex)
941 {
942 	char type;
943 	UINT32 id;
944 	s_pthreadSt *sem = (s_pthreadSt *)mutex;
945 	if(!mutex) return 0;
946 	type = sem->type;
947 	id   = sem->id;
948 	sem->type = 0;
949 	sem->id = 0;
950 	free(sem);
951 	if(0x50 == type) {
952 		LOS_MuxPost(id);
953 		LOS_MuxDelete(id);
954 	}else
955 	if(0x51 == type) {
956 		LOS_SemPost(id);
957 		LOS_SemDelete(id);
958 	}
959 	return 0;
960 }
961 #define MUTEXATTR_TYPE_MASK   0x0FU
pthread_mutexattr_init(pthread_mutexattr_t * mutexAttr)962 int pthread_mutexattr_init(pthread_mutexattr_t *mutexAttr)
963 {
964     if (mutexAttr == NULL) {
965         return EINVAL;
966     }
967 
968     mutexAttr->type = PTHREAD_MUTEX_DEFAULT;
969 
970     return 0;
971 }
972 
pthread_mutexattr_gettype(const pthread_mutexattr_t * attr,int * outType)973 int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *outType)
974 {
975     INT32 type;
976 
977     if ((attr == NULL) || (outType == NULL)) {
978         return EINVAL;
979     }
980 
981     type = (INT32)(attr->type & MUTEXATTR_TYPE_MASK);
982     if ((type != PTHREAD_MUTEX_NORMAL) &&
983         (type != PTHREAD_MUTEX_RECURSIVE) &&
984         (type != PTHREAD_MUTEX_ERRORCHECK)) {
985         return EINVAL;
986     }
987 
988     *outType = type;
989 
990     return 0;
991 }
992 
pthread_mutexattr_settype(pthread_mutexattr_t * mutexAttr,int type)993 int pthread_mutexattr_settype(pthread_mutexattr_t *mutexAttr, int type)
994 {
995     if (mutexAttr == NULL) {
996         return EINVAL;
997     }
998 
999     if (((unsigned)type != PTHREAD_MUTEX_NORMAL) &&
1000         ((unsigned)type != PTHREAD_MUTEX_RECURSIVE) &&
1001         ((unsigned)type != PTHREAD_MUTEX_ERRORCHECK)) {
1002         return EINVAL;
1003     }
1004     mutexAttr->type = (UINT8)((mutexAttr->type & ~MUTEXATTR_TYPE_MASK) | (UINT32)type);
1005 
1006     return 0;
1007 }
1008 
pthread_mutexattr_destroy(pthread_mutexattr_t * mutexAttr)1009 int pthread_mutexattr_destroy(pthread_mutexattr_t *mutexAttr)
1010 {
1011     if (mutexAttr == NULL) {
1012         return EINVAL;
1013     }
1014 
1015     memset(mutexAttr, 0, sizeof(pthread_mutexattr_t));
1016 
1017     return 0;
1018 }
1019 
pthread_exit(void * value_ptr)1020 void pthread_exit(void *value_ptr)
1021 {
1022 	LOS_TaskDelete(LOS_CurTaskIDGet());
1023 	while (1) {
1024 		LOS_TaskSuspend(LOS_CurTaskIDGet());
1025 		LOS_TaskDelay(10);
1026 	}
1027 }
1028 
sched_get_priority_min(int policy)1029 int sched_get_priority_min(int policy)
1030 {
1031     if (policy != SCHED_RR) {
1032         errno = EINVAL;
1033         return -1;
1034     }
1035 
1036     return LOS_TASK_PRIORITY_LOWEST;
1037 }
1038 
sched_get_priority_max(int policy)1039 int sched_get_priority_max(int policy)
1040 {
1041     if (policy != SCHED_RR) {
1042         errno = EINVAL;
1043         return -1;
1044     }
1045 
1046     return LOS_TASK_PRIORITY_HIGHEST;
1047 }
1048 
1049 #define POSIX_THREAD_STACK_SIZE LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE
pthread_attr_init(pthread_attr_t * attr)1050 int pthread_attr_init(pthread_attr_t *attr)
1051 {
1052     if (NULL == attr) {
1053         return EINVAL;
1054     }
1055 	memset(attr, 0, sizeof(pthread_attr_t));
1056     attr->detachstate                 = PTHREAD_CREATE_JOINABLE;
1057     attr->schedpolicy                 = SCHED_RR;
1058     attr->schedparam.sched_priority   = LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO;
1059     attr->inheritsched                = PTHREAD_INHERIT_SCHED;
1060     attr->stackaddr                   = NULL;
1061     attr->stacksize                   = POSIX_THREAD_STACK_SIZE;
1062 
1063     return 0;
1064 }
ServerStubInit(void)1065 int ServerStubInit(void)
1066 {
1067 
1068     return 0;
1069 }
1070 
pthread_attr_destroy(pthread_attr_t * attr)1071 int pthread_attr_destroy(pthread_attr_t *attr)
1072 {
1073     if (attr == NULL) {
1074         return EINVAL;
1075     }
1076 
1077     memset(attr, 0, sizeof(pthread_attr_t));
1078 
1079     return 0;
1080 }
1081 
pthread_attr_setdetachstate(pthread_attr_t * attr,int detachState)1082 int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachState)
1083 {
1084     if ((attr != NULL) && ((detachState == PTHREAD_CREATE_JOINABLE) || (detachState == PTHREAD_CREATE_DETACHED))) {
1085         attr->detachstate = (UINT32)detachState;
1086         return 0;
1087     }
1088 
1089     return EINVAL;
1090 }
1091 
pthread_attr_getdetachstate(const pthread_attr_t * attr,int * detachState)1092 int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachState)
1093 {
1094     if ((attr == NULL) || (detachState == NULL)) {
1095         return EINVAL;
1096     }
1097 
1098     *detachState = (int)attr->detachstate;
1099 
1100     return 0;
1101 }
1102 
pthread_attr_setscope(pthread_attr_t * attr,int scope)1103 int pthread_attr_setscope(pthread_attr_t *attr, int scope)
1104 {
1105     if (attr == NULL) {
1106         return EINVAL;
1107     }
1108 
1109     if (scope == PTHREAD_SCOPE_SYSTEM) {
1110         return 0;
1111     }
1112 
1113     if (scope == PTHREAD_SCOPE_PROCESS) {
1114         return ENOTSUP;
1115     }
1116 
1117     return EINVAL;
1118 }
1119 #if 0
1120 int pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
1121 {
1122     if ((attr == NULL) || (scope == NULL)) {
1123         return EINVAL;
1124     }
1125 
1126     *scope = (int)attr->scope;
1127 
1128     return 0;
1129 }
1130 #endif
pthread_setname_np(pthread_t thread,const char * name)1131 int pthread_setname_np(pthread_t thread, const char *name)
1132 {
1133 	LosTaskCB *taskCB;
1134 	taskCB = OS_TCB_FROM_TID((UINT32)thread);
1135 	taskCB->taskName = (char *)name;
1136 	return 0;
1137 }
1138 int strcpy_s(char *strDest, size_t destMax, const char *strSrc);
pthread_getname_np(pthread_t thread,char * buf,size_t buflen)1139 int pthread_getname_np(pthread_t thread, char *buf, size_t buflen)
1140 {
1141 	LosTaskCB *taskCB;
1142 	taskCB = OS_TCB_FROM_TID((UINT32)thread);
1143 	if (pthreadName == taskCB->taskName) return EINVAL;
1144 	if (NULL == taskCB->taskName) return EINVAL;
1145 	strcpy_s(buf, buflen, taskCB->taskName);
1146     return ERANGE;
1147 }
1148 
pthread_attr_setinheritsched(pthread_attr_t * attr,int inherit)1149 int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
1150 {
1151     if ((attr != NULL) && ((inherit == PTHREAD_INHERIT_SCHED) || (inherit == PTHREAD_EXPLICIT_SCHED))) {
1152         attr->inheritsched = (UINT32)inherit;
1153         return 0;
1154     }
1155 
1156     return EINVAL;
1157 }
1158 
pthread_attr_getinheritsched(const pthread_attr_t * attr,int * inherit)1159 int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
1160 {
1161     if ((attr == NULL) || (inherit == NULL)) {
1162         return EINVAL;
1163     }
1164 
1165     *inherit = (int)attr->inheritsched;
1166 
1167     return 0;
1168 }
1169 
pthread_attr_setschedpolicy(pthread_attr_t * attr,int policy)1170 int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
1171 {
1172     if ((attr != NULL) && (policy == SCHED_RR)) {
1173         attr->schedpolicy = SCHED_RR;
1174         return 0;
1175     }
1176 
1177     return EINVAL;
1178 }
1179 
pthread_attr_getschedpolicy(const pthread_attr_t * attr,int * policy)1180 int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
1181 {
1182     if ((attr == NULL) || (policy == NULL)) {
1183         return EINVAL;
1184     }
1185 
1186     *policy = (int)attr->schedpolicy;
1187 
1188     return 0;
1189 }
1190 
pthread_attr_setschedparam(pthread_attr_t * attr,const struct sched_param * param)1191 int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param)
1192 {
1193     if ((attr == NULL) || (param == NULL)) {
1194         return EINVAL;
1195     } else if ((param->sched_priority < LOS_TASK_PRIORITY_HIGHEST) ||
1196                (param->sched_priority >= LOS_TASK_PRIORITY_LOWEST)) {
1197         return ENOTSUP;
1198     }
1199 
1200     attr->schedparam = *param;
1201 
1202     return 0;
1203 }
1204 
pthread_attr_getschedparam(const pthread_attr_t * attr,struct sched_param * param)1205 int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param)
1206 {
1207     if ((attr == NULL) || (param == NULL)) {
1208         return EINVAL;
1209     }
1210 
1211     *param = attr->schedparam;
1212 
1213     return 0;
1214 }
1215 
pthread_attr_setstackaddr(pthread_attr_t * attr,void * stackAddr)1216 int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackAddr)
1217 {
1218     if (attr == NULL) {
1219         return EINVAL;
1220     }
1221 
1222     attr->stackaddr     = stackAddr;
1223 
1224     return 0;
1225 }
1226 
pthread_attr_getstackaddr(const pthread_attr_t * attr,void ** stackAddr)1227 int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackAddr)
1228 {
1229     if (((attr != NULL) && (stackAddr != NULL))) {
1230         *stackAddr = attr->stackaddr;
1231         return 0;
1232     }
1233 
1234     return EINVAL; /* Stack address not set, return EINVAL. */
1235 }
1236 
pthread_attr_setstacksize(pthread_attr_t * attr,size_t stackSize)1237 int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stackSize)
1238 {
1239     /* Reject inadequate stack sizes */
1240     if ((attr == NULL) || (stackSize < PTHREAD_STACK_MIN)) {
1241         return EINVAL;
1242     }
1243 
1244     attr->stacksize     = stackSize;
1245     return 0;
1246 }
1247 
pthread_attr_setstack(pthread_attr_t * attr,void * stackAddr,size_t stackSize)1248 int pthread_attr_setstack(pthread_attr_t *attr, void *stackAddr, size_t stackSize)
1249 {
1250     if ((attr == NULL) || (stackAddr == NULL) || (stackSize < PTHREAD_STACK_MIN)) {
1251         return EINVAL;
1252     }
1253 
1254     attr->stacksize     = stackSize;
1255     attr->stackaddr     = stackAddr;
1256     return 0;
1257 }
1258 
pthread_attr_getstack(const pthread_attr_t * attr,void ** stackAddr,size_t * stackSize)1259 int pthread_attr_getstack(const pthread_attr_t *attr, void **stackAddr, size_t *stackSize)
1260 {
1261     if ((attr == NULL) || (stackAddr == NULL) || (stackSize == NULL)) {
1262         return EINVAL;
1263     }
1264 
1265     *stackAddr = attr->stackaddr;
1266     *stackSize = attr->stacksize;
1267     return 0;
1268 }
1269 
pthread_attr_getstacksize(const pthread_attr_t * attr,size_t * stackSize)1270 int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stackSize)
1271 {
1272     /* Reject attempts to get a stack size when one has not been set. */
1273     if ((attr == NULL) || (stackSize == NULL)) {
1274         return EINVAL;
1275     }
1276 
1277     *stackSize = attr->stacksize;
1278 
1279     return 0;
1280 }
1281 
pthread_create(pthread_t * thread,const pthread_attr_t * attr,void * (* startRoutine)(void *),void * arg)1282 int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
1283                    void *(*startRoutine) (void *), void *arg)
1284 {
1285     TaskHandle_t xHandle = NULL;
1286 	TSK_INIT_PARAM_S param;
1287     if ((thread == NULL) || (startRoutine == NULL)) {
1288         return EINVAL;
1289     }
1290 	memset(&param, 0, sizeof(param));
1291 	param.pfnTaskEntry = (TSK_ENTRY_FUNC)startRoutine;
1292 	param.usTaskPrio = LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO;
1293 	param.uwArg = (UINT32)arg;
1294 	param.uwStackSize = POSIX_THREAD_STACK_SIZE;
1295 	param.uwResved = LOS_TASK_ATTR_JOINABLE;
1296 	param.pcName = pthreadName;
1297 	if (attr) {
1298 		if (attr->stackaddr) {
1299 			param.stackAddr = (UINTPTR)attr->stackaddr;
1300 			param.uwStackSize = attr->stacksize ? attr->stacksize : POSIX_THREAD_STACK_SIZE;
1301 		}
1302 		if(PTHREAD_CREATE_DETACHED == attr->detachstate ){
1303 			param.uwResved = 0;
1304 		}
1305 		if(0 != attr->schedparam.sched_priority) param.usTaskPrio = attr->schedparam.sched_priority;
1306 	}
1307 
1308 	{
1309 		UINT32 taskID = 0;
1310 		LOS_TaskCreate(&taskID, &param);
1311 		if (thread) *(UINT32 *)thread = taskID;
1312 	}
1313     return 0;
1314 }
1315 
pthread_self(void)1316 pthread_t pthread_self(void)
1317 {
1318     return (pthread_t)LOS_CurTaskIDGet();
1319 }
1320 
pthread_join(pthread_t thread,void ** retval)1321 int pthread_join(pthread_t thread, void **retval)
1322 {
1323     UINTPTR result;
1324     UINT32 ret;
1325 
1326     ret = LOS_TaskJoin((UINT32)thread, &result);
1327     if (ret == LOS_ERRNO_TSK_NOT_JOIN_SELF) {
1328         return EDEADLK;
1329     } else if ((ret == LOS_ERRNO_TSK_NOT_CREATED) ||
1330                (ret == LOS_ERRNO_TSK_OPERATE_IDLE) ||
1331                (ret == LOS_ERRNO_TSK_ID_INVALID) ||
1332                (ret == LOS_ERRNO_TSK_SUSPEND_SWTMR_NOT_ALLOWED)) {
1333         return ESRCH;
1334     } else if (ret != LOS_OK) {
1335         return EINVAL;
1336     }
1337 
1338     if (NULL != retval) {
1339         *retval = (VOID *)result;
1340     }
1341 
1342     return 0;
1343 }
1344 
pthread_setschedprio(pthread_t thread,int prio)1345 int pthread_setschedprio(pthread_t thread, int prio)
1346 {
1347     if (LOS_TaskPriSet((UINT32)thread, (UINT16)prio) != LOS_OK) {
1348         return EINVAL;
1349     }
1350 
1351     return 0;
1352 }
1353 
pthread_detach(pthread_t thread)1354 int pthread_detach(pthread_t thread)
1355 {
1356     UINT32 ret;
1357 
1358     ret = LOS_TaskDetach((UINT32)thread);
1359     if (ret == LOS_ERRNO_TSK_NOT_JOIN) {
1360         return ESRCH;
1361     } else if (ret != LOS_OK) {
1362         return EINVAL;
1363     }
1364 
1365     return 0;
1366 }
1367 
1368 #include "los_swtmr.h"
1369 static struct timespec g_accDeltaFromSet;
ValidTimeSpec(const struct timespec * tp)1370 static bool ValidTimeSpec(const struct timespec *tp)
1371 {
1372     /* Fail a NULL pointer */
1373     if (tp == NULL) {
1374         return false;
1375     }
1376 
1377     /* Fail illegal nanosecond values */
1378     if ((tp->tv_nsec < 0) || (tp->tv_nsec >= OS_SYS_NS_PER_SECOND) || (tp->tv_sec < 0)) {
1379         return false;
1380     }
1381 
1382     return true;
1383 }
timer_create(clockid_t clockID,struct sigevent * restrict evp,timer_t * restrict timerID)1384 int timer_create(clockid_t clockID, struct sigevent *restrict evp, timer_t *restrict timerID)
1385 {
1386     UINT32 ret;
1387     UINT32 swtmrID;
1388 
1389     if (!timerID || (clockID != CLOCK_REALTIME) || !evp) {
1390         errno = EINVAL;
1391         return -1;
1392     }
1393 
1394     if ((evp->sigev_notify != SIGEV_THREAD) || evp->sigev_notify_attributes) {
1395         errno = ENOTSUP;
1396         return -1;
1397     }
1398 
1399     ret = LOS_SwtmrCreate(1, LOS_SWTMR_MODE_ONCE, (SWTMR_PROC_FUNC)evp->sigev_notify_function,
1400                           &swtmrID, (UINT32)(UINTPTR)evp->sigev_value.sival_ptr
1401 #if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1)
1402                           , OS_SWTMR_ROUSES_IGNORE, OS_SWTMR_ALIGN_INSENSITIVE
1403 #endif
1404     );
1405     if (ret != LOS_OK) {
1406         errno = (ret == LOS_ERRNO_SWTMR_MAXSIZE) ? EAGAIN : EINVAL;
1407         return -1;
1408     }
1409 
1410     *timerID = (timer_t)(UINTPTR)swtmrID;
1411     return 0;
1412 }
1413 
timer_delete(timer_t timerID)1414 int timer_delete(timer_t timerID)
1415 {
1416     UINT32 swtmrID = (UINT32)(UINTPTR)timerID;
1417     if (LOS_SwtmrDelete(swtmrID) != LOS_OK) {
1418         errno = EINVAL;
1419         return -1;
1420     }
1421 
1422     return 0;
1423 }
1424 
OsTimeSpec2Tick(const struct timespec * tp)1425 static UINT32 OsTimeSpec2Tick(const struct timespec *tp)
1426 {
1427     UINT64 tick, ns;
1428 
1429     ns = (UINT64)tp->tv_sec * OS_SYS_NS_PER_SECOND + tp->tv_nsec;
1430     /* Round up for ticks */
1431     tick = (ns * LOSCFG_BASE_CORE_TICK_PER_SECOND + (OS_SYS_NS_PER_SECOND - 1)) / OS_SYS_NS_PER_SECOND;
1432     if (tick > LOS_WAIT_FOREVER) {
1433         tick = LOS_WAIT_FOREVER;
1434     }
1435     return (UINT32)tick;
1436 }
1437 
OsTick2TimeSpec(struct timespec * tp,UINT32 tick)1438 static VOID OsTick2TimeSpec(struct timespec *tp, UINT32 tick)
1439 {
1440     UINT64 ns = ((UINT64)tick * OS_SYS_NS_PER_SECOND) / LOSCFG_BASE_CORE_TICK_PER_SECOND;
1441     tp->tv_sec = (time_t)(ns / OS_SYS_NS_PER_SECOND);
1442     tp->tv_nsec = (long)(ns % OS_SYS_NS_PER_SECOND);
1443 }
OsGetHwTime(struct timespec * hwTime)1444 static VOID OsGetHwTime(struct timespec *hwTime)
1445 {
1446     UINT64 cycle = LOS_SysCycleGet();
1447     UINT64 nowNsec = (cycle / g_sysClock) * OS_SYS_NS_PER_SECOND +
1448                      (cycle % g_sysClock) * OS_SYS_NS_PER_SECOND / g_sysClock;
1449 
1450     hwTime->tv_sec = nowNsec / OS_SYS_NS_PER_SECOND;
1451     hwTime->tv_nsec = nowNsec % OS_SYS_NS_PER_SECOND;
1452 }
OsGetRealTime(struct timespec * realTime)1453 static VOID OsGetRealTime(struct timespec *realTime)
1454 {
1455     UINT32 intSave;
1456     struct timespec hwTime = {0};
1457     OsGetHwTime(&hwTime);
1458     intSave = LOS_IntLock();
1459     realTime->tv_nsec = hwTime.tv_nsec + g_accDeltaFromSet.tv_nsec;
1460     realTime->tv_sec = hwTime.tv_sec + g_accDeltaFromSet.tv_sec + (realTime->tv_nsec >= OS_SYS_NS_PER_SECOND);
1461     realTime->tv_nsec %= OS_SYS_NS_PER_SECOND;
1462     LOS_IntRestore(intSave);
1463 }
1464 
OsSetRealTime(const struct timespec * realTime)1465 static VOID OsSetRealTime(const struct timespec *realTime)
1466 {
1467     UINT32 intSave;
1468     struct timespec hwTime = {0};
1469     OsGetHwTime(&hwTime);
1470     intSave = LOS_IntLock();
1471     g_accDeltaFromSet.tv_nsec = realTime->tv_nsec - hwTime.tv_nsec;
1472     g_accDeltaFromSet.tv_sec = realTime->tv_sec - hwTime.tv_sec - (g_accDeltaFromSet.tv_nsec < 0);
1473     g_accDeltaFromSet.tv_nsec = (g_accDeltaFromSet.tv_nsec + OS_SYS_NS_PER_SECOND) % OS_SYS_NS_PER_SECOND;
1474     LOS_IntRestore(intSave);
1475 }
timer_settime(timer_t timerID,int flags,const struct itimerspec * restrict value,struct itimerspec * restrict oldValue)1476 int timer_settime(timer_t timerID, int flags,
1477                   const struct itimerspec *restrict value,
1478                   struct itimerspec *restrict oldValue)
1479 {
1480     UINT32 intSave;
1481     UINT32 swtmrID = (UINT32)(UINTPTR)timerID;
1482     SWTMR_CTRL_S *swtmr = NULL;
1483     UINT32 interval, expiry, ret;
1484 
1485     if (flags != 0) {
1486         /* flags not supported currently */
1487         errno = ENOTSUP;
1488         return -1;
1489     }
1490 
1491     if (value == NULL) {
1492         errno = EINVAL;
1493         return -1;
1494     }
1495 
1496     if (!ValidTimeSpec(&value->it_value) || !ValidTimeSpec(&value->it_interval)) {
1497         errno = EINVAL;
1498         return -1;
1499     }
1500 
1501     expiry = OsTimeSpec2Tick(&value->it_value);
1502     interval = OsTimeSpec2Tick(&value->it_interval);
1503 
1504     /* if specified interval, it must be same with expiry due to the limitation of liteos-m */
1505     if (interval && interval != expiry) {
1506         errno = ENOTSUP;
1507         return -1;
1508     }
1509 
1510     if (oldValue) {
1511         (VOID)timer_gettime(timerID, oldValue);
1512     }
1513 
1514     ret = LOS_SwtmrStop(swtmrID);
1515     if ((ret != LOS_OK) && (ret != LOS_ERRNO_SWTMR_NOT_STARTED)) {
1516         errno = EINVAL;
1517         return -1;
1518     }
1519 
1520     intSave = LOS_IntLock();
1521     swtmr = OS_SWT_FROM_SID(swtmrID);
1522     swtmr->ucMode = (interval ? LOS_SWTMR_MODE_PERIOD : LOS_SWTMR_MODE_NO_SELFDELETE);
1523     swtmr->uwInterval = (interval ? interval : expiry);
1524 
1525     swtmr->ucOverrun = 0;
1526     LOS_IntRestore(intSave);
1527 
1528     if ((value->it_value.tv_sec == 0) && (value->it_value.tv_nsec == 0)) {
1529         /*
1530          * 1) when expiry is 0, means timer should be stopped.
1531          * 2) If timer is ticking, stopping timer is already done before.
1532          * 3) If timer is created but not ticking, return 0 as well.
1533          */
1534         return 0;
1535     }
1536 
1537     if (LOS_SwtmrStart(swtmr->usTimerID) != LOS_OK) {
1538         errno = EINVAL;
1539         return -1;
1540     }
1541 
1542     return 0;
1543 }
1544 
timer_gettime(timer_t timerID,struct itimerspec * value)1545 int timer_gettime(timer_t timerID, struct itimerspec *value)
1546 {
1547     UINT32 tick = 0;
1548     SWTMR_CTRL_S *swtmr = NULL;
1549     UINT32 swtmrID = (UINT32)(UINTPTR)timerID;
1550     UINT32 ret;
1551 
1552     if (value == NULL) {
1553         errno = EINVAL;
1554         return -1;
1555     }
1556 
1557     swtmr = OS_SWT_FROM_SID(swtmrID);
1558 
1559     /* get expire time */
1560     ret = LOS_SwtmrTimeGet(swtmr->usTimerID, &tick);
1561     if ((ret != LOS_OK) && (ret != LOS_ERRNO_SWTMR_NOT_STARTED)) {
1562         errno = EINVAL;
1563         return -1;
1564     }
1565     if (ret == LOS_ERRNO_SWTMR_NOT_STARTED) {
1566         tick = 0;
1567     }
1568     OsTick2TimeSpec(&value->it_value, tick);
1569     OsTick2TimeSpec(&value->it_interval, (swtmr->ucMode == LOS_SWTMR_MODE_ONCE) ? 0 : swtmr->uwInterval);
1570     return 0;
1571 }
1572 
1573 #include "kal/libc/newlib/porting/include/semaphore.h"
1574 #include "los_sem.h"
1575 
1576 #define _SEM_MAGIC 0xEBCFDEA1
1577 
1578 #define s_magic __val[0]
1579 #define s_handle __val[1]
OsGetTickTimeFromNow(const struct timespec * ts,clockid_t clockId,UINT64 * absTicks)1580 static INT32 OsGetTickTimeFromNow(const struct timespec *ts, clockid_t clockId, UINT64 *absTicks)
1581 {
1582     struct timespec tp;
1583     UINT64 nseconds;
1584     UINT64 currTime;
1585     const UINT32 nsPerTick = OS_SYS_NS_PER_SECOND / LOSCFG_BASE_CORE_TICK_PER_SECOND;
1586 
1587     if (!ValidTimeSpec(ts)) {
1588         return EINVAL;
1589     }
1590 
1591     clock_gettime(clockId, &tp);
1592     currTime = (UINT64)tp.tv_sec * OS_SYS_NS_PER_SECOND + tp.tv_nsec;
1593     nseconds = (UINT64)ts->tv_sec * OS_SYS_NS_PER_SECOND + ts->tv_nsec;
1594     if (currTime >= nseconds) {
1595         return ETIMEDOUT;
1596     }
1597     *absTicks = ((nseconds - currTime) + nsPerTick - 1) / nsPerTick + 1;
1598 
1599     return 0;
1600 }
MapError(UINT32 err)1601 static inline int MapError(UINT32 err)
1602 {
1603     switch (err) {
1604         case LOS_OK:
1605             return 0;
1606         case LOS_ERRNO_SEM_INVALID:
1607         case LOS_ERRNO_SEM_UNAVAILABLE:
1608             return EINVAL;
1609         case LOS_ERRNO_SEM_ALL_BUSY:
1610             return ENOSPC;
1611         case LOS_ERRNO_SEM_OVERFLOW:
1612             return ENOMEM;
1613         case LOS_ERRNO_SEM_PENDED:
1614             return EBUSY;
1615         case LOS_ERRNO_SEM_PEND_IN_LOCK:
1616             return EPERM;
1617         case LOS_ERRNO_SEM_PEND_INTERR:
1618             return EINTR;
1619         case LOS_ERRNO_SEM_TIMEOUT:
1620             return ETIMEDOUT;
1621         default:
1622             return EINVAL;
1623     }
1624 }
1625 
sem_init(sem_t * sem,int shared,unsigned int value)1626 int sem_init(sem_t *sem, int shared, unsigned int value)
1627 {
1628     UINT32 semHandle = 0;
1629     UINT32 ret;
1630 
1631     (VOID)shared;
1632     if ((sem == NULL) || (value >= OS_SEM_COUNTING_MAX_COUNT)) {
1633         errno = EINVAL;
1634         return -1;
1635     }
1636 
1637     ret = LOS_SemCreate(value, &semHandle);
1638     if (ret != LOS_OK) {
1639         errno = MapError(ret);
1640         return -1;
1641     }
1642 
1643     sem->s_magic = (INT32)_SEM_MAGIC;
1644     sem->s_handle = (INT32)semHandle;
1645 
1646     return 0;
1647 }
1648 
sem_destroy(sem_t * sem)1649 int sem_destroy(sem_t *sem)
1650 {
1651     UINT32 ret;
1652 
1653     if ((sem == NULL) || (sem->s_magic != (INT32)_SEM_MAGIC)) {
1654         errno = EINVAL;
1655         return -1;
1656     }
1657 
1658     ret = LOS_SemDelete((UINT32)sem->s_handle);
1659     if (ret != LOS_OK) {
1660         errno = MapError(ret);
1661         return -1;
1662     }
1663 
1664     return 0;
1665 }
1666 
sem_wait(sem_t * sem)1667 int sem_wait(sem_t *sem)
1668 {
1669     UINT32 ret;
1670 
1671     if ((sem == NULL) || (sem->s_magic != (INT32)_SEM_MAGIC)) {
1672         errno = EINVAL;
1673         return -1;
1674     }
1675 
1676     ret = LOS_SemPend((UINT32)sem->s_handle, LOS_WAIT_FOREVER);
1677     if (ret != LOS_OK) {
1678         errno = MapError(ret);
1679         return -1;
1680     }
1681 
1682     return 0;
1683 }
1684 
sem_post(sem_t * sem)1685 int sem_post(sem_t *sem)
1686 {
1687     UINT32 ret;
1688 
1689     if ((sem == NULL) || (sem->s_magic != (INT32)_SEM_MAGIC)) {
1690         errno = EINVAL;
1691         return -1;
1692     }
1693 
1694     ret = LOS_SemPost((UINT32)sem->s_handle);
1695     if (ret != LOS_OK) {
1696         errno = MapError(ret);
1697         return -1;
1698     }
1699 
1700     return 0;
1701 }
1702 
sem_trywait(sem_t * sem)1703 int sem_trywait(sem_t *sem)
1704 {
1705     UINT32 ret;
1706 
1707     if ((sem == NULL) || (sem->s_magic != (INT32)_SEM_MAGIC)) {
1708         errno = EINVAL;
1709         return -1;
1710     }
1711 
1712     ret = LOS_SemPend((UINT32)sem->s_handle, LOS_NO_WAIT);
1713     if (ret != LOS_OK) {
1714         errno = MapError(ret);
1715         return -1;
1716     }
1717 
1718     return 0;
1719 }
1720 
sem_timedwait(sem_t * sem,const struct timespec * timeout)1721 int sem_timedwait(sem_t *sem, const struct timespec *timeout)
1722 {
1723     UINT32 ret;
1724     UINT64 tickCnt;
1725 
1726     if ((sem == NULL) || (sem->s_magic != (INT32)_SEM_MAGIC)) {
1727         errno = EINVAL;
1728         return -1;
1729     }
1730 
1731     ret = OsGetTickTimeFromNow(timeout, CLOCK_REALTIME, &tickCnt);
1732     if (ret != 0) {
1733         errno = (INT32)ret;
1734         return -1;
1735     }
1736 
1737     if (tickCnt > LOS_WAIT_FOREVER) {
1738         tickCnt = LOS_WAIT_FOREVER;
1739     }
1740 
1741     ret = LOS_SemPend((UINT32)sem->s_handle, (UINT32)tickCnt);
1742     if (ret != LOS_OK) {
1743         errno = MapError(ret);
1744         return -1;
1745     }
1746 
1747     return 0;
1748 }
1749 
sem_getvalue(sem_t * sem,int * currVal)1750 int sem_getvalue(sem_t *sem, int *currVal)
1751 {
1752     UINT32 ret;
1753 
1754     if ((sem == NULL) || (sem->s_magic != (INT32)_SEM_MAGIC)|| (currVal == NULL)) {
1755         errno = EINVAL;
1756         return -1;
1757     }
1758 
1759     ret = LOS_SemGetValue(sem->s_handle, currVal);
1760     if (ret) {
1761         errno = EINVAL;
1762         return -1;
1763     }
1764 
1765     return LOS_OK;
1766 }
1767 #endif
1768