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(¶m, 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, ¶m);
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