pthread.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  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. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. //
  14. // This module implements pthread API on top of FreeRTOS. API is implemented to the level allowing
  15. // libstdcxx threading framework to operate correctly. So not all original pthread routines are supported.
  16. //
  17. #include <time.h>
  18. #include <errno.h>
  19. #include <pthread.h>
  20. #include <string.h>
  21. #include "esp_err.h"
  22. #include "esp_attr.h"
  23. #include "rom/queue.h"
  24. #include "freertos/FreeRTOS.h"
  25. #include "freertos/task.h"
  26. #include "freertos/semphr.h"
  27. #include "pthread_internal.h"
  28. #include "esp_pthread.h"
  29. #define LOG_LOCAL_LEVEL CONFIG_LOG_DEFAULT_LEVEL
  30. #include "esp_log.h"
  31. const static char *TAG = "pthread";
  32. /** task state */
  33. enum esp_pthread_task_state {
  34. PTHREAD_TASK_STATE_RUN,
  35. PTHREAD_TASK_STATE_EXIT
  36. };
  37. /** pthread thread FreeRTOS wrapper */
  38. typedef struct esp_pthread_entry {
  39. SLIST_ENTRY(esp_pthread_entry) list_node; ///< Tasks list node struct.
  40. TaskHandle_t handle; ///< FreeRTOS task handle
  41. TaskHandle_t join_task; ///< Handle of the task waiting to join
  42. enum esp_pthread_task_state state; ///< pthread task state
  43. bool detached; ///< True if pthread is detached
  44. void *retval; ///< Value supplied to calling thread during join
  45. void *task_arg; ///< Task arguments
  46. } esp_pthread_t;
  47. /** pthread wrapper task arg */
  48. typedef struct {
  49. void *(*func)(void *); ///< user task entry
  50. void *arg; ///< user task argument
  51. esp_pthread_cfg_t cfg; ///< pthread configuration
  52. } esp_pthread_task_arg_t;
  53. /** pthread mutex FreeRTOS wrapper */
  54. typedef struct {
  55. SemaphoreHandle_t sem; ///< Handle of the task waiting to join
  56. int type; ///< Mutex type. Currently supported PTHREAD_MUTEX_NORMAL and PTHREAD_MUTEX_RECURSIVE
  57. } esp_pthread_mutex_t;
  58. static SemaphoreHandle_t s_threads_mux = NULL;
  59. static portMUX_TYPE s_mutex_init_lock = portMUX_INITIALIZER_UNLOCKED;
  60. static SLIST_HEAD(esp_thread_list_head, esp_pthread_entry) s_threads_list
  61. = SLIST_HEAD_INITIALIZER(s_threads_list);
  62. static pthread_key_t s_pthread_cfg_key;
  63. static int IRAM_ATTR pthread_mutex_lock_internal(esp_pthread_mutex_t *mux, TickType_t tmo);
  64. static void esp_pthread_cfg_key_destructor(void *value)
  65. {
  66. free(value);
  67. }
  68. esp_err_t esp_pthread_init(void)
  69. {
  70. if (pthread_key_create(&s_pthread_cfg_key, esp_pthread_cfg_key_destructor) != 0) {
  71. return ESP_ERR_NO_MEM;
  72. }
  73. s_threads_mux = xSemaphoreCreateMutex();
  74. if (s_threads_mux == NULL) {
  75. pthread_key_delete(s_pthread_cfg_key);
  76. return ESP_ERR_NO_MEM;
  77. }
  78. return ESP_OK;
  79. }
  80. static void *pthread_list_find_item(void *(*item_check)(esp_pthread_t *, void *arg), void *check_arg)
  81. {
  82. esp_pthread_t *it;
  83. SLIST_FOREACH(it, &s_threads_list, list_node) {
  84. void *val = item_check(it, check_arg);
  85. if (val) {
  86. return val;
  87. }
  88. }
  89. return NULL;
  90. }
  91. static void *pthread_get_handle_by_desc(esp_pthread_t *item, void *desc)
  92. {
  93. if (item == desc) {
  94. return item->handle;
  95. }
  96. return NULL;
  97. }
  98. static void *pthread_get_desc_by_handle(esp_pthread_t *item, void *hnd)
  99. {
  100. if (hnd == item->handle) {
  101. return item;
  102. }
  103. return NULL;
  104. }
  105. static inline TaskHandle_t pthread_find_handle(pthread_t thread)
  106. {
  107. return pthread_list_find_item(pthread_get_handle_by_desc, (void *)thread);
  108. }
  109. static esp_pthread_t *pthread_find(TaskHandle_t task_handle)
  110. {
  111. return pthread_list_find_item(pthread_get_desc_by_handle, task_handle);
  112. }
  113. static void pthread_delete(esp_pthread_t *pthread)
  114. {
  115. SLIST_REMOVE(&s_threads_list, pthread, esp_pthread_entry, list_node);
  116. free(pthread);
  117. }
  118. /* Call this function to configure pthread stacks in Pthreads */
  119. esp_err_t esp_pthread_set_cfg(const esp_pthread_cfg_t *cfg)
  120. {
  121. if (cfg->stack_size < PTHREAD_STACK_MIN) {
  122. return ESP_ERR_INVALID_ARG;
  123. }
  124. /* If a value is already set, update that value */
  125. esp_pthread_cfg_t *p = pthread_getspecific(s_pthread_cfg_key);
  126. if (!p) {
  127. p = malloc(sizeof(esp_pthread_cfg_t));
  128. if (!p) {
  129. return ESP_ERR_NO_MEM;
  130. }
  131. }
  132. *p = *cfg;
  133. pthread_setspecific(s_pthread_cfg_key, p);
  134. return 0;
  135. }
  136. esp_err_t esp_pthread_get_cfg(esp_pthread_cfg_t *p)
  137. {
  138. esp_pthread_cfg_t *cfg = pthread_getspecific(s_pthread_cfg_key);
  139. if (cfg) {
  140. *p = *cfg;
  141. return ESP_OK;
  142. }
  143. memset(p, 0, sizeof(*p));
  144. return ESP_ERR_NOT_FOUND;
  145. }
  146. static void pthread_task_func(void *arg)
  147. {
  148. void *rval = NULL;
  149. esp_pthread_task_arg_t *task_arg = (esp_pthread_task_arg_t *)arg;
  150. ESP_LOGV(TAG, "%s ENTER %p", __FUNCTION__, task_arg->func);
  151. // wait for start
  152. xTaskNotifyWait(0, 0, NULL, portMAX_DELAY);
  153. if (task_arg->cfg.inherit_cfg) {
  154. /* If inherit option is set, then do a set_cfg() ourselves for future forks */
  155. esp_pthread_set_cfg(&task_arg->cfg);
  156. }
  157. ESP_LOGV(TAG, "%s START %p", __FUNCTION__, task_arg->func);
  158. rval = task_arg->func(task_arg->arg);
  159. ESP_LOGV(TAG, "%s END %p", __FUNCTION__, task_arg->func);
  160. pthread_exit(rval);
  161. ESP_LOGV(TAG, "%s EXIT", __FUNCTION__);
  162. }
  163. int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
  164. void *(*start_routine) (void *), void *arg)
  165. {
  166. TaskHandle_t xHandle = NULL;
  167. ESP_LOGV(TAG, "%s", __FUNCTION__);
  168. esp_pthread_task_arg_t *task_arg = calloc(1, sizeof(esp_pthread_task_arg_t));
  169. if (task_arg == NULL) {
  170. ESP_LOGE(TAG, "Failed to allocate task args!");
  171. return ENOMEM;
  172. }
  173. esp_pthread_t *pthread = calloc(1, sizeof(esp_pthread_t));
  174. if (pthread == NULL) {
  175. ESP_LOGE(TAG, "Failed to allocate pthread data!");
  176. free(task_arg);
  177. return ENOMEM;
  178. }
  179. uint32_t stack_size = CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT;
  180. BaseType_t prio = CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT;
  181. esp_pthread_cfg_t *pthread_cfg = pthread_getspecific(s_pthread_cfg_key);
  182. if (pthread_cfg) {
  183. if (pthread_cfg->stack_size) {
  184. stack_size = pthread_cfg->stack_size;
  185. }
  186. if (pthread_cfg->prio && pthread_cfg->prio < configMAX_PRIORITIES) {
  187. prio = pthread_cfg->prio;
  188. }
  189. task_arg->cfg = *pthread_cfg;
  190. }
  191. if (attr) {
  192. /* Overwrite attributes */
  193. stack_size = attr->stacksize;
  194. switch (attr->detachstate) {
  195. case PTHREAD_CREATE_DETACHED:
  196. pthread->detached = true;
  197. break;
  198. case PTHREAD_CREATE_JOINABLE:
  199. default:
  200. pthread->detached = false;
  201. }
  202. }
  203. task_arg->func = start_routine;
  204. task_arg->arg = arg;
  205. pthread->task_arg = task_arg;
  206. BaseType_t res = xTaskCreate(&pthread_task_func, "pthread", stack_size,
  207. task_arg, prio, &xHandle);
  208. if(res != pdPASS) {
  209. ESP_LOGE(TAG, "Failed to create task!");
  210. free(pthread);
  211. free(task_arg);
  212. if (res == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY) {
  213. return ENOMEM;
  214. } else {
  215. return EAGAIN;
  216. }
  217. }
  218. pthread->handle = xHandle;
  219. if (xSemaphoreTake(s_threads_mux, portMAX_DELAY) != pdTRUE) {
  220. assert(false && "Failed to lock threads list!");
  221. }
  222. SLIST_INSERT_HEAD(&s_threads_list, pthread, list_node);
  223. xSemaphoreGive(s_threads_mux);
  224. // start task
  225. xTaskNotify(xHandle, 0, eNoAction);
  226. *thread = (pthread_t)pthread; // pointer value fit into pthread_t (uint32_t)
  227. ESP_LOGV(TAG, "Created task %x", (uint32_t)xHandle);
  228. return 0;
  229. }
  230. int pthread_join(pthread_t thread, void **retval)
  231. {
  232. esp_pthread_t *pthread = (esp_pthread_t *)thread;
  233. int ret = 0;
  234. bool wait = false;
  235. void *child_task_retval = 0;
  236. ESP_LOGV(TAG, "%s %p", __FUNCTION__, pthread);
  237. // find task
  238. if (xSemaphoreTake(s_threads_mux, portMAX_DELAY) != pdTRUE) {
  239. assert(false && "Failed to lock threads list!");
  240. }
  241. TaskHandle_t handle = pthread_find_handle(thread);
  242. if (!handle) {
  243. // not found
  244. ret = ESRCH;
  245. } else if (pthread->detached) {
  246. // Thread is detached
  247. ret = EDEADLK;
  248. } else if (pthread->join_task) {
  249. // already have waiting task to join
  250. ret = EINVAL;
  251. } else if (handle == xTaskGetCurrentTaskHandle()) {
  252. // join to self not allowed
  253. ret = EDEADLK;
  254. } else {
  255. esp_pthread_t *cur_pthread = pthread_find(xTaskGetCurrentTaskHandle());
  256. if (cur_pthread && cur_pthread->join_task == handle) {
  257. // join to each other not allowed
  258. ret = EDEADLK;
  259. } else {
  260. if (pthread->state == PTHREAD_TASK_STATE_RUN) {
  261. pthread->join_task = xTaskGetCurrentTaskHandle();
  262. wait = true;
  263. } else {
  264. child_task_retval = pthread->retval;
  265. pthread_delete(pthread);
  266. }
  267. }
  268. }
  269. xSemaphoreGive(s_threads_mux);
  270. if (ret == 0) {
  271. if (wait) {
  272. xTaskNotifyWait(0, 0, NULL, portMAX_DELAY);
  273. if (xSemaphoreTake(s_threads_mux, portMAX_DELAY) != pdTRUE) {
  274. assert(false && "Failed to lock threads list!");
  275. }
  276. child_task_retval = pthread->retval;
  277. pthread_delete(pthread);
  278. xSemaphoreGive(s_threads_mux);
  279. }
  280. vTaskDelete(handle);
  281. }
  282. if (retval) {
  283. *retval = child_task_retval;
  284. }
  285. ESP_LOGV(TAG, "%s %p EXIT %d", __FUNCTION__, pthread, ret);
  286. return ret;
  287. }
  288. int pthread_detach(pthread_t thread)
  289. {
  290. esp_pthread_t *pthread = (esp_pthread_t *)thread;
  291. int ret = 0;
  292. if (xSemaphoreTake(s_threads_mux, portMAX_DELAY) != pdTRUE) {
  293. assert(false && "Failed to lock threads list!");
  294. }
  295. TaskHandle_t handle = pthread_find_handle(thread);
  296. if (!handle) {
  297. ret = ESRCH;
  298. } else {
  299. pthread->detached = true;
  300. }
  301. xSemaphoreGive(s_threads_mux);
  302. ESP_LOGV(TAG, "%s %p EXIT %d", __FUNCTION__, pthread, ret);
  303. return ret;
  304. }
  305. void pthread_exit(void *value_ptr)
  306. {
  307. bool detached = false;
  308. /* preemptively clean up thread local storage, rather than
  309. waiting for the idle task to clean up the thread */
  310. pthread_internal_local_storage_destructor_callback();
  311. if (xSemaphoreTake(s_threads_mux, portMAX_DELAY) != pdTRUE) {
  312. assert(false && "Failed to lock threads list!");
  313. }
  314. esp_pthread_t *pthread = pthread_find(xTaskGetCurrentTaskHandle());
  315. if (!pthread) {
  316. assert(false && "Failed to find pthread for current task!");
  317. }
  318. if (pthread->task_arg) {
  319. free(pthread->task_arg);
  320. }
  321. if (pthread->detached) {
  322. // auto-free for detached threads
  323. pthread_delete(pthread);
  324. detached = true;
  325. } else {
  326. // Set return value
  327. pthread->retval = value_ptr;
  328. // Remove from list, it indicates that task has exited
  329. if (pthread->join_task) {
  330. // notify join
  331. xTaskNotify(pthread->join_task, 0, eNoAction);
  332. } else {
  333. pthread->state = PTHREAD_TASK_STATE_EXIT;
  334. }
  335. }
  336. xSemaphoreGive(s_threads_mux);
  337. ESP_LOGD(TAG, "Task stk_wm = %d", uxTaskGetStackHighWaterMark(NULL));
  338. if (detached) {
  339. vTaskDelete(NULL);
  340. } else {
  341. vTaskSuspend(NULL);
  342. }
  343. ESP_LOGV(TAG, "%s EXIT", __FUNCTION__);
  344. }
  345. int pthread_cancel(pthread_t thread)
  346. {
  347. ESP_LOGE(TAG, "%s: not supported!", __FUNCTION__);
  348. return ENOSYS;
  349. }
  350. int sched_yield( void )
  351. {
  352. vTaskDelay(0);
  353. return 0;
  354. }
  355. pthread_t pthread_self(void)
  356. {
  357. if (xSemaphoreTake(s_threads_mux, portMAX_DELAY) != pdTRUE) {
  358. assert(false && "Failed to lock threads list!");
  359. }
  360. esp_pthread_t *pthread = pthread_find(xTaskGetCurrentTaskHandle());
  361. if (!pthread) {
  362. assert(false && "Failed to find current thread ID!");
  363. }
  364. xSemaphoreGive(s_threads_mux);
  365. return (pthread_t)pthread;
  366. }
  367. int pthread_equal(pthread_t t1, pthread_t t2)
  368. {
  369. return t1 == t2 ? 1 : 0;
  370. }
  371. /***************** ONCE ******************/
  372. int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
  373. {
  374. if (once_control == NULL || init_routine == NULL || !once_control->is_initialized) {
  375. ESP_LOGE(TAG, "%s: Invalid args!", __FUNCTION__);
  376. return EINVAL;
  377. }
  378. uint32_t res = 1;
  379. #if defined(CONFIG_SPIRAM_SUPPORT)
  380. if (esp_ptr_external_ram(once_control)) {
  381. uxPortCompareSetExtram((uint32_t *) &once_control->init_executed, 0, &res);
  382. } else {
  383. #endif
  384. uxPortCompareSet((uint32_t *) &once_control->init_executed, 0, &res);
  385. #if defined(CONFIG_SPIRAM_SUPPORT)
  386. }
  387. #endif
  388. // Check if compare and set was successful
  389. if (res == 0) {
  390. ESP_LOGV(TAG, "%s: call init_routine %p", __FUNCTION__, once_control);
  391. init_routine();
  392. }
  393. return 0;
  394. }
  395. /***************** MUTEX ******************/
  396. static int mutexattr_check(const pthread_mutexattr_t *attr)
  397. {
  398. if (attr->type != PTHREAD_MUTEX_NORMAL &&
  399. attr->type != PTHREAD_MUTEX_RECURSIVE &&
  400. attr->type != PTHREAD_MUTEX_ERRORCHECK) {
  401. return EINVAL;
  402. }
  403. return 0;
  404. }
  405. int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
  406. {
  407. int type = PTHREAD_MUTEX_NORMAL;
  408. if (!mutex) {
  409. return EINVAL;
  410. }
  411. if (attr) {
  412. if (!attr->is_initialized) {
  413. return EINVAL;
  414. }
  415. int res = mutexattr_check(attr);
  416. if (res) {
  417. return res;
  418. }
  419. type = attr->type;
  420. }
  421. esp_pthread_mutex_t *mux = (esp_pthread_mutex_t *)malloc(sizeof(esp_pthread_mutex_t));
  422. if (!mux) {
  423. return ENOMEM;
  424. }
  425. mux->type = type;
  426. if (mux->type == PTHREAD_MUTEX_RECURSIVE) {
  427. mux->sem = xSemaphoreCreateRecursiveMutex();
  428. } else {
  429. mux->sem = xSemaphoreCreateMutex();
  430. }
  431. if (!mux->sem) {
  432. free(mux);
  433. return EAGAIN;
  434. }
  435. *mutex = (pthread_mutex_t)mux; // pointer value fit into pthread_mutex_t (uint32_t)
  436. return 0;
  437. }
  438. int pthread_mutex_destroy(pthread_mutex_t *mutex)
  439. {
  440. esp_pthread_mutex_t *mux;
  441. ESP_LOGV(TAG, "%s %p", __FUNCTION__, mutex);
  442. if (!mutex) {
  443. return EINVAL;
  444. }
  445. mux = (esp_pthread_mutex_t *)*mutex;
  446. if (!mux) {
  447. return EINVAL;
  448. }
  449. // check if mux is busy
  450. int res = pthread_mutex_lock_internal(mux, 0);
  451. if (res == EBUSY) {
  452. return EBUSY;
  453. }
  454. vSemaphoreDelete(mux->sem);
  455. free(mux);
  456. return 0;
  457. }
  458. static int IRAM_ATTR pthread_mutex_lock_internal(esp_pthread_mutex_t *mux, TickType_t tmo)
  459. {
  460. if (!mux) {
  461. return EINVAL;
  462. }
  463. if ((mux->type == PTHREAD_MUTEX_ERRORCHECK) &&
  464. (xSemaphoreGetMutexHolder(mux->sem) == xTaskGetCurrentTaskHandle())) {
  465. return EDEADLK;
  466. }
  467. if (mux->type == PTHREAD_MUTEX_RECURSIVE) {
  468. if (xSemaphoreTakeRecursive(mux->sem, tmo) != pdTRUE) {
  469. return EBUSY;
  470. }
  471. } else {
  472. if (xSemaphoreTake(mux->sem, tmo) != pdTRUE) {
  473. return EBUSY;
  474. }
  475. }
  476. return 0;
  477. }
  478. static int pthread_mutex_init_if_static(pthread_mutex_t *mutex)
  479. {
  480. int res = 0;
  481. if ((intptr_t) *mutex == PTHREAD_MUTEX_INITIALIZER) {
  482. portENTER_CRITICAL(&s_mutex_init_lock);
  483. if ((intptr_t) *mutex == PTHREAD_MUTEX_INITIALIZER) {
  484. res = pthread_mutex_init(mutex, NULL);
  485. }
  486. portEXIT_CRITICAL(&s_mutex_init_lock);
  487. }
  488. return res;
  489. }
  490. int IRAM_ATTR pthread_mutex_lock(pthread_mutex_t *mutex)
  491. {
  492. if (!mutex) {
  493. return EINVAL;
  494. }
  495. int res = pthread_mutex_init_if_static(mutex);
  496. if (res != 0) {
  497. return res;
  498. }
  499. return pthread_mutex_lock_internal((esp_pthread_mutex_t *)*mutex, portMAX_DELAY);
  500. }
  501. int IRAM_ATTR pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *timeout)
  502. {
  503. if (!mutex) {
  504. return EINVAL;
  505. }
  506. int res = pthread_mutex_init_if_static(mutex);
  507. if (res != 0) {
  508. return res;
  509. }
  510. struct timespec currtime;
  511. clock_gettime(CLOCK_REALTIME, &currtime);
  512. TickType_t tmo = ((timeout->tv_sec - currtime.tv_sec)*1000 +
  513. (timeout->tv_nsec - currtime.tv_nsec)/1000000)/portTICK_PERIOD_MS;
  514. res = pthread_mutex_lock_internal((esp_pthread_mutex_t *)*mutex, tmo);
  515. if (res == EBUSY) {
  516. return ETIMEDOUT;
  517. }
  518. return res;
  519. }
  520. int IRAM_ATTR pthread_mutex_trylock(pthread_mutex_t *mutex)
  521. {
  522. if (!mutex) {
  523. return EINVAL;
  524. }
  525. int res = pthread_mutex_init_if_static(mutex);
  526. if (res != 0) {
  527. return res;
  528. }
  529. return pthread_mutex_lock_internal((esp_pthread_mutex_t *)*mutex, 0);
  530. }
  531. int IRAM_ATTR pthread_mutex_unlock(pthread_mutex_t *mutex)
  532. {
  533. esp_pthread_mutex_t *mux;
  534. if (!mutex) {
  535. return EINVAL;
  536. }
  537. mux = (esp_pthread_mutex_t *)*mutex;
  538. if (!mux) {
  539. return EINVAL;
  540. }
  541. if (((mux->type == PTHREAD_MUTEX_RECURSIVE) ||
  542. (mux->type == PTHREAD_MUTEX_ERRORCHECK)) &&
  543. (xSemaphoreGetMutexHolder(mux->sem) != xTaskGetCurrentTaskHandle())) {
  544. return EPERM;
  545. }
  546. int ret;
  547. if (mux->type == PTHREAD_MUTEX_RECURSIVE) {
  548. ret = xSemaphoreGiveRecursive(mux->sem);
  549. } else {
  550. ret = xSemaphoreGive(mux->sem);
  551. }
  552. if (ret != pdTRUE) {
  553. assert(false && "Failed to unlock mutex!");
  554. }
  555. return 0;
  556. }
  557. int pthread_mutexattr_init(pthread_mutexattr_t *attr)
  558. {
  559. if (!attr) {
  560. return EINVAL;
  561. }
  562. attr->type = PTHREAD_MUTEX_NORMAL;
  563. attr->is_initialized = 1;
  564. return 0;
  565. }
  566. int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
  567. {
  568. if (!attr) {
  569. return EINVAL;
  570. }
  571. attr->is_initialized = 0;
  572. return 0;
  573. }
  574. int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
  575. {
  576. if (!attr) {
  577. return EINVAL;
  578. }
  579. *type = attr->type;
  580. return 0;
  581. }
  582. int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
  583. {
  584. if (!attr) {
  585. return EINVAL;
  586. }
  587. pthread_mutexattr_t tmp_attr = {.type = type};
  588. int res = mutexattr_check(&tmp_attr);
  589. if (!res) {
  590. attr->type = type;
  591. }
  592. return res;
  593. }
  594. /***************** ATTRIBUTES ******************/
  595. int pthread_attr_init(pthread_attr_t *attr)
  596. {
  597. if (attr) {
  598. /* Nothing to allocate. Set everything to default */
  599. attr->stacksize = CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT;
  600. attr->detachstate = PTHREAD_CREATE_JOINABLE;
  601. return 0;
  602. }
  603. return EINVAL;
  604. }
  605. int pthread_attr_destroy(pthread_attr_t *attr)
  606. {
  607. if (attr) {
  608. /* Nothing to deallocate. Reset everything to default */
  609. attr->stacksize = CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT;
  610. attr->detachstate = PTHREAD_CREATE_JOINABLE;
  611. return 0;
  612. }
  613. return EINVAL;
  614. }
  615. int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
  616. {
  617. if (attr) {
  618. *stacksize = attr->stacksize;
  619. return 0;
  620. }
  621. return EINVAL;
  622. }
  623. int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
  624. {
  625. if (attr && !(stacksize < PTHREAD_STACK_MIN)) {
  626. attr->stacksize = stacksize;
  627. return 0;
  628. }
  629. return EINVAL;
  630. }
  631. int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
  632. {
  633. if (attr) {
  634. *detachstate = attr->detachstate;
  635. return 0;
  636. }
  637. return EINVAL;
  638. }
  639. int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
  640. {
  641. if (attr) {
  642. switch (detachstate) {
  643. case PTHREAD_CREATE_DETACHED:
  644. attr->detachstate = PTHREAD_CREATE_DETACHED;
  645. break;
  646. case PTHREAD_CREATE_JOINABLE:
  647. attr->detachstate = PTHREAD_CREATE_JOINABLE;
  648. break;
  649. default:
  650. return EINVAL;
  651. }
  652. return 0;
  653. }
  654. return EINVAL;
  655. }