Projektarbeit Line Following Robot bei Prof. Chowanetz im WS22/23
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

vcos_pthreads.c 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902
  1. /*
  2. Copyright (c) 2012, Broadcom Europe Ltd
  3. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without
  5. modification, are permitted provided that the following conditions are met:
  6. * Redistributions of source code must retain the above copyright
  7. notice, this list of conditions and the following disclaimer.
  8. * Redistributions in binary form must reproduce the above copyright
  9. notice, this list of conditions and the following disclaimer in the
  10. documentation and/or other materials provided with the distribution.
  11. * Neither the name of the copyright holder nor the
  12. names of its contributors may be used to endorse or promote products
  13. derived from this software without specific prior written permission.
  14. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  15. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  17. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
  18. DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  19. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  20. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  21. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  23. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. /*#define VCOS_INLINE_BODIES */
  26. #include "interface/vcos/vcos.h"
  27. #include "interface/vcos/vcos_msgqueue.h"
  28. #include <string.h>
  29. #include <stdarg.h>
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32. #include <sys/time.h>
  33. #include <linux/param.h>
  34. /* Cygwin doesn't always have prctl.h and it doesn't have PR_SET_NAME */
  35. #if defined( __linux__ )
  36. # if !defined(HAVE_PRCTL)
  37. # define HAVE_PRCTL
  38. # endif
  39. #include <sys/prctl.h>
  40. #endif
  41. #ifdef HAVE_CMAKE_CONFIG
  42. #include "cmake_config.h"
  43. #endif
  44. #ifdef HAVE_MTRACE
  45. #include <mcheck.h>
  46. #endif
  47. #if defined(ANDROID)
  48. #include <android/log.h>
  49. #endif
  50. #ifndef VCOS_DEFAULT_STACK_SIZE
  51. #define VCOS_DEFAULT_STACK_SIZE 4096
  52. #endif
  53. static int vcos_argc;
  54. static const char **vcos_argv;
  55. typedef void (*LEGACY_ENTRY_FN_T)(int, void *);
  56. static VCOS_THREAD_ATTR_T default_attrs = {
  57. .ta_stacksz = VCOS_DEFAULT_STACK_SIZE,
  58. };
  59. /** Singleton global lock used for vcos_global_lock/unlock(). */
  60. static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
  61. #ifdef ANDROID
  62. static VCOS_MUTEX_T printf_lock;
  63. #endif
  64. /* Create a per-thread key for faking up vcos access
  65. * on non-vcos threads.
  66. */
  67. pthread_key_t _vcos_thread_current_key;
  68. static VCOS_UNSIGNED _vcos_thread_current_key_created = 0;
  69. static VCOS_ONCE_T current_thread_key_once; /* init just once */
  70. static void vcos_thread_cleanup(VCOS_THREAD_T *thread)
  71. {
  72. vcos_semaphore_delete(&thread->suspend);
  73. if (thread->task_timer_created)
  74. {
  75. vcos_timer_delete(&thread->task_timer);
  76. }
  77. }
  78. static void vcos_dummy_thread_cleanup(void *cxt)
  79. {
  80. VCOS_THREAD_T *thread = cxt;
  81. if (thread->dummy)
  82. {
  83. int i;
  84. /* call termination functions */
  85. for (i=0; thread->at_exit[i].pfn != NULL; i++)
  86. {
  87. thread->at_exit[i].pfn(thread->at_exit[i].cxt);
  88. }
  89. vcos_thread_cleanup(thread);
  90. vcos_free(thread);
  91. }
  92. }
  93. static void current_thread_key_init(void)
  94. {
  95. vcos_assert(!_vcos_thread_current_key_created);
  96. pthread_key_create (&_vcos_thread_current_key, vcos_dummy_thread_cleanup);
  97. _vcos_thread_current_key_created = 1;
  98. }
  99. /* A VCOS wrapper for the thread which called vcos_init. */
  100. static VCOS_THREAD_T vcos_thread_main;
  101. static void *vcos_thread_entry(void *arg)
  102. {
  103. int i;
  104. void *ret;
  105. VCOS_THREAD_T *thread = (VCOS_THREAD_T *)arg;
  106. vcos_assert(thread != NULL);
  107. thread->dummy = 0;
  108. pthread_setspecific(_vcos_thread_current_key, thread);
  109. #if defined( HAVE_PRCTL ) && defined( PR_SET_NAME )
  110. /* cygwin doesn't have PR_SET_NAME */
  111. prctl( PR_SET_NAME, (unsigned long)thread->name, 0, 0, 0 );
  112. #endif
  113. if (thread->legacy)
  114. {
  115. LEGACY_ENTRY_FN_T fn = (LEGACY_ENTRY_FN_T)thread->entry;
  116. (*fn)(0, thread->arg);
  117. ret = 0;
  118. }
  119. else
  120. {
  121. ret = (*thread->entry)(thread->arg);
  122. }
  123. /* call termination functions */
  124. for (i=0; thread->at_exit[i].pfn != NULL; i++)
  125. {
  126. thread->at_exit[i].pfn(thread->at_exit[i].cxt);
  127. }
  128. return ret;
  129. }
  130. static void _task_timer_expiration_routine(void *cxt)
  131. {
  132. VCOS_THREAD_T *thread = (VCOS_THREAD_T *)cxt;
  133. vcos_assert(thread->orig_task_timer_expiration_routine);
  134. thread->orig_task_timer_expiration_routine(thread->orig_task_timer_context);
  135. thread->orig_task_timer_expiration_routine = NULL;
  136. }
  137. VCOS_STATUS_T vcos_thread_create(VCOS_THREAD_T *thread,
  138. const char *name,
  139. VCOS_THREAD_ATTR_T *attrs,
  140. VCOS_THREAD_ENTRY_FN_T entry,
  141. void *arg)
  142. {
  143. VCOS_STATUS_T st;
  144. pthread_attr_t pt_attrs;
  145. VCOS_THREAD_ATTR_T *local_attrs = attrs ? attrs : &default_attrs;
  146. int rc;
  147. vcos_assert(thread);
  148. memset(thread, 0, sizeof(VCOS_THREAD_T));
  149. rc = pthread_attr_init(&pt_attrs);
  150. if (rc < 0)
  151. return VCOS_ENOMEM;
  152. st = vcos_semaphore_create(&thread->suspend, NULL, 0);
  153. if (st != VCOS_SUCCESS)
  154. {
  155. pthread_attr_destroy(&pt_attrs);
  156. return st;
  157. }
  158. pthread_attr_setstacksize(&pt_attrs, local_attrs->ta_stacksz);
  159. #if VCOS_CAN_SET_STACK_ADDR
  160. if (local_attrs->ta_stackaddr)
  161. {
  162. pthread_attr_setstackaddr(&pt_attrs, local_attrs->ta_stackaddr);
  163. }
  164. #else
  165. vcos_demand(local_attrs->ta_stackaddr == 0);
  166. #endif
  167. /* pthread_attr_setpriority(&pt_attrs, local_attrs->ta_priority); */
  168. vcos_assert(local_attrs->ta_stackaddr == 0); /* Not possible */
  169. thread->entry = entry;
  170. thread->arg = arg;
  171. thread->legacy = local_attrs->legacy;
  172. strncpy(thread->name, name, sizeof(thread->name));
  173. thread->name[sizeof(thread->name)-1] = '\0';
  174. memset(thread->at_exit, 0, sizeof(thread->at_exit));
  175. rc = pthread_create(&thread->thread, &pt_attrs, vcos_thread_entry, thread);
  176. pthread_attr_destroy(&pt_attrs);
  177. if (rc < 0)
  178. {
  179. vcos_semaphore_delete(&thread->suspend);
  180. return VCOS_ENOMEM;
  181. }
  182. else
  183. {
  184. return VCOS_SUCCESS;
  185. }
  186. }
  187. void vcos_thread_join(VCOS_THREAD_T *thread,
  188. void **pData)
  189. {
  190. pthread_join(thread->thread, pData);
  191. vcos_thread_cleanup(thread);
  192. }
  193. VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_thread_create_classic(VCOS_THREAD_T *thread,
  194. const char *name,
  195. void *(*entry)(void *arg),
  196. void *arg,
  197. void *stack,
  198. VCOS_UNSIGNED stacksz,
  199. VCOS_UNSIGNED priaff,
  200. VCOS_UNSIGNED timeslice,
  201. VCOS_UNSIGNED autostart)
  202. {
  203. VCOS_THREAD_ATTR_T attrs;
  204. vcos_thread_attr_init(&attrs);
  205. vcos_thread_attr_setstacksize(&attrs, stacksz);
  206. vcos_thread_attr_setpriority(&attrs, priaff & ~_VCOS_AFFINITY_MASK);
  207. vcos_thread_attr_setaffinity(&attrs, priaff & _VCOS_AFFINITY_MASK);
  208. (void)timeslice;
  209. (void)autostart;
  210. if (VCOS_CAN_SET_STACK_ADDR)
  211. {
  212. vcos_thread_attr_setstack(&attrs, stack, stacksz);
  213. }
  214. return vcos_thread_create(thread, name, &attrs, entry, arg);
  215. }
  216. uint64_t vcos_getmicrosecs64_internal(void)
  217. {
  218. struct timeval tv;
  219. uint64_t tm = 0;
  220. if (!gettimeofday(&tv, NULL))
  221. {
  222. tm = (tv.tv_sec * 1000000LL) + tv.tv_usec;
  223. }
  224. return tm;
  225. }
  226. #ifdef ANDROID
  227. static int log_prio[] =
  228. {
  229. ANDROID_LOG_INFO, /* VCOS_LOG_UNINITIALIZED */
  230. ANDROID_LOG_INFO, /* VCOS_LOG_NEVER */
  231. ANDROID_LOG_ERROR, /* VCOS_LOG_ERROR */
  232. ANDROID_LOG_WARN, /* VCOS_LOG_WARN */
  233. ANDROID_LOG_INFO, /* VCOS_LOG_INFO */
  234. ANDROID_LOG_DEBUG /* VCOS_LOG_TRACE */
  235. };
  236. int vcos_use_android_log = 1;
  237. int vcos_log_to_file = 0;
  238. #else
  239. int vcos_use_android_log = 0;
  240. int vcos_log_to_file = 0;
  241. #endif
  242. static FILE * log_fhandle = NULL;
  243. void vcos_vlog_default_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args)
  244. {
  245. (void)_level;
  246. #ifdef ANDROID
  247. if ( vcos_use_android_log )
  248. {
  249. __android_log_vprint(log_prio[_level], cat->name, fmt, args);
  250. }
  251. else
  252. {
  253. vcos_mutex_lock(&printf_lock);
  254. #endif
  255. if(NULL != log_fhandle)
  256. {
  257. if (cat->flags.want_prefix)
  258. fprintf( log_fhandle, "%s: ", cat->name );
  259. vfprintf(log_fhandle, fmt, args);
  260. fputs("\n", log_fhandle);
  261. fflush(log_fhandle);
  262. }
  263. #ifdef ANDROID
  264. vcos_mutex_unlock(&printf_lock);
  265. }
  266. #endif
  267. }
  268. void _vcos_log_platform_init(void)
  269. {
  270. if(vcos_log_to_file)
  271. {
  272. char log_fname[100];
  273. #ifdef ANDROID
  274. snprintf(log_fname, 100, "/data/log/vcos_log%u.txt", vcos_process_id_current());
  275. #else
  276. snprintf(log_fname, 100, "/var/log/vcos_log%u.txt", vcos_process_id_current());
  277. #endif
  278. log_fhandle = fopen(log_fname, "w");
  279. }
  280. else
  281. log_fhandle = stderr;
  282. }
  283. /* Flags for init/deinit components */
  284. enum
  285. {
  286. VCOS_INIT_NAMED_SEM = (1 << 0),
  287. VCOS_INIT_PRINTF_LOCK = (1 << 1),
  288. VCOS_INIT_MAIN_SEM = (1 << 2),
  289. VCOS_INIT_MSGQ = (1 << 3),
  290. VCOS_INIT_ALL = 0xffffffff
  291. };
  292. static void vcos_term(uint32_t flags)
  293. {
  294. if (flags & VCOS_INIT_MSGQ)
  295. vcos_msgq_deinit();
  296. if (flags & VCOS_INIT_MAIN_SEM)
  297. vcos_semaphore_delete(&vcos_thread_main.suspend);
  298. #ifdef ANDROID
  299. if (flags & VCOS_INIT_PRINTF_LOCK)
  300. vcos_mutex_delete(&printf_lock);
  301. #endif
  302. if (flags & VCOS_INIT_NAMED_SEM)
  303. _vcos_named_semaphore_deinit();
  304. }
  305. VCOS_STATUS_T vcos_platform_init(void)
  306. {
  307. VCOS_STATUS_T st;
  308. uint32_t flags = 0;
  309. int pst;
  310. st = _vcos_named_semaphore_init();
  311. if (!vcos_verify(st == VCOS_SUCCESS))
  312. goto end;
  313. flags |= VCOS_INIT_NAMED_SEM;
  314. #ifdef HAVE_MTRACE
  315. /* enable glibc memory debugging, if the environment
  316. * variable MALLOC_TRACE names a valid file.
  317. */
  318. mtrace();
  319. #endif
  320. #ifdef ANDROID
  321. st = vcos_mutex_create(&printf_lock, "printf");
  322. if (!vcos_verify(st == VCOS_SUCCESS))
  323. goto end;
  324. flags |= VCOS_INIT_PRINTF_LOCK;
  325. #endif
  326. st = vcos_once(&current_thread_key_once, current_thread_key_init);
  327. if (!vcos_verify(st == VCOS_SUCCESS))
  328. goto end;
  329. /* Initialise a VCOS wrapper for the thread which called vcos_init. */
  330. st = vcos_semaphore_create(&vcos_thread_main.suspend, NULL, 0);
  331. if (!vcos_verify(st == VCOS_SUCCESS))
  332. goto end;
  333. flags |= VCOS_INIT_MAIN_SEM;
  334. vcos_thread_main.thread = pthread_self();
  335. pst = pthread_setspecific(_vcos_thread_current_key, &vcos_thread_main);
  336. if (!vcos_verify(pst == 0))
  337. {
  338. st = VCOS_EINVAL;
  339. goto end;
  340. }
  341. st = vcos_msgq_init();
  342. if (!vcos_verify(st == VCOS_SUCCESS))
  343. goto end;
  344. flags |= VCOS_INIT_MSGQ;
  345. vcos_logging_init();
  346. end:
  347. if (st != VCOS_SUCCESS)
  348. vcos_term(flags);
  349. return st;
  350. }
  351. void vcos_platform_deinit(void)
  352. {
  353. vcos_term(VCOS_INIT_ALL);
  354. }
  355. void vcos_global_lock(void)
  356. {
  357. pthread_mutex_lock(&lock);
  358. }
  359. void vcos_global_unlock(void)
  360. {
  361. pthread_mutex_unlock(&lock);
  362. }
  363. void vcos_thread_exit(void *arg)
  364. {
  365. VCOS_THREAD_T *thread = vcos_thread_current();
  366. if ( thread && thread->dummy )
  367. {
  368. vcos_free ( (void*) thread );
  369. thread = NULL;
  370. }
  371. pthread_exit(arg);
  372. }
  373. void vcos_thread_attr_init(VCOS_THREAD_ATTR_T *attrs)
  374. {
  375. *attrs = default_attrs;
  376. }
  377. VCOS_STATUS_T vcos_pthreads_map_error(int error)
  378. {
  379. switch (error)
  380. {
  381. case ENOMEM:
  382. return VCOS_ENOMEM;
  383. case ENXIO:
  384. return VCOS_ENXIO;
  385. case EAGAIN:
  386. return VCOS_EAGAIN;
  387. case ENOSPC:
  388. return VCOS_ENOSPC;
  389. default:
  390. return VCOS_EINVAL;
  391. }
  392. }
  393. VCOS_STATUS_T vcos_pthreads_map_errno(void)
  394. {
  395. return vcos_pthreads_map_error(errno);
  396. }
  397. void _vcos_task_timer_set(void (*pfn)(void*), void *cxt, VCOS_UNSIGNED ms)
  398. {
  399. VCOS_THREAD_T *thread = vcos_thread_current();
  400. if (thread == NULL)
  401. return;
  402. vcos_assert(thread->orig_task_timer_expiration_routine == NULL);
  403. if (!thread->task_timer_created)
  404. {
  405. VCOS_STATUS_T st = vcos_timer_create(&thread->task_timer, NULL,
  406. _task_timer_expiration_routine, thread);
  407. (void)st;
  408. vcos_assert(st == VCOS_SUCCESS);
  409. thread->task_timer_created = 1;
  410. }
  411. thread->orig_task_timer_expiration_routine = pfn;
  412. thread->orig_task_timer_context = cxt;
  413. vcos_timer_set(&thread->task_timer, ms);
  414. }
  415. void _vcos_task_timer_cancel(void)
  416. {
  417. VCOS_THREAD_T *thread = vcos_thread_current();
  418. if (thread == NULL || !thread->task_timer_created)
  419. return;
  420. vcos_timer_cancel(&thread->task_timer);
  421. thread->orig_task_timer_expiration_routine = NULL;
  422. }
  423. int vcos_vsnprintf( char *buf, size_t buflen, const char *fmt, va_list ap )
  424. {
  425. return vsnprintf( buf, buflen, fmt, ap );
  426. }
  427. int vcos_snprintf(char *buf, size_t buflen, const char *fmt, ...)
  428. {
  429. int ret;
  430. va_list ap;
  431. va_start(ap,fmt);
  432. ret = vsnprintf(buf, buflen, fmt, ap);
  433. va_end(ap);
  434. return ret;
  435. }
  436. int vcos_have_rtos(void)
  437. {
  438. return 1;
  439. }
  440. const char * vcos_thread_get_name(const VCOS_THREAD_T *thread)
  441. {
  442. return thread->name;
  443. }
  444. #ifdef VCOS_HAVE_BACKTRACK
  445. void __attribute__((weak)) vcos_backtrace_self(void);
  446. #endif
  447. void vcos_pthreads_logging_assert(const char *file, const char *func, unsigned int line, const char *fmt, ...)
  448. {
  449. va_list ap;
  450. va_start(ap, fmt);
  451. fprintf(stderr, "assertion failure:%s:%d:%s():",
  452. file, line, func);
  453. vfprintf(stderr, fmt, ap);
  454. va_end(ap);
  455. fprintf(stderr, "\n");
  456. #ifdef VCOS_HAVE_BACKTRACK
  457. if (vcos_backtrace_self)
  458. vcos_backtrace_self();
  459. #endif
  460. abort();
  461. }
  462. extern VCOS_STATUS_T vcos_thread_at_exit(void (*pfn)(void*), void *cxt)
  463. {
  464. int i;
  465. VCOS_THREAD_T *self = vcos_thread_current();
  466. if (!self)
  467. {
  468. vcos_assert(0);
  469. return VCOS_EINVAL;
  470. }
  471. for (i=0; i<VCOS_MAX_EXIT_HANDLERS; i++)
  472. {
  473. if (self->at_exit[i].pfn == NULL)
  474. {
  475. self->at_exit[i].pfn = pfn;
  476. self->at_exit[i].cxt = cxt;
  477. return VCOS_SUCCESS;
  478. }
  479. }
  480. return VCOS_ENOSPC;
  481. }
  482. void vcos_set_args(int argc, const char **argv)
  483. {
  484. vcos_argc = argc;
  485. vcos_argv = argv;
  486. }
  487. int vcos_get_argc(void)
  488. {
  489. return vcos_argc;
  490. }
  491. const char ** vcos_get_argv(void)
  492. {
  493. return vcos_argv;
  494. }
  495. /* we can't inline this, because HZ comes from sys/param.h which
  496. * dumps all sorts of junk into the global namespace, notable MIN and
  497. * MAX.
  498. */
  499. uint32_t _vcos_get_ticks_per_second(void)
  500. {
  501. return HZ;
  502. }
  503. VCOS_STATUS_T vcos_once(VCOS_ONCE_T *once_control,
  504. void (*init_routine)(void))
  505. {
  506. int rc = pthread_once(once_control, init_routine);
  507. if (rc != 0)
  508. {
  509. switch (errno)
  510. {
  511. case EINVAL:
  512. return VCOS_EINVAL;
  513. default:
  514. vcos_assert(0);
  515. return VCOS_EACCESS;
  516. }
  517. }
  518. else
  519. {
  520. return VCOS_SUCCESS;
  521. }
  522. }
  523. VCOS_THREAD_T *vcos_dummy_thread_create(void)
  524. {
  525. VCOS_STATUS_T st;
  526. VCOS_THREAD_T *thread_hndl = NULL;
  527. int rc;
  528. thread_hndl = (VCOS_THREAD_T *)vcos_malloc(sizeof(VCOS_THREAD_T), NULL);
  529. vcos_assert(thread_hndl != NULL);
  530. memset(thread_hndl, 0, sizeof(VCOS_THREAD_T));
  531. thread_hndl->dummy = 1;
  532. thread_hndl->thread = pthread_self();
  533. st = vcos_semaphore_create(&thread_hndl->suspend, NULL, 0);
  534. if (st != VCOS_SUCCESS)
  535. {
  536. vcos_free(thread_hndl);
  537. return( thread_hndl );
  538. }
  539. vcos_once(&current_thread_key_once, current_thread_key_init);
  540. rc = pthread_setspecific(_vcos_thread_current_key,
  541. thread_hndl);
  542. (void)rc;
  543. return( thread_hndl );
  544. }
  545. /***********************************************************
  546. *
  547. * Timers
  548. *
  549. ***********************************************************/
  550. /* On Linux we could use POSIX timers with a bit of synchronization.
  551. * Unfortunately POSIX timers on Bionic are NOT POSIX compliant
  552. * what makes that option not viable.
  553. * That's why we ended up with our own implementation of timers.
  554. * NOTE: That condition variables on Bionic are also buggy and
  555. * they work incorrectly with CLOCK_MONOTONIC, so we have to
  556. * use CLOCK_REALTIME (and hope that no one will change the time
  557. * significantly after the timer has been set up
  558. */
  559. #define NSEC_IN_SEC (1000*1000*1000)
  560. #define MSEC_IN_SEC (1000)
  561. #define NSEC_IN_MSEC (1000*1000)
  562. static int _timespec_is_zero(struct timespec *ts)
  563. {
  564. return ((ts->tv_sec == 0) && (ts->tv_nsec == 0));
  565. }
  566. static void _timespec_set_zero(struct timespec *ts)
  567. {
  568. ts->tv_sec = ts->tv_nsec = 0;
  569. }
  570. /* Adds left to right and stores the result in left */
  571. static void _timespec_add(struct timespec *left, struct timespec *right)
  572. {
  573. left->tv_sec += right->tv_sec;
  574. left->tv_nsec += right->tv_nsec;
  575. if (left->tv_nsec >= (NSEC_IN_SEC))
  576. {
  577. left->tv_nsec -= NSEC_IN_SEC;
  578. left->tv_sec++;
  579. }
  580. }
  581. static int _timespec_is_larger(struct timespec *left, struct timespec *right)
  582. {
  583. if (left->tv_sec != right->tv_sec)
  584. return left->tv_sec > right->tv_sec;
  585. else
  586. return left->tv_nsec > right->tv_nsec;
  587. }
  588. static void* _timer_thread(void *arg)
  589. {
  590. VCOS_TIMER_T *timer = (VCOS_TIMER_T*)arg;
  591. pthread_mutex_lock(&timer->lock);
  592. while (!timer->quit)
  593. {
  594. struct timespec now;
  595. /* Wait until next expiry time, or until timer's settings are changed */
  596. if (_timespec_is_zero(&timer->expires))
  597. pthread_cond_wait(&timer->settings_changed, &timer->lock);
  598. else
  599. pthread_cond_timedwait(&timer->settings_changed, &timer->lock, &timer->expires);
  600. /* See if the timer has expired - reloop if it didn't */
  601. clock_gettime(CLOCK_REALTIME, &now);
  602. if (_timespec_is_zero(&timer->expires) || _timespec_is_larger(&timer->expires, &now))
  603. continue;
  604. /* The timer has expired. Clear the expiry time and call the
  605. * expiration routine
  606. */
  607. _timespec_set_zero(&timer->expires);
  608. timer->orig_expiration_routine(timer->orig_context);
  609. }
  610. pthread_mutex_unlock(&timer->lock);
  611. return NULL;
  612. }
  613. VCOS_STATUS_T vcos_timer_init(void)
  614. {
  615. return VCOS_SUCCESS;
  616. }
  617. VCOS_STATUS_T vcos_timer_create(VCOS_TIMER_T *timer,
  618. const char *name,
  619. void (*expiration_routine)(void *context),
  620. void *context)
  621. {
  622. pthread_mutexattr_t lock_attr;
  623. VCOS_STATUS_T result = VCOS_SUCCESS;
  624. int settings_changed_initialized = 0;
  625. int lock_attr_initialized = 0;
  626. int lock_initialized = 0;
  627. (void)name;
  628. vcos_assert(timer);
  629. vcos_assert(expiration_routine);
  630. memset(timer, 0, sizeof(VCOS_TIMER_T));
  631. timer->orig_expiration_routine = expiration_routine;
  632. timer->orig_context = context;
  633. /* Create conditional variable for notifying the timer's thread
  634. * when settings change.
  635. */
  636. if (result == VCOS_SUCCESS)
  637. {
  638. int rc = pthread_cond_init(&timer->settings_changed, NULL);
  639. if (rc == 0)
  640. settings_changed_initialized = 1;
  641. else
  642. result = vcos_pthreads_map_error(rc);
  643. }
  644. /* Create attributes for the lock (we want it to be recursive) */
  645. if (result == VCOS_SUCCESS)
  646. {
  647. int rc = pthread_mutexattr_init(&lock_attr);
  648. if (rc == 0)
  649. {
  650. pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
  651. lock_attr_initialized = 1;
  652. }
  653. else
  654. {
  655. result = vcos_pthreads_map_error(rc);
  656. }
  657. }
  658. /* Create lock for the timer structure */
  659. if (result == VCOS_SUCCESS)
  660. {
  661. int rc = pthread_mutex_init(&timer->lock, &lock_attr);
  662. if (rc == 0)
  663. lock_initialized = 1;
  664. else
  665. result = vcos_pthreads_map_error(rc);
  666. }
  667. /* Lock attributes are no longer needed */
  668. if (lock_attr_initialized)
  669. pthread_mutexattr_destroy(&lock_attr);
  670. /* Create the underlying thread */
  671. if (result == VCOS_SUCCESS)
  672. {
  673. int rc = pthread_create(&timer->thread, NULL, _timer_thread, timer);
  674. if (rc != 0)
  675. result = vcos_pthreads_map_error(rc);
  676. }
  677. /* Clean up if anything went wrong */
  678. if (result != VCOS_SUCCESS)
  679. {
  680. if (lock_initialized)
  681. pthread_mutex_destroy(&timer->lock);
  682. if (settings_changed_initialized)
  683. pthread_cond_destroy(&timer->settings_changed);
  684. }
  685. return result;
  686. }
  687. void vcos_timer_set(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay_ms)
  688. {
  689. struct timespec now;
  690. vcos_assert(timer);
  691. /* Other implementations of this function do undefined things
  692. * when delay_ms is 0. This implementation will simply assert and return
  693. */
  694. vcos_assert(delay_ms != 0);
  695. if (delay_ms == 0)
  696. return;
  697. pthread_mutex_lock(&timer->lock);
  698. /* Calculate the new absolute expiry time */
  699. clock_gettime(CLOCK_REALTIME, &now);
  700. timer->expires.tv_sec = delay_ms / MSEC_IN_SEC;
  701. timer->expires.tv_nsec = (delay_ms % MSEC_IN_SEC) * NSEC_IN_MSEC;
  702. _timespec_add(&timer->expires, &now);
  703. /* Notify the timer's thread about the change */
  704. pthread_cond_signal(&timer->settings_changed);
  705. pthread_mutex_unlock(&timer->lock);
  706. }
  707. void vcos_timer_cancel(VCOS_TIMER_T *timer)
  708. {
  709. vcos_assert(timer);
  710. pthread_mutex_lock(&timer->lock);
  711. _timespec_set_zero(&timer->expires);
  712. pthread_cond_signal(&timer->settings_changed);
  713. pthread_mutex_unlock(&timer->lock);
  714. }
  715. void vcos_timer_reset(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay_ms)
  716. {
  717. vcos_timer_set(timer, delay_ms);
  718. }
  719. void vcos_timer_delete(VCOS_TIMER_T *timer)
  720. {
  721. vcos_assert(timer);
  722. pthread_mutex_lock(&timer->lock);
  723. /* Other implementation of this function (e.g. ThreadX)
  724. * disallow it being called from the expiration routine
  725. */
  726. vcos_assert(pthread_self() != timer->thread);
  727. /* Stop the timer and set flag telling the timer thread to quit */
  728. _timespec_set_zero(&timer->expires);
  729. timer->quit = 1;
  730. /* Notify the timer's thread about the change */
  731. pthread_cond_signal(&timer->settings_changed);
  732. /* Release the lock, so that the timer's thread can quit */
  733. pthread_mutex_unlock(&timer->lock);
  734. /* Wait for the timer thread to finish */
  735. pthread_join(timer->thread, NULL);
  736. /* Free resources used by the timer */
  737. pthread_mutex_destroy(&timer->lock);
  738. pthread_cond_destroy(&timer->settings_changed);
  739. }