X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Ftimed_thread.c;h=ee4346dcdca5a7369c947f7c9d2837fe65e5945a;hb=6b3c69882a020f2215713367a39c0de93f7ddc3c;hp=70ddaf46c55aea0b4cacb653a6e5ef85f161fc90;hpb=3d26a4880e92df2c6004d85c1be458e35c6bfc3a;p=monky diff --git a/src/timed_thread.c b/src/timed_thread.c index 70ddaf4..ee4346d 100644 --- a/src/timed_thread.c +++ b/src/timed_thread.c @@ -1,6 +1,7 @@ -/* $Id$ */ - -/* timed_thread.c: Abstraction layer for timed threads +/* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*- + * vim: ts=4 sw=4 noet ai cindent syntax=c + * + * timed_thread.c: Abstraction layer for timed threads * * Copyright (C) 2006-2007 Philip Kovacs pkovacs@users.sourceforge.net * @@ -17,7 +18,9 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 - * USA. */ + * USA. + * + */ #ifdef HAVE_CONFIG_H #include @@ -26,9 +29,8 @@ #include #include #include -#include -#include #include +#include #ifndef HAVE_CLOCK_GETTIME #include #endif @@ -48,6 +50,9 @@ struct _timed_thread { void *(*start_routine)(void *); /* thread function to run */ void *arg; /* thread function argument */ struct timespec interval_time; /* interval_usecs as a struct timespec */ + struct timespec wait_time; /* absolute future time next timed_thread_test will wait until */ + int pipefd[2]; + int die; }; /* linked list of created threads */ @@ -60,8 +65,17 @@ typedef struct _timed_thread_list { static timed_thread_list *p_timed_thread_list_head = NULL; static timed_thread_list *p_timed_thread_list_tail = NULL; +int timed_thread_readfd(timed_thread *p_timed_thread) +{ + return p_timed_thread->pipefd[0]; +} + static int now(struct timespec *abstime) { +#ifndef HAVE_CLOCK_GETTIME + struct timeval tv; +#endif + if (!abstime) { return -1; } @@ -70,8 +84,6 @@ static int now(struct timespec *abstime) return clock_gettime(CLOCK_REALTIME, abstime); #else /* fallback to gettimeofday () */ - struct timeval tv; - if (gettimeofday(&tv, NULL) != 0) { return -1; } @@ -95,10 +107,15 @@ timed_thread *timed_thread_create(void *start_routine(void *), void *arg, return NULL; } + /* create thread pipe (used to tell threads to die) */ + if (pipe(p_timed_thread->pipefd)) { + return NULL; + } + /* init attributes, e.g. joinable thread */ pthread_attr_init(&p_timed_thread->thread_attr); pthread_attr_setdetachstate(&p_timed_thread->thread_attr, - PTHREAD_CREATE_JOINABLE); + PTHREAD_CREATE_JOINABLE); /* init mutexes */ pthread_mutex_init(&p_timed_thread->cs_mutex, NULL); pthread_mutex_init(&p_timed_thread->runnable_mutex, NULL); @@ -108,6 +125,11 @@ timed_thread *timed_thread_create(void *start_routine(void *), void *arg, p_timed_thread->start_routine = start_routine; p_timed_thread->arg = arg; + /* set wait time to current time */ + if (now(&p_timed_thread->wait_time)) { + return NULL; + } + /* seconds portion of the microseconds interval */ p_timed_thread->interval_time.tv_sec = (time_t) (interval_usecs / 1000000); /* remaining microseconds convert to nanoseconds */ @@ -115,8 +137,8 @@ timed_thread *timed_thread_create(void *start_routine(void *), void *arg, (long) ((interval_usecs % 1000000) * 1000); /* printf("interval_time.tv_sec = %li, .tv_nsec = %li\n", - p_timed_thread->interval_time.tv_sec, - p_timed_thread->interval_time.tv_nsec); */ + p_timed_thread->interval_time.tv_sec, + p_timed_thread->interval_time.tv_nsec); */ return p_timed_thread; } @@ -124,7 +146,7 @@ timed_thread *timed_thread_create(void *start_routine(void *), void *arg, int timed_thread_run(timed_thread *p_timed_thread) { return pthread_create(&p_timed_thread->thread, &p_timed_thread->thread_attr, - p_timed_thread->start_routine, p_timed_thread->arg); + p_timed_thread->start_routine, p_timed_thread->arg); } /* destroy a timed thread. @@ -135,12 +157,14 @@ void timed_thread_destroy(timed_thread *p_timed_thread, { assert(p_timed_thread != NULL); assert((addr_of_p_timed_thread == NULL) - || (*addr_of_p_timed_thread == p_timed_thread)); + || (*addr_of_p_timed_thread == p_timed_thread)); /* signal thread to stop */ pthread_mutex_lock(&p_timed_thread->runnable_mutex); pthread_cond_signal(&p_timed_thread->runnable_cond); + p_timed_thread->die = 1; pthread_mutex_unlock(&p_timed_thread->runnable_mutex); + write(p_timed_thread->pipefd[1], "die", 3); /* join the terminating thread */ if (p_timed_thread->thread) { @@ -178,35 +202,13 @@ int timed_thread_unlock(timed_thread *p_timed_thread) /* thread waits interval_usecs for runnable_cond to be signaled. * returns 1 if signaled, -1 on error, and 0 otherwise. * caller should call timed_thread_exit() on any non-zero return value. */ -int timed_thread_test(timed_thread *p_timed_thread) +int timed_thread_test(timed_thread *p_timed_thread, int override_wait_time) { - struct timespec wait_time; + struct timespec now_time; int rc; assert(p_timed_thread != NULL); - if (now(&wait_time)) { - return -1; - } - /* printf("PRE:wait_time.tv_secs = %li, .tv_nsecs = %li\n", - wait_time.tv_sec, wait_time.tv_nsec); */ - - /* add in the wait interval */ - if (1000000000 - wait_time.tv_nsec - <= p_timed_thread->interval_time.tv_nsec) { - /* perform nsec->sec carry operation */ - wait_time.tv_sec += p_timed_thread->interval_time.tv_sec + 1; - wait_time.tv_nsec -= 1000000000 - p_timed_thread->interval_time.tv_nsec; - /* printf("001:wait_time.tv_secs = %li, .tv_nsecs = %li\n", - wait_time.tv_sec, wait_time.tv_nsec); */ - } else { - /* no carry needed, just add respective components */ - wait_time.tv_sec += p_timed_thread->interval_time.tv_sec; - wait_time.tv_nsec += p_timed_thread->interval_time.tv_nsec; - /* printf("002:wait_time.tv_secs = %li, .tv_nsecs = %li\n", - wait_time.tv_sec, wait_time.tv_nsec); */ - } - /* acquire runnable_cond mutex */ if (pthread_mutex_lock(&p_timed_thread->runnable_mutex)) { /* could not acquire runnable_cond mutex, @@ -214,17 +216,44 @@ int timed_thread_test(timed_thread *p_timed_thread) return -1; } + if (p_timed_thread->die) { + /* if we were kindly asked to die, then die */ + return 1; + } + + if (override_wait_time && now(&p_timed_thread->wait_time)) { + return -1; + } + /* release mutex and wait until future time for runnable_cond to signal */ rc = pthread_cond_timedwait(&p_timed_thread->runnable_cond, - &p_timed_thread->runnable_mutex, &wait_time); + &p_timed_thread->runnable_mutex, &p_timed_thread->wait_time); /* mutex re-acquired, so release it */ pthread_mutex_unlock(&p_timed_thread->runnable_mutex); + + if (now(&now_time)) { + return -1; + } if (rc == 0) { /* runnable_cond was signaled, so tell caller to exit thread */ return 1; } + /* absolute future time for next pass */ + p_timed_thread->wait_time.tv_sec += p_timed_thread->interval_time.tv_sec; + p_timed_thread->wait_time.tv_nsec += p_timed_thread->interval_time.tv_nsec; + p_timed_thread->wait_time.tv_sec += p_timed_thread->wait_time.tv_nsec / 1000000000; + p_timed_thread->wait_time.tv_nsec = p_timed_thread->wait_time.tv_nsec % 1000000000; + + /* ensure our future wait time is sane */ + if (p_timed_thread->wait_time.tv_sec > (now_time.tv_sec + p_timed_thread->interval_time.tv_sec) || p_timed_thread->wait_time.tv_sec < now_time.tv_sec) { + p_timed_thread->wait_time.tv_sec = now_time.tv_sec + p_timed_thread->interval_time.tv_sec; + p_timed_thread->wait_time.tv_nsec = now_time.tv_nsec + p_timed_thread->interval_time.tv_nsec; + p_timed_thread->wait_time.tv_sec += p_timed_thread->wait_time.tv_nsec / 1000000000; + p_timed_thread->wait_time.tv_nsec = p_timed_thread->wait_time.tv_nsec % 1000000000; + } + /* tell caller not to exit yet */ return 0; } @@ -234,6 +263,9 @@ void timed_thread_exit(timed_thread *p_timed_thread) { assert(p_timed_thread != NULL); + close(p_timed_thread->pipefd[0]); + close(p_timed_thread->pipefd[1]); + pthread_exit(NULL); } @@ -245,7 +277,7 @@ int timed_thread_register(timed_thread *p_timed_thread, timed_thread_node *p_node; assert((addr_of_p_timed_thread == NULL) - || (*addr_of_p_timed_thread == p_timed_thread)); + || (*addr_of_p_timed_thread == p_timed_thread)); if ((p_node = calloc(sizeof(timed_thread_node), 1)) == 0) { return 0; @@ -276,7 +308,7 @@ void timed_thread_destroy_registered_threads(void) for (p_node = p_timed_thread_list_head; p_node; p_node = p_next) { p_next = p_node->next; timed_thread_destroy(p_node->p_timed_thread, - p_node->addr_of_p_timed_thread); + p_node->addr_of_p_timed_thread); free(p_node); p_node = NULL; }