|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902 |
- /*
- Copyright (c) 2012, Broadcom Europe Ltd
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * Neither the name of the copyright holder nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
- /*#define VCOS_INLINE_BODIES */
- #include "interface/vcos/vcos.h"
- #include "interface/vcos/vcos_msgqueue.h"
- #include <string.h>
- #include <stdarg.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <sys/time.h>
- #include <linux/param.h>
-
- /* Cygwin doesn't always have prctl.h and it doesn't have PR_SET_NAME */
- #if defined( __linux__ )
- # if !defined(HAVE_PRCTL)
- # define HAVE_PRCTL
- # endif
- #include <sys/prctl.h>
- #endif
-
- #ifdef HAVE_CMAKE_CONFIG
- #include "cmake_config.h"
- #endif
-
- #ifdef HAVE_MTRACE
- #include <mcheck.h>
- #endif
-
- #if defined(ANDROID)
- #include <android/log.h>
- #endif
-
- #ifndef VCOS_DEFAULT_STACK_SIZE
- #define VCOS_DEFAULT_STACK_SIZE 4096
- #endif
-
- static int vcos_argc;
- static const char **vcos_argv;
-
- typedef void (*LEGACY_ENTRY_FN_T)(int, void *);
-
- static VCOS_THREAD_ATTR_T default_attrs = {
- .ta_stacksz = VCOS_DEFAULT_STACK_SIZE,
- };
-
- /** Singleton global lock used for vcos_global_lock/unlock(). */
- static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
-
- #ifdef ANDROID
- static VCOS_MUTEX_T printf_lock;
- #endif
-
- /* Create a per-thread key for faking up vcos access
- * on non-vcos threads.
- */
- pthread_key_t _vcos_thread_current_key;
-
- static VCOS_UNSIGNED _vcos_thread_current_key_created = 0;
- static VCOS_ONCE_T current_thread_key_once; /* init just once */
-
- static void vcos_thread_cleanup(VCOS_THREAD_T *thread)
- {
- vcos_semaphore_delete(&thread->suspend);
- if (thread->task_timer_created)
- {
- vcos_timer_delete(&thread->task_timer);
- }
- }
-
- static void vcos_dummy_thread_cleanup(void *cxt)
- {
- VCOS_THREAD_T *thread = cxt;
- if (thread->dummy)
- {
- int i;
- /* call termination functions */
- for (i=0; thread->at_exit[i].pfn != NULL; i++)
- {
- thread->at_exit[i].pfn(thread->at_exit[i].cxt);
- }
- vcos_thread_cleanup(thread);
- vcos_free(thread);
- }
- }
-
- static void current_thread_key_init(void)
- {
- vcos_assert(!_vcos_thread_current_key_created);
- pthread_key_create (&_vcos_thread_current_key, vcos_dummy_thread_cleanup);
- _vcos_thread_current_key_created = 1;
- }
-
-
- /* A VCOS wrapper for the thread which called vcos_init. */
- static VCOS_THREAD_T vcos_thread_main;
-
- static void *vcos_thread_entry(void *arg)
- {
- int i;
- void *ret;
- VCOS_THREAD_T *thread = (VCOS_THREAD_T *)arg;
-
- vcos_assert(thread != NULL);
- thread->dummy = 0;
-
- pthread_setspecific(_vcos_thread_current_key, thread);
- #if defined( HAVE_PRCTL ) && defined( PR_SET_NAME )
- /* cygwin doesn't have PR_SET_NAME */
- prctl( PR_SET_NAME, (unsigned long)thread->name, 0, 0, 0 );
- #endif
- if (thread->legacy)
- {
- LEGACY_ENTRY_FN_T fn = (LEGACY_ENTRY_FN_T)thread->entry;
- (*fn)(0, thread->arg);
- ret = 0;
- }
- else
- {
- ret = (*thread->entry)(thread->arg);
- }
-
- /* call termination functions */
- for (i=0; thread->at_exit[i].pfn != NULL; i++)
- {
- thread->at_exit[i].pfn(thread->at_exit[i].cxt);
- }
-
- return ret;
- }
-
- static void _task_timer_expiration_routine(void *cxt)
- {
- VCOS_THREAD_T *thread = (VCOS_THREAD_T *)cxt;
-
- vcos_assert(thread->orig_task_timer_expiration_routine);
- thread->orig_task_timer_expiration_routine(thread->orig_task_timer_context);
- thread->orig_task_timer_expiration_routine = NULL;
- }
-
- VCOS_STATUS_T vcos_thread_create(VCOS_THREAD_T *thread,
- const char *name,
- VCOS_THREAD_ATTR_T *attrs,
- VCOS_THREAD_ENTRY_FN_T entry,
- void *arg)
- {
- VCOS_STATUS_T st;
- pthread_attr_t pt_attrs;
- VCOS_THREAD_ATTR_T *local_attrs = attrs ? attrs : &default_attrs;
- int rc;
-
- vcos_assert(thread);
- memset(thread, 0, sizeof(VCOS_THREAD_T));
-
- rc = pthread_attr_init(&pt_attrs);
- if (rc < 0)
- return VCOS_ENOMEM;
-
- st = vcos_semaphore_create(&thread->suspend, NULL, 0);
- if (st != VCOS_SUCCESS)
- {
- pthread_attr_destroy(&pt_attrs);
- return st;
- }
-
- pthread_attr_setstacksize(&pt_attrs, local_attrs->ta_stacksz);
- #if VCOS_CAN_SET_STACK_ADDR
- if (local_attrs->ta_stackaddr)
- {
- pthread_attr_setstackaddr(&pt_attrs, local_attrs->ta_stackaddr);
- }
- #else
- vcos_demand(local_attrs->ta_stackaddr == 0);
- #endif
-
- /* pthread_attr_setpriority(&pt_attrs, local_attrs->ta_priority); */
-
- vcos_assert(local_attrs->ta_stackaddr == 0); /* Not possible */
-
- thread->entry = entry;
- thread->arg = arg;
- thread->legacy = local_attrs->legacy;
-
- strncpy(thread->name, name, sizeof(thread->name));
- thread->name[sizeof(thread->name)-1] = '\0';
- memset(thread->at_exit, 0, sizeof(thread->at_exit));
-
- rc = pthread_create(&thread->thread, &pt_attrs, vcos_thread_entry, thread);
-
- pthread_attr_destroy(&pt_attrs);
-
- if (rc < 0)
- {
- vcos_semaphore_delete(&thread->suspend);
- return VCOS_ENOMEM;
- }
- else
- {
- return VCOS_SUCCESS;
- }
- }
-
- void vcos_thread_join(VCOS_THREAD_T *thread,
- void **pData)
- {
- pthread_join(thread->thread, pData);
- vcos_thread_cleanup(thread);
- }
-
- VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_thread_create_classic(VCOS_THREAD_T *thread,
- const char *name,
- void *(*entry)(void *arg),
- void *arg,
- void *stack,
- VCOS_UNSIGNED stacksz,
- VCOS_UNSIGNED priaff,
- VCOS_UNSIGNED timeslice,
- VCOS_UNSIGNED autostart)
- {
- VCOS_THREAD_ATTR_T attrs;
- vcos_thread_attr_init(&attrs);
- vcos_thread_attr_setstacksize(&attrs, stacksz);
- vcos_thread_attr_setpriority(&attrs, priaff & ~_VCOS_AFFINITY_MASK);
- vcos_thread_attr_setaffinity(&attrs, priaff & _VCOS_AFFINITY_MASK);
- (void)timeslice;
- (void)autostart;
-
- if (VCOS_CAN_SET_STACK_ADDR)
- {
- vcos_thread_attr_setstack(&attrs, stack, stacksz);
- }
-
- return vcos_thread_create(thread, name, &attrs, entry, arg);
- }
-
- uint64_t vcos_getmicrosecs64_internal(void)
- {
- struct timeval tv;
- uint64_t tm = 0;
-
- if (!gettimeofday(&tv, NULL))
- {
- tm = (tv.tv_sec * 1000000LL) + tv.tv_usec;
- }
-
- return tm;
- }
-
- #ifdef ANDROID
-
- static int log_prio[] =
- {
- ANDROID_LOG_INFO, /* VCOS_LOG_UNINITIALIZED */
- ANDROID_LOG_INFO, /* VCOS_LOG_NEVER */
- ANDROID_LOG_ERROR, /* VCOS_LOG_ERROR */
- ANDROID_LOG_WARN, /* VCOS_LOG_WARN */
- ANDROID_LOG_INFO, /* VCOS_LOG_INFO */
- ANDROID_LOG_DEBUG /* VCOS_LOG_TRACE */
- };
-
- int vcos_use_android_log = 1;
- int vcos_log_to_file = 0;
- #else
- int vcos_use_android_log = 0;
- int vcos_log_to_file = 0;
- #endif
-
- static FILE * log_fhandle = NULL;
-
- void vcos_vlog_default_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args)
- {
- (void)_level;
-
- #ifdef ANDROID
- if ( vcos_use_android_log )
- {
- __android_log_vprint(log_prio[_level], cat->name, fmt, args);
- }
- else
- {
- vcos_mutex_lock(&printf_lock);
- #endif
- if(NULL != log_fhandle)
- {
- if (cat->flags.want_prefix)
- fprintf( log_fhandle, "%s: ", cat->name );
- vfprintf(log_fhandle, fmt, args);
- fputs("\n", log_fhandle);
- fflush(log_fhandle);
- }
- #ifdef ANDROID
- vcos_mutex_unlock(&printf_lock);
- }
- #endif
- }
-
- void _vcos_log_platform_init(void)
- {
- if(vcos_log_to_file)
- {
- char log_fname[100];
- #ifdef ANDROID
- snprintf(log_fname, 100, "/data/log/vcos_log%u.txt", vcos_process_id_current());
- #else
- snprintf(log_fname, 100, "/var/log/vcos_log%u.txt", vcos_process_id_current());
- #endif
- log_fhandle = fopen(log_fname, "w");
- }
- else
- log_fhandle = stderr;
- }
-
- /* Flags for init/deinit components */
- enum
- {
- VCOS_INIT_NAMED_SEM = (1 << 0),
- VCOS_INIT_PRINTF_LOCK = (1 << 1),
- VCOS_INIT_MAIN_SEM = (1 << 2),
- VCOS_INIT_MSGQ = (1 << 3),
- VCOS_INIT_ALL = 0xffffffff
- };
-
- static void vcos_term(uint32_t flags)
- {
- if (flags & VCOS_INIT_MSGQ)
- vcos_msgq_deinit();
-
- if (flags & VCOS_INIT_MAIN_SEM)
- vcos_semaphore_delete(&vcos_thread_main.suspend);
-
- #ifdef ANDROID
- if (flags & VCOS_INIT_PRINTF_LOCK)
- vcos_mutex_delete(&printf_lock);
- #endif
-
- if (flags & VCOS_INIT_NAMED_SEM)
- _vcos_named_semaphore_deinit();
- }
-
- VCOS_STATUS_T vcos_platform_init(void)
- {
- VCOS_STATUS_T st;
- uint32_t flags = 0;
- int pst;
-
- st = _vcos_named_semaphore_init();
- if (!vcos_verify(st == VCOS_SUCCESS))
- goto end;
-
- flags |= VCOS_INIT_NAMED_SEM;
-
- #ifdef HAVE_MTRACE
- /* enable glibc memory debugging, if the environment
- * variable MALLOC_TRACE names a valid file.
- */
- mtrace();
- #endif
-
- #ifdef ANDROID
- st = vcos_mutex_create(&printf_lock, "printf");
- if (!vcos_verify(st == VCOS_SUCCESS))
- goto end;
-
- flags |= VCOS_INIT_PRINTF_LOCK;
- #endif
-
- st = vcos_once(¤t_thread_key_once, current_thread_key_init);
- if (!vcos_verify(st == VCOS_SUCCESS))
- goto end;
-
- /* Initialise a VCOS wrapper for the thread which called vcos_init. */
- st = vcos_semaphore_create(&vcos_thread_main.suspend, NULL, 0);
- if (!vcos_verify(st == VCOS_SUCCESS))
- goto end;
-
- flags |= VCOS_INIT_MAIN_SEM;
-
- vcos_thread_main.thread = pthread_self();
-
- pst = pthread_setspecific(_vcos_thread_current_key, &vcos_thread_main);
- if (!vcos_verify(pst == 0))
- {
- st = VCOS_EINVAL;
- goto end;
- }
-
- st = vcos_msgq_init();
- if (!vcos_verify(st == VCOS_SUCCESS))
- goto end;
-
- flags |= VCOS_INIT_MSGQ;
-
- vcos_logging_init();
-
- end:
- if (st != VCOS_SUCCESS)
- vcos_term(flags);
-
- return st;
- }
-
- void vcos_platform_deinit(void)
- {
- vcos_term(VCOS_INIT_ALL);
- }
-
- void vcos_global_lock(void)
- {
- pthread_mutex_lock(&lock);
- }
-
- void vcos_global_unlock(void)
- {
- pthread_mutex_unlock(&lock);
- }
-
- void vcos_thread_exit(void *arg)
- {
- VCOS_THREAD_T *thread = vcos_thread_current();
-
- if ( thread && thread->dummy )
- {
- vcos_free ( (void*) thread );
- thread = NULL;
- }
-
- pthread_exit(arg);
- }
-
-
- void vcos_thread_attr_init(VCOS_THREAD_ATTR_T *attrs)
- {
- *attrs = default_attrs;
- }
-
- VCOS_STATUS_T vcos_pthreads_map_error(int error)
- {
- switch (error)
- {
- case ENOMEM:
- return VCOS_ENOMEM;
- case ENXIO:
- return VCOS_ENXIO;
- case EAGAIN:
- return VCOS_EAGAIN;
- case ENOSPC:
- return VCOS_ENOSPC;
- default:
- return VCOS_EINVAL;
- }
- }
-
- VCOS_STATUS_T vcos_pthreads_map_errno(void)
- {
- return vcos_pthreads_map_error(errno);
- }
-
- void _vcos_task_timer_set(void (*pfn)(void*), void *cxt, VCOS_UNSIGNED ms)
- {
- VCOS_THREAD_T *thread = vcos_thread_current();
-
- if (thread == NULL)
- return;
-
- vcos_assert(thread->orig_task_timer_expiration_routine == NULL);
-
- if (!thread->task_timer_created)
- {
- VCOS_STATUS_T st = vcos_timer_create(&thread->task_timer, NULL,
- _task_timer_expiration_routine, thread);
- (void)st;
- vcos_assert(st == VCOS_SUCCESS);
- thread->task_timer_created = 1;
- }
-
- thread->orig_task_timer_expiration_routine = pfn;
- thread->orig_task_timer_context = cxt;
-
- vcos_timer_set(&thread->task_timer, ms);
- }
-
- void _vcos_task_timer_cancel(void)
- {
- VCOS_THREAD_T *thread = vcos_thread_current();
-
- if (thread == NULL || !thread->task_timer_created)
- return;
-
- vcos_timer_cancel(&thread->task_timer);
- thread->orig_task_timer_expiration_routine = NULL;
- }
-
- int vcos_vsnprintf( char *buf, size_t buflen, const char *fmt, va_list ap )
- {
- return vsnprintf( buf, buflen, fmt, ap );
- }
-
- int vcos_snprintf(char *buf, size_t buflen, const char *fmt, ...)
- {
- int ret;
- va_list ap;
- va_start(ap,fmt);
- ret = vsnprintf(buf, buflen, fmt, ap);
- va_end(ap);
- return ret;
- }
-
- int vcos_have_rtos(void)
- {
- return 1;
- }
-
- const char * vcos_thread_get_name(const VCOS_THREAD_T *thread)
- {
- return thread->name;
- }
-
- #ifdef VCOS_HAVE_BACKTRACK
- void __attribute__((weak)) vcos_backtrace_self(void);
- #endif
-
- void vcos_pthreads_logging_assert(const char *file, const char *func, unsigned int line, const char *fmt, ...)
- {
- va_list ap;
- va_start(ap, fmt);
- fprintf(stderr, "assertion failure:%s:%d:%s():",
- file, line, func);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- fprintf(stderr, "\n");
-
- #ifdef VCOS_HAVE_BACKTRACK
- if (vcos_backtrace_self)
- vcos_backtrace_self();
- #endif
- abort();
- }
-
- extern VCOS_STATUS_T vcos_thread_at_exit(void (*pfn)(void*), void *cxt)
- {
- int i;
- VCOS_THREAD_T *self = vcos_thread_current();
- if (!self)
- {
- vcos_assert(0);
- return VCOS_EINVAL;
- }
- for (i=0; i<VCOS_MAX_EXIT_HANDLERS; i++)
- {
- if (self->at_exit[i].pfn == NULL)
- {
- self->at_exit[i].pfn = pfn;
- self->at_exit[i].cxt = cxt;
- return VCOS_SUCCESS;
- }
- }
- return VCOS_ENOSPC;
- }
-
- void vcos_set_args(int argc, const char **argv)
- {
- vcos_argc = argc;
- vcos_argv = argv;
- }
-
- int vcos_get_argc(void)
- {
- return vcos_argc;
- }
-
- const char ** vcos_get_argv(void)
- {
- return vcos_argv;
- }
-
- /* we can't inline this, because HZ comes from sys/param.h which
- * dumps all sorts of junk into the global namespace, notable MIN and
- * MAX.
- */
- uint32_t _vcos_get_ticks_per_second(void)
- {
- return HZ;
- }
-
- VCOS_STATUS_T vcos_once(VCOS_ONCE_T *once_control,
- void (*init_routine)(void))
- {
- int rc = pthread_once(once_control, init_routine);
- if (rc != 0)
- {
- switch (errno)
- {
- case EINVAL:
- return VCOS_EINVAL;
- default:
- vcos_assert(0);
- return VCOS_EACCESS;
- }
- }
- else
- {
- return VCOS_SUCCESS;
- }
- }
-
-
- VCOS_THREAD_T *vcos_dummy_thread_create(void)
- {
- VCOS_STATUS_T st;
- VCOS_THREAD_T *thread_hndl = NULL;
- int rc;
-
- thread_hndl = (VCOS_THREAD_T *)vcos_malloc(sizeof(VCOS_THREAD_T), NULL);
- vcos_assert(thread_hndl != NULL);
-
- memset(thread_hndl, 0, sizeof(VCOS_THREAD_T));
-
- thread_hndl->dummy = 1;
- thread_hndl->thread = pthread_self();
-
- st = vcos_semaphore_create(&thread_hndl->suspend, NULL, 0);
- if (st != VCOS_SUCCESS)
- {
- vcos_free(thread_hndl);
- return( thread_hndl );
- }
-
- vcos_once(¤t_thread_key_once, current_thread_key_init);
-
- rc = pthread_setspecific(_vcos_thread_current_key,
- thread_hndl);
- (void)rc;
-
- return( thread_hndl );
- }
-
-
- /***********************************************************
- *
- * Timers
- *
- ***********************************************************/
-
- /* On Linux we could use POSIX timers with a bit of synchronization.
- * Unfortunately POSIX timers on Bionic are NOT POSIX compliant
- * what makes that option not viable.
- * That's why we ended up with our own implementation of timers.
- * NOTE: That condition variables on Bionic are also buggy and
- * they work incorrectly with CLOCK_MONOTONIC, so we have to
- * use CLOCK_REALTIME (and hope that no one will change the time
- * significantly after the timer has been set up
- */
- #define NSEC_IN_SEC (1000*1000*1000)
- #define MSEC_IN_SEC (1000)
- #define NSEC_IN_MSEC (1000*1000)
-
- static int _timespec_is_zero(struct timespec *ts)
- {
- return ((ts->tv_sec == 0) && (ts->tv_nsec == 0));
- }
-
- static void _timespec_set_zero(struct timespec *ts)
- {
- ts->tv_sec = ts->tv_nsec = 0;
- }
-
- /* Adds left to right and stores the result in left */
- static void _timespec_add(struct timespec *left, struct timespec *right)
- {
- left->tv_sec += right->tv_sec;
- left->tv_nsec += right->tv_nsec;
- if (left->tv_nsec >= (NSEC_IN_SEC))
- {
- left->tv_nsec -= NSEC_IN_SEC;
- left->tv_sec++;
- }
- }
-
- static int _timespec_is_larger(struct timespec *left, struct timespec *right)
- {
- if (left->tv_sec != right->tv_sec)
- return left->tv_sec > right->tv_sec;
- else
- return left->tv_nsec > right->tv_nsec;
- }
-
- static void* _timer_thread(void *arg)
- {
- VCOS_TIMER_T *timer = (VCOS_TIMER_T*)arg;
-
- pthread_mutex_lock(&timer->lock);
- while (!timer->quit)
- {
- struct timespec now;
-
- /* Wait until next expiry time, or until timer's settings are changed */
- if (_timespec_is_zero(&timer->expires))
- pthread_cond_wait(&timer->settings_changed, &timer->lock);
- else
- pthread_cond_timedwait(&timer->settings_changed, &timer->lock, &timer->expires);
-
- /* See if the timer has expired - reloop if it didn't */
- clock_gettime(CLOCK_REALTIME, &now);
- if (_timespec_is_zero(&timer->expires) || _timespec_is_larger(&timer->expires, &now))
- continue;
-
- /* The timer has expired. Clear the expiry time and call the
- * expiration routine
- */
- _timespec_set_zero(&timer->expires);
- timer->orig_expiration_routine(timer->orig_context);
- }
- pthread_mutex_unlock(&timer->lock);
-
- return NULL;
- }
-
- VCOS_STATUS_T vcos_timer_init(void)
- {
- return VCOS_SUCCESS;
- }
-
- VCOS_STATUS_T vcos_timer_create(VCOS_TIMER_T *timer,
- const char *name,
- void (*expiration_routine)(void *context),
- void *context)
- {
- pthread_mutexattr_t lock_attr;
- VCOS_STATUS_T result = VCOS_SUCCESS;
- int settings_changed_initialized = 0;
- int lock_attr_initialized = 0;
- int lock_initialized = 0;
-
- (void)name;
-
- vcos_assert(timer);
- vcos_assert(expiration_routine);
-
- memset(timer, 0, sizeof(VCOS_TIMER_T));
-
- timer->orig_expiration_routine = expiration_routine;
- timer->orig_context = context;
-
- /* Create conditional variable for notifying the timer's thread
- * when settings change.
- */
- if (result == VCOS_SUCCESS)
- {
- int rc = pthread_cond_init(&timer->settings_changed, NULL);
- if (rc == 0)
- settings_changed_initialized = 1;
- else
- result = vcos_pthreads_map_error(rc);
- }
-
- /* Create attributes for the lock (we want it to be recursive) */
- if (result == VCOS_SUCCESS)
- {
- int rc = pthread_mutexattr_init(&lock_attr);
- if (rc == 0)
- {
- pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
- lock_attr_initialized = 1;
- }
- else
- {
- result = vcos_pthreads_map_error(rc);
- }
- }
-
- /* Create lock for the timer structure */
- if (result == VCOS_SUCCESS)
- {
- int rc = pthread_mutex_init(&timer->lock, &lock_attr);
- if (rc == 0)
- lock_initialized = 1;
- else
- result = vcos_pthreads_map_error(rc);
- }
-
- /* Lock attributes are no longer needed */
- if (lock_attr_initialized)
- pthread_mutexattr_destroy(&lock_attr);
-
- /* Create the underlying thread */
- if (result == VCOS_SUCCESS)
- {
- int rc = pthread_create(&timer->thread, NULL, _timer_thread, timer);
- if (rc != 0)
- result = vcos_pthreads_map_error(rc);
- }
-
- /* Clean up if anything went wrong */
- if (result != VCOS_SUCCESS)
- {
- if (lock_initialized)
- pthread_mutex_destroy(&timer->lock);
-
- if (settings_changed_initialized)
- pthread_cond_destroy(&timer->settings_changed);
- }
-
- return result;
- }
-
- void vcos_timer_set(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay_ms)
- {
- struct timespec now;
-
- vcos_assert(timer);
-
- /* Other implementations of this function do undefined things
- * when delay_ms is 0. This implementation will simply assert and return
- */
- vcos_assert(delay_ms != 0);
- if (delay_ms == 0)
- return;
-
- pthread_mutex_lock(&timer->lock);
-
- /* Calculate the new absolute expiry time */
- clock_gettime(CLOCK_REALTIME, &now);
- timer->expires.tv_sec = delay_ms / MSEC_IN_SEC;
- timer->expires.tv_nsec = (delay_ms % MSEC_IN_SEC) * NSEC_IN_MSEC;
- _timespec_add(&timer->expires, &now);
-
- /* Notify the timer's thread about the change */
- pthread_cond_signal(&timer->settings_changed);
-
- pthread_mutex_unlock(&timer->lock);
- }
-
- void vcos_timer_cancel(VCOS_TIMER_T *timer)
- {
- vcos_assert(timer);
-
- pthread_mutex_lock(&timer->lock);
-
- _timespec_set_zero(&timer->expires);
- pthread_cond_signal(&timer->settings_changed);
-
- pthread_mutex_unlock(&timer->lock);
- }
-
- void vcos_timer_reset(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay_ms)
- {
- vcos_timer_set(timer, delay_ms);
- }
-
- void vcos_timer_delete(VCOS_TIMER_T *timer)
- {
- vcos_assert(timer);
-
- pthread_mutex_lock(&timer->lock);
-
- /* Other implementation of this function (e.g. ThreadX)
- * disallow it being called from the expiration routine
- */
- vcos_assert(pthread_self() != timer->thread);
-
- /* Stop the timer and set flag telling the timer thread to quit */
- _timespec_set_zero(&timer->expires);
- timer->quit = 1;
-
- /* Notify the timer's thread about the change */
- pthread_cond_signal(&timer->settings_changed);
-
- /* Release the lock, so that the timer's thread can quit */
- pthread_mutex_unlock(&timer->lock);
-
- /* Wait for the timer thread to finish */
- pthread_join(timer->thread, NULL);
-
- /* Free resources used by the timer */
- pthread_mutex_destroy(&timer->lock);
- pthread_cond_destroy(&timer->settings_changed);
- }
-
|