new timed thread abstraction layer
authorPhilip Kovacs <pkovacs@users.sourceforge.net>
Tue, 14 Nov 2006 22:30:31 +0000 (22:30 +0000)
committerPhilip Kovacs <pkovacs@users.sourceforge.net>
Tue, 14 Nov 2006 22:30:31 +0000 (22:30 +0000)
git-svn-id: https://conky.svn.sourceforge.net/svnroot/conky/trunk/conky1@770 7f574dfc-610e-0410-a909-a81674777703

ChangeLog
configure.ac
src/Makefile.am
src/timed_thread.c [new file with mode: 0644]
src/timed_thread.h [new file with mode: 0644]

index cbd0024..3cbd71f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,7 @@
 
 2006-11-14
        * Fix compile error with --disable-x11.
+       * Add new timed thread abstraction file.
 
 2006-11-13
        * Use pthread_cond_timedwait() instead of sleep() in audacious
index 281166b..59d0e16 100644 (file)
@@ -1,6 +1,6 @@
-AC_INIT([Conky],[1.4.4],[brenden1@users.sourceforge.net])
+AC_INIT([Conky],[1.4.5],[brenden1@users.sourceforge.net])
 
-AM_INIT_AUTOMAKE(conky, 1.4.4)
+AM_INIT_AUTOMAKE(conky, 1.4.5)
 AM_CONFIG_HEADER(src/config.h)
 dnl
 dnl C Compiler
@@ -362,17 +362,23 @@ if test x$WANT_OSSLIB = xyes; then
 fi
 
 dnl
-dnl Some random headers
+dnl Some headers
 dnl
 
-
-AC_CHECK_HEADERS([signal.h unistd.h sys/utsname.h sys/stat.h linux/soundcard.h dirent.h mcheck.h])
-AC_CHECK_HEADERS([sys/statfs.h sys/param.h])
+AC_CHECK_HEADERS([signal.h unistd.h sys/utsname.h sys/stat.h linux/soundcard.h dirent.h mcheck.h \
+                 sys/statfs.h sys/param.h pthread.h assert.h errno.h time.h])
 AC_CHECK_HEADERS([sys/mount.h], [], [],
                 [#ifdef HAVE_SYS_PARAM_H
                  #include <sys/param.h>
                  #endif
-])
+                 ])
+dnl
+dnl Some functions
+dnl
+
+AC_CHECK_FUNCS([calloc malloc free popen])
+AC_SEARCH_LIBS(clock_gettime, [rt], [], AC_MSG_ERROR([clock_gettime() not found]))
+
 
 dnl
 dnl Check doc stuff
@@ -446,11 +452,6 @@ AC_TRY_COMPILE(
    AC_DEFINE(HAVE_GETLOADAVG, 1, [Define if you have getloadavg])],
   [AC_MSG_RESULT(no)])
 
-dnl
-dnl Check popen
-dnl
-
-AC_CHECK_FUNCS(popen)
 
 dnl
 dnl Da.
index 8e5585e..05ee561 100644 (file)
@@ -66,6 +66,8 @@ conky_SOURCES =               \
        remotec.h               \
        remoted.c               \
        remoted.h               \
+       timed_thread.c          \
+       timed_thread.h          \
        $(x11)                  \
        $(xmms2) 
 
diff --git a/src/timed_thread.c b/src/timed_thread.c
new file mode 100644 (file)
index 0000000..091473f
--- /dev/null
@@ -0,0 +1,217 @@
+/* $Id $ */
+
+/* timed_thread.c
+ * Author: Philip Kovacs
+ *
+ * Abstraction layer for timed threads
+ * */
+
+#include <pthread.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include "timed_thread.h"
+
+/* Abstraction layer for timed threads */
+
+/* private */
+struct _timed_thread 
+{
+    pthread_t thread;                  /* thread itself */
+    pthread_attr_t thread_attr;                /* thread attributes */
+    pthread_mutex_t cs_mutex;          /* critical section mutex */
+    pthread_mutex_t runnable_mutex;    /* only for the runnable_cond */
+    pthread_cond_t runnable_cond;      /* used to time and stop the thread */
+    unsigned int interval_usecs;       /* firing interval in microseconds */
+};
+
+/* linked list of created threadsa */
+typedef struct _timed_thread_list
+{
+    timed_thread *p_timed_thread;
+    timed_thread **addr_of_p_timed_thread;
+    struct _timed_thread_list *next;
+} timed_thread_node, timed_thread_list;
+
+static timed_thread_list *p_timed_thread_list_head = NULL;
+static timed_thread_list *p_timed_thread_list_tail = NULL;
+
+
+/* create a timed thread */
+timed_thread* 
+timed_thread_create (void *(*start_routine)(void*), void *arg, unsigned int interval_usecs)
+{
+    timed_thread *p_timed_thread;
+
+    assert ((start_routine != NULL) && (interval_usecs >= MINIMUM_INTERVAL_USECS));
+
+    if ((p_timed_thread = calloc (sizeof(timed_thread), 1)) == 0)
+       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);
+    /* init mutexes */
+    pthread_mutex_init (&p_timed_thread->cs_mutex, NULL);
+    pthread_mutex_init (&p_timed_thread->runnable_mutex, NULL);
+    /* init cond */
+    pthread_cond_init (&p_timed_thread->runnable_cond, NULL);
+
+    p_timed_thread->interval_usecs = interval_usecs;
+
+    /* create thread */
+    if (pthread_create (&p_timed_thread->thread, &p_timed_thread->thread_attr, start_routine, arg))
+    {
+       timed_thread_destroy (p_timed_thread, NULL);
+       return NULL;
+    }
+
+    return p_timed_thread;
+}
+
+
+/* destroy a timed thread.
+ * optional addr_of_p_timed_thread to set callers pointer to NULL as a convenience. */
+void 
+timed_thread_destroy (timed_thread* p_timed_thread, timed_thread** addr_of_p_timed_thread)
+{
+    assert (p_timed_thread != NULL);
+    assert ((addr_of_p_timed_thread == NULL) || (*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);
+    pthread_mutex_unlock (&p_timed_thread->runnable_mutex);
+
+    /* join the terminating thread */
+    pthread_join (p_timed_thread->thread, NULL);
+
+    /* clean up */
+    pthread_attr_destroy (&p_timed_thread->thread_attr);
+    pthread_mutex_destroy (&p_timed_thread->cs_mutex);
+    pthread_mutex_destroy (&p_timed_thread->runnable_mutex);
+    pthread_cond_destroy (&p_timed_thread->runnable_cond);
+
+    free (p_timed_thread);
+    if (addr_of_p_timed_thread)
+       *addr_of_p_timed_thread = NULL;
+}
+
+
+/* lock a timed thread for critical section activity */
+int
+timed_thread_lock (timed_thread* p_timed_thread)
+{
+    assert (p_timed_thread != NULL);
+
+    return pthread_mutex_lock (&p_timed_thread->cs_mutex);
+}
+
+
+/* unlock a timed thread after critical section activity */
+int
+timed_thread_unlock (timed_thread* p_timed_thread)
+{
+    assert (p_timed_thread != NULL);
+
+    return pthread_mutex_unlock (&p_timed_thread->cs_mutex);
+}
+
+
+/* waits required interval for termination signal and returns 1 if got it, 0 otherwise */
+int 
+timed_thread_test (timed_thread* p_timed_thread)
+{
+    struct timespec abstime, reltime;
+
+    assert (p_timed_thread != NULL);
+
+    /* get the absolute time in the future we stop waiting for condition to signal */
+    clock_gettime (CLOCK_REALTIME, &abstime);
+    /* seconds portion of the microseconds interval */
+    reltime.tv_sec = (time_t)(p_timed_thread->interval_usecs / 1000000);
+    /* remaining microseconds convert to nanoseconds */
+    reltime.tv_nsec = (long)((p_timed_thread->interval_usecs % 1000000) * 1000);
+    /* absolute future time */
+    abstime.tv_sec += reltime.tv_sec;
+    abstime.tv_nsec += reltime.tv_nsec;
+
+    /* wait until future time for runnable_cond to signal */
+    if (pthread_cond_timedwait (&p_timed_thread->runnable_cond,
+                               &p_timed_thread->runnable_mutex,
+                               &abstime) != ETIMEDOUT)
+    {
+       /* runnable_cond was signalled or some error occured */
+       pthread_mutex_unlock (&p_timed_thread->runnable_mutex);
+       /* tell caller to exit */
+       return 1;
+    }
+
+    /* tell caller not to exit yet */
+    return 0;
+}
+
+
+/* exit a timed thread */
+void 
+timed_thread_exit (timed_thread* p_timed_thread)
+{
+    assert (p_timed_thread != NULL);
+
+    pthread_exit (NULL);
+}
+
+
+/* register a timed thread for future destruction via timed_thread_destroy_registered_threads() */
+int 
+timed_thread_register (timed_thread* p_timed_thread, timed_thread** addr_of_p_timed_thread)
+{
+    timed_thread_node *p_node;
+
+    assert (p_timed_thread != NULL);
+    assert ((addr_of_p_timed_thread == NULL) || (*addr_of_p_timed_thread == p_timed_thread));
+
+    if ((p_node = calloc (sizeof (timed_thread_node), 1)) == 0)
+       return 0;
+    
+    p_node->p_timed_thread = p_timed_thread;
+    p_node->addr_of_p_timed_thread = addr_of_p_timed_thread;
+    p_node->next = NULL;
+
+    if (!p_timed_thread_list_tail)
+    {
+       /* first node of empty list */
+       p_timed_thread_list_tail = p_node;
+       p_timed_thread_list_head = p_node;
+    }
+    else
+    {
+       /* add node to tail of non-empty list */
+       p_timed_thread_list_tail->next = p_node;
+       p_timed_thread_list_tail = p_node;
+    }
+
+    return 0;
+}
+
+
+/* destroy all registered timed threads */
+void 
+timed_thread_destroy_registered_threads (void)
+{
+    timed_thread_node *p_node, *p_next;
+
+    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);
+       free (p_node);
+    }
+
+    p_timed_thread_list_head = NULL;
+    p_timed_thread_list_tail = NULL;
+}
+
diff --git a/src/timed_thread.h b/src/timed_thread.h
new file mode 100644 (file)
index 0000000..83eafd3
--- /dev/null
@@ -0,0 +1,37 @@
+/* $Id $ */
+
+/* timed_thread.h
+ * Author: Philip Kovacs 
+ *
+ * Abstraction layer for timed threads
+ * */
+
+
+#define MINIMUM_INTERVAL_USECS 50000  /* 50000 microseconds = 50 ms =  0.05 sec */
+
+/* opaque structure for clients */
+typedef struct _timed_thread timed_thread;
+
+/* create a timed thread */
+timed_thread* timed_thread_create (void *(*start_routine)(void*), void *arg, unsigned int interval_ms);
+
+/* destroy a timed thread */
+void timed_thread_destroy (timed_thread* p_timed_thread, timed_thread** addr_of_p_timed_thread);
+
+/* lock a timed thread for critical section activity */
+int timed_thread_lock (timed_thread* p_timed_thread);
+
+/* unlock a timed thread after critical section activity */
+int timed_thread_unlock (timed_thread* p_timed_thread);
+
+/* waits required interval for termination signal and returns 1 if got it, 0 otherwise */
+int timed_thread_test (timed_thread* p_timed_thread);
+
+/* exit a timed thread */
+void timed_thread_exit (timed_thread* p_timed_thread);
+
+/* register a timed thread for future destruction */
+int timed_thread_register (timed_thread* p_timed_thread, timed_thread** addr_of_p_timed_thread);
+
+/* destroy all registered timed threads */
+void timed_thread_destroy_registered_threads (void);