From 41bb8b7e78b8df8f6724ce1b78edb0059d87324a Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 3 Dec 2009 09:29:56 -0500 Subject: [PATCH 01/48] make a TODO note about the finished condition variable --- src/backend/threads.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/threads.h b/src/backend/threads.h index e8b774299..ac8a163fd 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -124,6 +124,7 @@ struct lumiera_thread_struct // void (*function)(void*); // void* arg; pthread_t id; + // TODO: maybe this condition variable should be renamed when we have a better understanding of how it will be used LumieraReccondition finished; // the following member could have been called "class" except that it would conflict with C++ keyword // as consequence, it's been decided to leave the type name containing the word "class", From 5c7abbded99585d7334f075f57c1b43437b3909a Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 17 Dec 2009 03:49:02 +0100 Subject: [PATCH 02/48] Fix: race conditions with the nobug resource tracker * requires new nobug version * 40components.test "Type-based contexts" TypedCounter_test hangs for unknown reason, temporary disabled --- src/lib/condition.h | 40 ++++++++------- src/lib/mutex.h | 24 +++++---- src/lib/reccondition.h | 34 +++++++------ src/lib/rwlock.h | 105 ++++++++++++++++++++------------------- src/lib/sectionlock.h | 10 ++-- tests/40components.tests | 4 +- 6 files changed, 115 insertions(+), 102 deletions(-) diff --git a/src/lib/condition.h b/src/lib/condition.h index f90d079d8..efb3136ab 100644 --- a/src/lib/condition.h +++ b/src/lib/condition.h @@ -52,11 +52,12 @@ ({ \ lumiera_cond_section_.lock = (cnd); \ NOBUG_IF_ALPHA(lumiera_cond_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_ENTER (nobugflag, (cnd)->rh, "acquire condmutex", \ - NOBUG_RESOURCE_WAITING, lumiera_cond_section_.rh); \ - if (pthread_mutex_lock (&(cnd)->cndmutex)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_cond_section_.rh); \ + RESOURCE_WAIT (nobugflag, (cnd)->rh, "acquire condmutex", lumiera_cond_section_.rh) \ + { \ + if (pthread_mutex_lock (&(cnd)->cndmutex)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_cond_section_.rh); \ + } \ }); \ lumiera_cond_section_.lock; \ ({ \ @@ -74,12 +75,13 @@ REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ lumiera_cond_section_.lock = cnd; \ NOBUG_IF_ALPHA(lumiera_cond_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_ENTER (nobugflag, (cnd)->rh, "acquire condmutex", \ - NOBUG_RESOURCE_WAITING, lumiera_cond_section_.rh); \ - if (pthread_mutex_lock (&(cnd)->cndmutex)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_cond_section_.rh); \ - LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ + RESOURCE_ENTER (nobugflag, (cnd)->rh, "acquire condmutex", lumiera_cond_section_.rh) \ + { \ + if (pthread_mutex_lock (&(cnd)->cndmutex)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_cond_section_.rh); \ + LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ + } \ }); \ lumiera_cond_section_.lock; \ ({ \ @@ -97,13 +99,15 @@ * Must be used inside a CONDITION_SECTION. * @param expr Conditon which must become true, else the condition variable goes back into sleep */ -#define LUMIERA_CONDITION_WAIT(expr) \ - do { \ - REQUIRE (lumiera_cond_section_.lock, "Condition mutex not locked"); \ - NOBUG_RESOURCE_STATE_RAW (lumiera_cond_section_.flag, NOBUG_RESOURCE_WAITING, lumiera_cond_section_.rh); \ - pthread_cond_wait (&((LumieraCondition)lumiera_cond_section_.lock)->cond, \ - &((LumieraCondition)lumiera_cond_section_.lock)->cndmutex); \ - NOBUG_RESOURCE_STATE_RAW (lumiera_cond_section_.flag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_cond_section_.rh); \ +#define LUMIERA_CONDITION_WAIT(expr) \ + do { \ + REQUIRE (lumiera_cond_section_.lock, "Condition mutex not locked"); \ + NOBUG_RESOURCE_STATE_RAW (lumiera_cond_section_.flag, NOBUG_RESOURCE_WAITING, lumiera_cond_section_.rh) \ + { \ + pthread_cond_wait (&((LumieraCondition)lumiera_cond_section_.lock)->cond, \ + &((LumieraCondition)lumiera_cond_section_.lock)->cndmutex); \ + NOBUG_RESOURCE_STATE_RAW (lumiera_cond_section_.flag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_cond_section_.rh); \ + } \ } while (!(expr)) diff --git a/src/lib/mutex.h b/src/lib/mutex.h index cead7dec0..1a85d970a 100644 --- a/src/lib/mutex.h +++ b/src/lib/mutex.h @@ -46,11 +46,12 @@ ({ \ lumiera_lock_section_.lock = (mtx); \ NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire mutex", \ - NOBUG_RESOURCE_WAITING, lumiera_lock_section_.rh); \ - if (pthread_mutex_lock (&(mtx)->mutex)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \ + RESOURCE_WAIT (nobugflag, (mtx)->rh, "acquire mutex", lumiera_lock_section_.rh) \ + { \ + if (pthread_mutex_lock (&(mtx)->mutex)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \ + } \ }); \ lumiera_lock_section_.lock; \ ({ \ @@ -76,12 +77,13 @@ REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ lumiera_lock_section_.lock = mtx; \ NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire mutex", \ - NOBUG_RESOURCE_WAITING, lumiera_lock_section_.rh); \ - if (pthread_mutex_lock (&(mtx)->mutex)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \ - LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ + RESOURCE_WAIT (nobugflag, (mtx)->rh, "acquire mutex", lumiera_lock_section_.rh) \ + { \ + if (pthread_mutex_lock (&(mtx)->mutex)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \ + LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ + } \ }); \ lumiera_lock_section_.lock; \ ({ \ diff --git a/src/lib/reccondition.h b/src/lib/reccondition.h index 8ba3479ac..f9bcd59d1 100644 --- a/src/lib/reccondition.h +++ b/src/lib/reccondition.h @@ -50,11 +50,12 @@ ({ \ lumiera_reccond_section_.lock = (cnd); \ NOBUG_IF_ALPHA(lumiera_reccond_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_ENTER (nobugflag, (cnd)->rh, "acquire reccondmutex", \ - NOBUG_RESOURCE_WAITING, lumiera_reccond_section_.rh); \ - if (pthread_mutex_lock (&(cnd)->reccndmutex)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_reccond_section_.rh); \ + RESOURCE_WAIT (nobugflag, (cnd)->rh, "acquire reccondmutex", lumiera_reccond_section_.rh) \ + { \ + if (pthread_mutex_lock (&(cnd)->reccndmutex)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_reccond_section_.rh); \ + } \ }); \ lumiera_reccond_section_.lock; \ ({ \ @@ -73,12 +74,13 @@ REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ lumiera_reccond_section_.lock = (cnd); \ NOBUG_IF_ALPHA(lumiera_reccond_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_ENTER (nobugflag, (cnd)->rh, "acquire reccondmutex", \ - NOBUG_RESOURCE_WAITING, lumiera_reccond_section_.rh); \ - if (pthread_mutex_lock (&(cnd)->reccndmutex)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_reccond_section_.rh); \ - LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_) \ + RESOURCE_WAIT (nobugflag, (cnd)->rh, "acquire reccondmutex", lumiera_reccond_section_.rh) \ + { \ + if (pthread_mutex_lock (&(cnd)->reccndmutex)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_reccond_section_.rh); \ + LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ + } \ }); \ lumiera_reccond_section_.lock; \ ({ \ @@ -98,10 +100,12 @@ #define LUMIERA_RECCONDITION_WAIT(expr) \ do { \ REQUIRE (lumiera_reccond_section_.lock, "Condition recmutex not locked"); \ - NOBUG_RESOURCE_STATE_RAW (lumiera_reccond_section_.flag, NOBUG_RESOURCE_WAITING, lumiera_reccond_section_.rh); \ - pthread_cond_wait (&((LumieraReccondition)lumiera_reccond_section_.lock)->cond, \ - &((LumieraReccondition)lumiera_reccond_section_.lock)->reccndmutex); \ - NOBUG_RESOURCE_STATE_RAW (lumiera_reccond_section_.flag, NOBUG_RESOURCE_RECURSIVE, lumiera_reccond_section_.rh); \ + NOBUG_RESOURCE_STATE_RAW (lumiera_reccond_section_.flag, NOBUG_RESOURCE_WAITING, lumiera_reccond_section_.rh) \ + { \ + pthread_cond_wait (&((LumieraReccondition)lumiera_reccond_section_.lock)->cond, \ + &((LumieraReccondition)lumiera_reccond_section_.lock)->reccndmutex); \ + NOBUG_RESOURCE_STATE_RAW (lumiera_reccond_section_.flag, NOBUG_RESOURCE_RECURSIVE, lumiera_reccond_section_.rh); \ + } \ } while (!(expr)) diff --git a/src/lib/rwlock.h b/src/lib/rwlock.h index 1e72347cd..2cd8d006a 100644 --- a/src/lib/rwlock.h +++ b/src/lib/rwlock.h @@ -54,13 +54,12 @@ LUMIERA_ERROR_DECLARE(RWLOCK_WRLOCK); ({ \ lumiera_lock_section_.lock = (rwlck); \ NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_ENTER (nobugflag, (rwlck)->rh, "acquire readlock", \ - NOBUG_RESOURCE_WAITING, \ - lumiera_lock_section_.rh); \ - if (pthread_rwlock_rdlock (&(rwlck)->rwlock)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - TODO ("implement NOBUG_RESOURCE_SHARED"); \ - /*RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_SHARED, lumiera_lock_section_.rh); */ \ + RESOURCE_WAIT (nobugflag, (rwlck)->rh, "acquire readlock", lumiera_lock_section_.rh) \ + { \ + if (pthread_rwlock_rdlock (&(rwlck)->rwlock)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_SHARED, lumiera_lock_section_.rh); \ + } \ }); \ lumiera_lock_section_.lock; \ ({ \ @@ -78,12 +77,13 @@ LUMIERA_ERROR_DECLARE(RWLOCK_WRLOCK); REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ lumiera_lock_section_.lock = (rwlck); \ NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_ENTER (nobugflag, (rwlck)->rh, "acquire readlock", \ - NOBUG_RESOURCE_WAITING, lumiera_lock_section_.rh); \ - if (pthread_rwlock_rdlock (&(rwlck)->rwlock)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - /*RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_SHARED, lumiera_lock_section_.rh); */ \ - LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ + RESOURCE_WAIT (nobugflag, (rwlck)->rh, "acquire readlock", lumiera_lock_section_.rh) \ + { \ + if (pthread_rwlock_rdlock (&(rwlck)->rwlock)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_SHARED, lumiera_lock_section_.rh); \ + LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ + } \ }); \ lumiera_lock_section_.lock; \ ({ \ @@ -96,48 +96,49 @@ LUMIERA_ERROR_DECLARE(RWLOCK_WRLOCK); /** * Write locked section. */ -#define LUMIERA_WRLOCK_SECTION(nobugflag, rwlck) \ - for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \ - lumiera_lock_section_ = { \ - (void*)1, lumiera_rwlock_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ - lumiera_lock_section_.lock;) \ - for ( \ - ({ \ - lumiera_lock_section_.lock = (rwlck); \ - NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_ENTER (nobugflag, (rwlck)->rh, "acquire writelock", \ - NOBUG_RESOURCE_WAITING, \ - lumiera_lock_section_.rh); \ - if (pthread_rwlock_wrlock (&(rwlck)->rwlock)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \ - }); \ - lumiera_lock_section_.lock; \ - ({ \ - LUMIERA_RWLOCK_SECTION_UNLOCK; \ +#define LUMIERA_WRLOCK_SECTION(nobugflag, rwlck) \ + for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \ + lumiera_lock_section_ = { \ + (void*)1, lumiera_rwlock_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ + lumiera_lock_section_.lock;) \ + for ( \ + ({ \ + lumiera_lock_section_.lock = (rwlck); \ + NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \ + RESOURCE_WAIT (nobugflag, (rwlck)->rh, "acquire writelock", lumiera_lock_section_.rh) \ + { \ + if (pthread_rwlock_wrlock (&(rwlck)->rwlock)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \ + } \ + }); \ + lumiera_lock_section_.lock; \ + ({ \ + LUMIERA_RWLOCK_SECTION_UNLOCK; \ })) -#define LUMIERA_WRLOCK_SECTION_CHAIN(nobugflag, rwlck) \ - for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \ - NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_lock_section_ = { \ - (void*)1, lumiera_rwlock_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ - lumiera_lock_section_.lock;) \ - for ( \ - ({ \ - REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ - lumiera_lock_section_.lock = (rwlck); \ - NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_ENTER (nobugflag, (rwlck)->rh, "acquire writelock", \ - NOBUG_RESOURCE_WAITING, lumiera_lock_section_.rh); \ - if (pthread_rwlock_wrlock (&(twlck)->rwlock)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \ - LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ - }); \ - lumiera_lock_section_.lock; \ - ({ \ - LUMIERA_MUTEX_SECTION_UNLOCK; \ +#define LUMIERA_WRLOCK_SECTION_CHAIN(nobugflag, rwlck) \ + for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \ + NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_lock_section_ = { \ + (void*)1, lumiera_rwlock_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ + lumiera_lock_section_.lock;) \ + for ( \ + ({ \ + REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ + lumiera_lock_section_.lock = (rwlck); \ + NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \ + RESOURCE_WAIT (nobugflag, (rwlck)->rh, "acquire writelock", lumiera_lock_section_.rh) \ + { \ + if (pthread_rwlock_wrlock (&(twlck)->rwlock)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \ + LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ + } \ + }); \ + lumiera_lock_section_.lock; \ + ({ \ + LUMIERA_MUTEX_SECTION_UNLOCK; \ })) diff --git a/src/lib/sectionlock.h b/src/lib/sectionlock.h index c50ecfc8d..975a5fbc2 100644 --- a/src/lib/sectionlock.h +++ b/src/lib/sectionlock.h @@ -65,10 +65,12 @@ lumiera_sectionlock_ensureunlocked (LumieraSectionlock self) #define LUMIERA_SECTION_UNLOCK_(section) \ do if ((section)->lock) \ { \ - if ((section)->unlock((section)->lock)) \ - LUMIERA_DIE (LOCK_RELEASE); \ - (section)->lock = NULL; \ - NOBUG_RESOURCE_LEAVE_RAW((section)->flag, (section)->rh); \ + NOBUG_RESOURCE_LEAVE_RAW((section)->flag, (section)->rh) \ + { \ + if ((section)->unlock((section)->lock)) \ + LUMIERA_DIE (LOCK_RELEASE); \ + (section)->lock = NULL; \ + } \ } while (0) diff --git a/tests/40components.tests b/tests/40components.tests index 01d959a34..7475363bd 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -857,8 +857,8 @@ TEST "TypedAllocationManager" TypedAllocationManager_test < Date: Fri, 18 Dec 2009 03:14:47 +0100 Subject: [PATCH 03/48] Sectionlock needs a 'user' handle with new nobug --- src/lib/sectionlock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/sectionlock.h b/src/lib/sectionlock.h index 975a5fbc2..42e719de7 100644 --- a/src/lib/sectionlock.h +++ b/src/lib/sectionlock.h @@ -42,7 +42,7 @@ struct lumiera_sectionlock_struct void* lock; lumiera_sectionlock_unlock_fn unlock; NOBUG_IF_ALPHA(struct nobug_flag* flag); - RESOURCE_HANDLE (rh); + RESOURCE_USER (rh); }; typedef struct lumiera_sectionlock_struct lumiera_sectionlock; typedef struct lumiera_sectionlock_struct* LumieraSectionlock; From 24e87c815ddf6522ccbe8af87b7f722c3a6f62e1 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 17 Dec 2009 22:08:57 -0500 Subject: [PATCH 04/48] remove old functions pthread_runner and lumiera_thread_run --- src/backend/threads.c | 53 ------------------------------------------- 1 file changed, 53 deletions(-) diff --git a/src/backend/threads.c b/src/backend/threads.c index 62f0d14a6..0520de288 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -73,59 +73,6 @@ static void* thread_loop (void* arg) return 0; } -#if 0 -static void* pthread_runner (void* thread) -{ - pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL); - - struct lumiera_thread_mockup* starter = (struct lumiera_thread_mockup*) thread; - LumieraReccondition thread_end_notification = starter->finished; - - starter->fn (starter->arg); - - if (!thread_end_notification) - return NULL; // no signalling of thread termination desired - - LUMIERA_RECCONDITION_SECTION(cond_sync, thread_end_notification) - LUMIERA_RECCONDITION_BROADCAST; - - return NULL; -} -#endif - -#if 0 -// TODO: rewrite this using lumiera_threadpool_acquire() -LumieraThread -lumiera_thread_run (enum lumiera_thread_class kind, - void (*start_routine)(void *), - void * arg, - LumieraReccondition finished, - const char* purpose, - struct nobug_flag* flag) -{ - (void) kind; - (void) purpose; - (void) flag; - - if (attr_once == PTHREAD_ONCE_INIT) - pthread_once (&attr_once, thread_attr_init); - - static struct lumiera_thread_mockup thread; - - thread.fn = start_routine; - thread.arg = arg; - thread.finished = finished; - - pthread_t dummy; - int error = pthread_create (&dummy, &attrs, pthread_runner, &thread); - - if (error) return 0; /////TODO temporary addition by Ichthyo; probably we'll set lumiera_error? - return (LumieraThread) 1; -} -#endif - -// TODO: new implementation, remove the above one -// maybe this shouldn't return LumieraThread at all // when this is called it should have already been decided that the function // shall run in parallel, as a thread LumieraThread From f2406c23a1ffda8a2938690ff389bf8660ab7b5e Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Wed, 23 Dec 2009 13:10:31 -0500 Subject: [PATCH 05/48] bork bork bork by pulling this you agree to... --- src/backend/thread-wrapper.hpp | 2 +- src/backend/threadpool.c | 96 ++++++++++++++++++-------------- src/backend/threadpool.h | 17 ++++-- src/backend/threads.c | 81 ++++++++++++++++++--------- src/backend/threads.h | 23 +++++--- tests/30backend-threadpool.tests | 63 +++------------------ tests/backend/test-threadpool.c | 70 +++++++++++++++++++++-- tests/backend/test-threads.c | 3 - tests/test.sh | 2 +- 9 files changed, 208 insertions(+), 149 deletions(-) diff --git a/src/backend/thread-wrapper.hpp b/src/backend/thread-wrapper.hpp index 3f897b582..f8ec2bc87 100644 --- a/src/backend/thread-wrapper.hpp +++ b/src/backend/thread-wrapper.hpp @@ -177,10 +177,10 @@ namespace backend { lumiera_thread_run ( kind , &run // invoking the run helper and.. , this // passing this start context as parameter - , joinCond // maybe wait-blocking for the thread to terminate , purpose.c() , logging_flag ); + (void)joinCond; if (!res) throw lumiera::error::State("failed to create new thread."); diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 66ecd4e33..2a33978d6 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -53,21 +53,22 @@ void* pool_thread_loop(void * arg) } void -lumiera_threadpool_init(unsigned limit) +lumiera_threadpool_init() { for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { llist_init(&threadpool.pool[i].list); - threadpool.pool[i].max_threads = limit; - threadpool.pool[i].working_thread_count = 0; + threadpool.pool[i].working_thread_count = 0; threadpool.pool[i].idle_thread_count = 0; //TODO: configure each pools' pthread_attrs appropriately pthread_attr_init (&threadpool.pool[i].pthread_attrs); - pthread_attr_setdetachstate (&threadpool.pool[i].pthread_attrs, PTHREAD_CREATE_DETACHED); + // cehteh prefers that threads are joinable by default + //pthread_attr_setdetachstate (&threadpool.pool[i].pthread_attrs, PTHREAD_CREATE_DETACHED); //cancel... lumiera_mutex_init(&threadpool.pool[i].lock,"pool of threads", &NOBUG_FLAG(threadpool)); + lumiera_reccondition_init (&threadpool.pool[i].signal, "thread-signal", &NOBUG_FLAG(threadpool)); } } @@ -78,10 +79,16 @@ lumiera_threadpool_destroy(void) for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { ECHO ("destroying individual pool #%d", i); - // no locking is done at this point - ECHO ("number of threads in the pool=%d", llist_count(&threadpool.pool[i].list)); - LLIST_WHILE_HEAD(&threadpool.pool[i].list, thread) - lumiera_thread_delete((LumieraThread)thread); + LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[i].lock) + { + REQUIRE (0 == threadpool.pool[i].working_thread_count, "%d threads are running", threadpool.pool[i].working_thread_count); + // TODO need to have a stronger assertion that no threads are really running because they will not even be in the list + ECHO ("number of threads in the pool=%d", llist_count(&threadpool.pool[i].list)); + LLIST_WHILE_HEAD(&threadpool.pool[i].list, t) + { + lumiera_thread_delete((LumieraThread)t); + } + } ECHO ("destroying the pool mutex"); lumiera_mutex_destroy (&threadpool.pool[i].lock, &NOBUG_FLAG (threadpool)); ECHO ("pool mutex destroyed"); @@ -89,6 +96,15 @@ lumiera_threadpool_destroy(void) } } +void lumiera_threadpool_unlink(LumieraThread thread) +{ + REQUIRE (thread, "invalid thread given"); + REQUIRE (thread->kind < LUMIERA_THREADCLASS_COUNT, "thread belongs to an unknown pool kind: %d", thread->kind); + llist_unlink(&thread->node); + ENSURE (llist_is_empty(&thread->node), "failed to unlink the thread"); +} + + LumieraThread lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, const char* purpose, @@ -97,52 +113,45 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, LumieraThread ret; REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "unknown pool kind specified: %d", kind); - if (llist_is_empty (&threadpool.pool[kind].list)) - { - // TODO: fill in the reccondition argument, currently NULL - FIXME ("this max thread logic needs to be deeply thought about and made more efficient as well as rebust"); - if (threadpool.pool[kind].working_thread_count - + threadpool.pool[kind].idle_thread_count - < threadpool.pool[kind].max_threads) { - ret = lumiera_thread_new (kind, NULL, purpose, flag, + LUMIERA_RECCONDITION_SECTION (threadpool, &threadpool.pool[kind].signal) + { + if (llist_is_empty (&threadpool.pool[kind].list)) + { + + ret = lumiera_thread_new (kind, purpose, flag, &threadpool.pool[kind].pthread_attrs); - threadpool.pool[kind].working_thread_count++; + threadpool.pool[kind].idle_thread_count++; ENSURE (ret, "did not create a valid thread"); + LUMIERA_RECCONDITION_WAIT (!llist_is_empty (&threadpool.pool[kind].list)); } - else - { - //ERROR (threadpool, "did not create a new thread because per-pool limit was reached: %d", threadpool.pool[kind].max_threads); - LUMIERA_DIE(ERRNO); - } - } - else - { - // use an existing thread, pick the first one - // remove it from the pool's list - LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[kind].lock) - { - ret = (LumieraThread)(llist_unlink(llist_head (&threadpool.pool[kind].list))); - threadpool.pool[kind].working_thread_count++; - threadpool.pool[kind].idle_thread_count--; // cheaper than using llist_count - ENSURE (threadpool.pool[kind].idle_thread_count == - llist_count(&threadpool.pool[kind].list), - "idle thread count %d is wrong, should be %d", - threadpool.pool[kind].idle_thread_count, - llist_count(&threadpool.pool[kind].list)); - } - ENSURE (ret, "did not find a valid thread"); - } - return ret; + // use an existing thread, pick the first one + // remove it from the pool's list + ret = (LumieraThread)(llist_unlink(llist_head (&threadpool.pool[kind].list))); + REQUIRE (ret->state == LUMIERA_THREADSTATE_IDLE, "trying to return a non-idle thread (state=%s)", lumiera_threadstate_names[ret->state]); + threadpool.pool[kind].working_thread_count++; + threadpool.pool[kind].idle_thread_count--; // cheaper than using llist_count + ENSURE (threadpool.pool[kind].idle_thread_count == + llist_count(&threadpool.pool[kind].list), + "idle thread count %d is wrong, should be %d", + threadpool.pool[kind].idle_thread_count, + llist_count(&threadpool.pool[kind].list)); + ENSURE (ret, "did not find a valid thread"); + } + return ret; } +// TODO: rename to lumiera_threadpool_park_thread void -lumiera_threadpool_release_thread(LumieraThread thread) +lumiera_threadpool_park_thread(LumieraThread thread) { REQUIRE (thread, "invalid thread given"); REQUIRE (thread->kind < LUMIERA_THREADCLASS_COUNT, "thread belongs to an unknown pool kind: %d", thread->kind); - LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[thread->kind].lock) + REQUIRE (thread->state != LUMIERA_THREADSTATE_IDLE, "trying to park an already idle thread"); + + LUMIERA_RECCONDITION_SECTION (threadpool, &threadpool.pool[thread->kind].signal) { + thread->state = LUMIERA_THREADSTATE_IDLE; REQUIRE (llist_is_single(&thread->node), "thread already belongs to some list"); llist_insert_head(&threadpool.pool[thread->kind].list, &thread->node); threadpool.pool[thread->kind].working_thread_count--; @@ -153,6 +162,7 @@ lumiera_threadpool_release_thread(LumieraThread thread) threadpool.pool[thread->kind].idle_thread_count, llist_count(&threadpool.pool[thread->kind].list)); // REQUIRE (!llist_is_empty (&threadpool.pool[thread->kind].list), "thread pool is still empty after insertion"); + LUMIERA_RECCONDITION_BROADCAST; } } diff --git a/src/backend/threadpool.h b/src/backend/threadpool.h index 03b56a4fe..de545876c 100644 --- a/src/backend/threadpool.h +++ b/src/backend/threadpool.h @@ -55,12 +55,12 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, struct nobug_flag* flag); /** - * Release a thread - * This ends up putting a (parked/idle) thread back on the list of an appropriate threadpool. + * Park a thread + * This ends up putting a finished thread back on the list of an appropriate threadpool. * This function doesn't need to be accessible outside of the threadpool implementation. */ void -lumiera_threadpool_release_thread(LumieraThread thread); +lumiera_threadpool_park_thread(LumieraThread thread); typedef struct lumiera_threadpool_struct lumiera_threadpool; typedef lumiera_threadpool* LumieraThreadpool; @@ -71,23 +71,28 @@ struct lumiera_threadpool_struct { llist list; lumiera_mutex lock; - unsigned max_threads; unsigned working_thread_count; unsigned idle_thread_count; pthread_attr_t pthread_attrs; + lumiera_reccondition signal; } pool[LUMIERA_THREADCLASS_COUNT]; }; /** * Initialize the thread pool. - * @param limit the maximum number of threads (idle+working) allowed per pool */ void -lumiera_threadpool_init(unsigned limit); +lumiera_threadpool_init(); void lumiera_threadpool_destroy(void); +/** + * Just remove the thread structure from an associated pool list. + */ +void +lumiera_threadpool_unlink(LumieraThread thread); + #endif /* // Local Variables: diff --git a/src/backend/threads.c b/src/backend/threads.c index 0520de288..a75b7f81b 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -67,9 +67,29 @@ struct lumiera_thread_mockup LumieraReccondition finished; }; -static void* thread_loop (void* arg) +static void* thread_loop (void* thread) { - (void)arg; + LumieraThread t = (LumieraThread)thread; + + pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL); + + REQUIRE (t, "thread does not exist"); + + ECHO ("entering section 1"); + // this seems to deadlock unexpectedly: + LUMIERA_RECCONDITION_SECTION (threads, &t->signal) + { + do { + // NULL function means: no work to do + if (t->function) + t->function (t->arguments); + lumiera_threadpool_park_thread(t); + LUMIERA_RECCONDITION_WAIT(t->state != LUMIERA_THREADSTATE_IDLE); + } while (t->state != LUMIERA_THREADSTATE_SHUTDOWN); + // SHUTDOWN state + + ECHO ("thread quitting"); + } return 0; } @@ -79,22 +99,23 @@ LumieraThread lumiera_thread_run (enum lumiera_thread_class kind, void (*function)(void *), void * arg, - LumieraReccondition finished, const char* purpose, struct nobug_flag* flag) { - (void)finished; - (void)function; - (void)arg; + REQUIRE (function, "invalid function"); + // ask the threadpool for a thread (it might create a new one) LumieraThread self = lumiera_threadpool_acquire_thread(kind, purpose, flag); - // TODO: set the function and data to be run - // lumiera_thread_set_func_data (self, start_routine, arg, purpose, flag); + // set the function and data to be run + self->function = function; + self->arguments = arg; // and let it really run (signal the condition var, the thread waits on it) - LUMIERA_RECCONDITION_SECTION(cond_sync, self->finished) - LUMIERA_RECCONDITION_SIGNAL; + self->state = LUMIERA_THREADSTATE_WAKEUP; + ECHO ("entering section 2"); + LUMIERA_RECCONDITION_SECTION(threads, &self->signal) + LUMIERA_RECCONDITION_BROADCAST; // NOTE: example only, add solid error handling! @@ -106,29 +127,25 @@ lumiera_thread_run (enum lumiera_thread_class kind, */ LumieraThread lumiera_thread_new (enum lumiera_thread_class kind, - LumieraReccondition finished, const char* purpose, struct nobug_flag* flag, pthread_attr_t* attrs) { // TODO: do something with these: (void) purpose; - (void) flag; REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "invalid thread kind specified: %d", kind); REQUIRE (attrs, "invalid pthread attributes structure passed"); - //REQUIRE (finished, "invalid finished flag passed"); - - LumieraThread self = lumiera_malloc (sizeof (*self)); llist_init(&self->node); - self->finished = finished; + lumiera_reccondition_init (&self->signal, "thread-control", flag); self->kind = kind; - self->state = LUMIERA_THREADSTATE_IDLE; + self->state = LUMIERA_THREADSTATE_STARTUP; + self->function = NULL; + self->arguments = NULL; - //REQUIRE (thread_loop); int error = pthread_create (&self->id, attrs, &thread_loop, self); - ENSURE(error == 0 || EAGAIN == error, "pthread returned %d:%s", error, strerror(error)); + ENSURE(error == 0 || EAGAIN == error, "pthread_create returned %d:%s", error, strerror(error)); if (error) { // error here can only be EAGAIN, given the above ENSURE @@ -143,12 +160,26 @@ lumiera_thread_destroy (LumieraThread self) { REQUIRE (self, "trying to destroy an invalid thread"); - // TODO: stop the pthread - llist_unlink(&self->node); - //finished = NULL; // or free(finished)? - lumiera_reccondition_destroy (self->finished, &NOBUG_FLAG(threads)); - //kind = 0; - //state = 0; + lumiera_threadpool_unlink(self); + + // get the pthread out of the processing loop + // need to signal to the thread that it should start quitting + // should this be within the section? + LUMIERA_RECCONDITION_SECTION(threads, &self->signal) + { + REQUIRE (self->state == LUMIERA_THREADSTATE_IDLE, "trying to delete a thread in state other than IDLE (%s)", lumiera_threadstate_names[self->state]); + self->state = LUMIERA_THREADSTATE_SHUTDOWN; + self->function = NULL; + self->arguments = NULL; + LUMIERA_RECCONDITION_SIGNAL; + } + + int error = pthread_join(self->id, NULL); + ENSURE (0 == error, "pthread_join returned %d:%s", error, strerror(error)); + + // condition has to be destroyed after joining with the thread + lumiera_reccondition_destroy (&self->signal, &NOBUG_FLAG(threads)); + return self; } diff --git a/src/backend/threads.h b/src/backend/threads.h index ac8a163fd..a55926123 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -90,10 +90,16 @@ enum lumiera_thread_class // defined in threads.c extern const char* lumiera_threadclass_names[]; -#define LUMIERA_THREAD_STATES \ - LUMIERA_THREAD_STATE(IDLE) \ - LUMIERA_THREAD_STATE(RUNNING) \ - LUMIERA_THREAD_STATE(ERROR) +// there is some confusion between the meaning of this +// on one hand it could be used to tell the current state of the thread +// on the other, it is used to tell the thread which state to enter on next iteration +#define LUMIERA_THREAD_STATES \ + LUMIERA_THREAD_STATE(IDLE) \ + LUMIERA_THREAD_STATE(ERROR) \ + LUMIERA_THREAD_STATE(RUNNING) \ + LUMIERA_THREAD_STATE(WAKEUP) \ + LUMIERA_THREAD_STATE(SHUTDOWN) \ + LUMIERA_THREAD_STATE(STARTUP) #define LUMIERA_THREAD_STATE(name) LUMIERA_THREADSTATE_##name, @@ -125,12 +131,15 @@ struct lumiera_thread_struct // void* arg; pthread_t id; // TODO: maybe this condition variable should be renamed when we have a better understanding of how it will be used - LumieraReccondition finished; + lumiera_reccondition signal; // control signal, state change signal // the following member could have been called "class" except that it would conflict with C++ keyword // as consequence, it's been decided to leave the type name containing the word "class", // while all members/variables called "kind" enum lumiera_thread_class kind; + // this is used both as a command and as a state tracker lumiera_thread_state state; + void (*function)(void *); + void * arguments; }; /** @@ -138,7 +147,6 @@ struct lumiera_thread_struct */ LumieraThread lumiera_thread_new (enum lumiera_thread_class kind, - LumieraReccondition finished, const char* purpose, struct nobug_flag* flag, pthread_attr_t* attrs); @@ -162,8 +170,6 @@ lumiera_thread_delete (LumieraThread self); * @param kind class of the thread to start * @param function pointer to a function to execute in a thread (returning void, not void* as in pthreads) * @param arg generic pointer passed to the thread - * @param finished a condition variable to be broadcasted, if not NULL. - * The associated mutex should be locked at thread_run time already, else the signal can get lost. * @param purpose descriptive name of this thread, used by NoBug * @param flag NoBug flag used for logging the thread startup and return */ @@ -171,7 +177,6 @@ LumieraThread lumiera_thread_run (enum lumiera_thread_class kind, void (*function)(void *), void * arg, - LumieraReccondition finished, const char* purpose, struct nobug_flag* flag); diff --git a/tests/30backend-threadpool.tests b/tests/30backend-threadpool.tests index c136aff42..2cad43477 100644 --- a/tests/30backend-threadpool.tests +++ b/tests/30backend-threadpool.tests @@ -5,24 +5,11 @@ PLANNED "create" PLANNED "yield" PLANNED "cancel" -TEST "Acquire/Release test" basic-acquire-release < #include +#include + +void is_prime(void * arg) +{ + int number = *(int *)arg; + int prime = 1; + + for (int x = number; x >= sqrt(number); --x) + { + if (number % x == 0) + { + prime = 0; + break; + } + } + *(int *)arg = prime; +} TESTS_BEGIN +TEST ("threadpool-basic") +{ + lumiera_threadpool_init(100); + lumiera_threadpool_destroy(); +} + +TEST ("threadpool1") +{ + ECHO("start by initializing the threadpool"); + lumiera_threadpool_init(100); + LumieraThread t1 = + lumiera_threadpool_acquire_thread(LUMIERA_THREADCLASS_INTERACTIVE, + "test purpose", + &NOBUG_FLAG(NOBUG_ON)); + // lumiera_threadpool_release_thread(t1); + ECHO("acquired thread 1 %p",t1); + lumiera_threadpool_destroy(); +} + TEST ("basic-acquire-release") { @@ -37,12 +73,12 @@ TEST ("basic-acquire-release") LumieraThread t1 = lumiera_threadpool_acquire_thread(LUMIERA_THREADCLASS_INTERACTIVE, "test purpose", - NULL); + &NOBUG_FLAG(NOBUG_ON)); ECHO("acquiring thread 2"); LumieraThread t2 = lumiera_threadpool_acquire_thread(LUMIERA_THREADCLASS_IDLE, "test purpose", - NULL); + &NOBUG_FLAG(NOBUG_ON)); ECHO("thread 1 kind=%s", lumiera_threadclass_names[t1->kind]); CHECK(LUMIERA_THREADCLASS_INTERACTIVE == t1->kind); @@ -54,16 +90,17 @@ TEST ("basic-acquire-release") CHECK(LUMIERA_THREADSTATE_IDLE == t2->state); ECHO("releasing thread 1"); - lumiera_threadpool_release_thread(t1); + //lumiera_threadpool_release_thread(t1); ECHO("thread 1 has been released"); ECHO("releasing thread 2"); - lumiera_threadpool_release_thread(t2); + //lumiera_threadpool_release_thread(t2); ECHO("thread 2 has been released"); lumiera_threadpool_destroy(); } +#if 0 TEST ("many-acquire-release") { @@ -79,7 +116,7 @@ TEST ("many-acquire-release") threads[i+kind*threads_per_pool_count] = lumiera_threadpool_acquire_thread(kind, "test purpose", - NULL); + &NOBUG_FLAG(NOBUG_ON)); } } @@ -107,7 +144,7 @@ TEST ("toomany-acquire-release") threads[i+kind*threads_per_pool_count] = lumiera_threadpool_acquire_thread(kind, "test purpose", - NULL); + &NOBUG_FLAG(NOBUG_ON)); } } @@ -119,5 +156,26 @@ TEST ("toomany-acquire-release") lumiera_threadpool_destroy(); } +#endif + +TEST ("process-function") +{ + // this is what the scheduler would do once it figures out what function a job needs to run + LumieraThread t; + int number = 440616; + + lumiera_threadpool_init(10); + + ECHO ("the input to the function is %d", number); + + t = lumiera_thread_run (LUMIERA_THREADCLASS_INTERACTIVE, + &is_prime, + (void *)&number, //void * arg, + "process my test function", + &NOBUG_FLAG(NOBUG_ON)); // struct nobug_flag* flag) + + // cleanup + lumiera_threadpool_destroy(); +} TESTS_END diff --git a/tests/backend/test-threads.c b/tests/backend/test-threads.c index 76da2f450..21786ae8b 100644 --- a/tests/backend/test-threads.c +++ b/tests/backend/test-threads.c @@ -91,7 +91,6 @@ TEST ("simple_thread") lumiera_thread_run (LUMIERA_THREADCLASS_WORKER, threadfn, NULL, - NULL, argv[1], NULL); @@ -112,7 +111,6 @@ TEST ("thread_synced") lumiera_thread_run (LUMIERA_THREADCLASS_WORKER, threadsyncfn, &cnd, - &cnd, argv[1], NULL); @@ -143,7 +141,6 @@ TEST ("mutex_thread") lumiera_thread_run (LUMIERA_THREADCLASS_WORKER, mutexfn, NULL, - NULL, argv[1], NULL); diff --git a/tests/test.sh b/tests/test.sh index 951d2fcea..b1fd0d99b 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -26,7 +26,7 @@ # stop testing on the first failure export LC_ALL=C -NOBUG_LOGREGEX='^\(\*\*[0-9]*\*\* \)\?[0-9]\{10,\}: \(TRACE\|INFO\|NOTICE\|WARNING\|ERR\|TODO\|PLANNED\|FIXME\|DEPRECATED\|UNIMPLEMENTED\):' +NOBUG_LOGREGEX='^\(\*\*[0-9]*\*\* \)\?[0-9]\{10,\}: \(TRACE\|INFO\|NOTICE\|WARNING\|ERR\|TODO\|PLANNED\|FIXME\|DEPRECATED\|UNIMPLEMENTED\|RESOURCE_ENTER\|RESOURCE_LEAVE\|RESOURCE_STATE\):' arg0="$0" srcdir="$(dirname "$arg0")" From 6f5578ba1002b8e2290e64d98408e7aa82c5dfff Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Wed, 23 Dec 2009 18:14:29 -0500 Subject: [PATCH 06/48] fix a copy+paste mistake in LUMIERA_RECCONDITION_SECTION_CHAIN and add a test-case for it --- src/lib/reccondition.h | 6 +++--- tests/15locking.tests | 4 ++++ tests/library/test-locking.c | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/lib/reccondition.h b/src/lib/reccondition.h index f9bcd59d1..51ce6ef07 100644 --- a/src/lib/reccondition.h +++ b/src/lib/reccondition.h @@ -65,13 +65,13 @@ #define LUMIERA_RECCONDITION_SECTION_CHAIN(nobugflag, cnd) \ - for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \ + for (lumiera_sectionlock *lumiera_reccond_section_old_ = &lumiera_reccond_section_, \ NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_reccond_section_ = { \ (void*)1, lumiera_reccondition_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ lumiera_reccond_section_.lock;) \ for ( \ ({ \ - REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ + REQUIRE (lumiera_reccond_section_old_->lock, "section prematurely unlocked"); \ lumiera_reccond_section_.lock = (cnd); \ NOBUG_IF_ALPHA(lumiera_reccond_section_.flag = &NOBUG_FLAG(nobugflag);) \ RESOURCE_WAIT (nobugflag, (cnd)->rh, "acquire reccondmutex", lumiera_reccond_section_.rh) \ @@ -79,7 +79,7 @@ if (pthread_mutex_lock (&(cnd)->reccndmutex)) \ LUMIERA_DIE (LOCK_ACQUIRE); \ RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_reccond_section_.rh); \ - LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ + LUMIERA_SECTION_UNLOCK_(lumiera_reccond_section_old_); \ } \ }); \ lumiera_reccond_section_.lock; \ diff --git a/tests/15locking.tests b/tests/15locking.tests index 0936499f2..c72f88855 100644 --- a/tests/15locking.tests +++ b/tests/15locking.tests @@ -86,3 +86,7 @@ PLANNED "reccondition broadcasting" < Date: Thu, 24 Dec 2009 01:45:44 +0100 Subject: [PATCH 07/48] remove threadpool_unlink() thread removes itself from the list, this is trival in place --- src/backend/threadpool.c | 8 -------- src/backend/threadpool.h | 6 ------ src/backend/threads.c | 2 +- 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 2a33978d6..d7c13551e 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -96,14 +96,6 @@ lumiera_threadpool_destroy(void) } } -void lumiera_threadpool_unlink(LumieraThread thread) -{ - REQUIRE (thread, "invalid thread given"); - REQUIRE (thread->kind < LUMIERA_THREADCLASS_COUNT, "thread belongs to an unknown pool kind: %d", thread->kind); - llist_unlink(&thread->node); - ENSURE (llist_is_empty(&thread->node), "failed to unlink the thread"); -} - LumieraThread lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, diff --git a/src/backend/threadpool.h b/src/backend/threadpool.h index de545876c..572727e3e 100644 --- a/src/backend/threadpool.h +++ b/src/backend/threadpool.h @@ -87,12 +87,6 @@ lumiera_threadpool_init(); void lumiera_threadpool_destroy(void); -/** - * Just remove the thread structure from an associated pool list. - */ -void -lumiera_threadpool_unlink(LumieraThread thread); - #endif /* // Local Variables: diff --git a/src/backend/threads.c b/src/backend/threads.c index a75b7f81b..9c4cc9f1f 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -160,7 +160,7 @@ lumiera_thread_destroy (LumieraThread self) { REQUIRE (self, "trying to destroy an invalid thread"); - lumiera_threadpool_unlink(self); + llist_unlink (&self->node); // get the pthread out of the processing loop // need to signal to the thread that it should start quitting From 026fab07dc845f0a7f696405fa8286cd456f0125 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 24 Dec 2009 01:46:43 +0100 Subject: [PATCH 08/48] cosmetics, deadcode removal --- src/backend/threadpool.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index d7c13551e..1f2a1cc71 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -42,23 +42,13 @@ NOBUG_DEFINE_FLAG_PARENT (threadpool, threads_dbg); /*TODO insert a suitable/bet //code goes here// -void* pool_thread_loop(void * arg) -{ - (void) arg; - while (1) - { - ; - } - return arg; -} - void lumiera_threadpool_init() { for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { llist_init(&threadpool.pool[i].list); - threadpool.pool[i].working_thread_count = 0; + threadpool.pool[i].working_thread_count = 0; threadpool.pool[i].idle_thread_count = 0; //TODO: configure each pools' pthread_attrs appropriately From 6b4415d8fa4bfb86757a5abf16f10a9f3f585372 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 24 Dec 2009 01:50:59 +0100 Subject: [PATCH 09/48] nobugify declare and init the nobug flags and use them for logging diagnostics --- src/backend/threadpool.c | 16 +++++++++++----- src/backend/threads.c | 10 ++++++++-- src/backend/threads.h | 1 + 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 1f2a1cc71..706f5bb3b 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -45,6 +45,10 @@ NOBUG_DEFINE_FLAG_PARENT (threadpool, threads_dbg); /*TODO insert a suitable/bet void lumiera_threadpool_init() { + NOBUG_INIT_FLAG(threadpool); + NOBUG_INIT_FLAG(threads); + TRACE(threadpool); + for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { llist_init(&threadpool.pool[i].list); @@ -65,15 +69,16 @@ lumiera_threadpool_init() void lumiera_threadpool_destroy(void) { - ECHO ("destroying threadpool"); + TRACE(threadpool); + for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { - ECHO ("destroying individual pool #%d", i); + TRACE (threadpool, "destroying individual pool #%d", i); LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[i].lock) { REQUIRE (0 == threadpool.pool[i].working_thread_count, "%d threads are running", threadpool.pool[i].working_thread_count); // TODO need to have a stronger assertion that no threads are really running because they will not even be in the list - ECHO ("number of threads in the pool=%d", llist_count(&threadpool.pool[i].list)); + INFO (threadpool, "number of threads in the pool=%d", llist_count(&threadpool.pool[i].list)); LLIST_WHILE_HEAD(&threadpool.pool[i].list, t) { lumiera_thread_delete((LumieraThread)t); @@ -92,8 +97,8 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, const char* purpose, struct nobug_flag* flag) { - LumieraThread ret; - + TRACE(threadpool); + LumieraThread ret = NULL; REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "unknown pool kind specified: %d", kind); LUMIERA_RECCONDITION_SECTION (threadpool, &threadpool.pool[kind].signal) { @@ -126,6 +131,7 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, void lumiera_threadpool_park_thread(LumieraThread thread) { + TRACE(threadpool); REQUIRE (thread, "invalid thread given"); REQUIRE (thread->kind < LUMIERA_THREADCLASS_COUNT, "thread belongs to an unknown pool kind: %d", thread->kind); diff --git a/src/backend/threads.c b/src/backend/threads.c index 9c4cc9f1f..a34dcde4a 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -69,6 +69,7 @@ struct lumiera_thread_mockup static void* thread_loop (void* thread) { + TRACE(threads); LumieraThread t = (LumieraThread)thread; pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL); @@ -81,14 +82,16 @@ static void* thread_loop (void* thread) { do { // NULL function means: no work to do + INFO(threads, "function %p", t->function); if (t->function) t->function (t->arguments); + INFO(threads, "Thread awaken with state %d", t->state); lumiera_threadpool_park_thread(t); LUMIERA_RECCONDITION_WAIT(t->state != LUMIERA_THREADSTATE_IDLE); } while (t->state != LUMIERA_THREADSTATE_SHUTDOWN); // SHUTDOWN state - ECHO ("thread quitting"); + INFO(threads, "Thread Shutdown"); } return 0; } @@ -102,7 +105,8 @@ lumiera_thread_run (enum lumiera_thread_class kind, const char* purpose, struct nobug_flag* flag) { - REQUIRE (function, "invalid function"); + TRACE(threads); + // REQUIRE (function, "invalid function"); // ask the threadpool for a thread (it might create a new one) LumieraThread self = lumiera_threadpool_acquire_thread(kind, purpose, flag); @@ -158,6 +162,7 @@ lumiera_thread_new (enum lumiera_thread_class kind, LumieraThread lumiera_thread_destroy (LumieraThread self) { + TRACE(threads); REQUIRE (self, "trying to destroy an invalid thread"); llist_unlink (&self->node); @@ -186,6 +191,7 @@ lumiera_thread_destroy (LumieraThread self) void lumiera_thread_delete (LumieraThread self) { + TRACE(threads); ECHO ("deleting thread"); lumiera_free (lumiera_thread_destroy (self)); } diff --git a/src/backend/threads.h b/src/backend/threads.h index a55926123..9a4e6bbdf 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -34,6 +34,7 @@ //TODO: System includes// #include +NOBUG_DECLARE_FLAG (threads); /** From 88195087d6817cf631beb5dc07b3be9ef400f415 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 24 Dec 2009 01:54:49 +0100 Subject: [PATCH 10/48] recondition to condition, remove the mutex from the pool rename park to release :P --- src/backend/threadpool.c | 58 ++++++++++++++++++------------------ src/backend/threadpool.h | 8 ++--- src/backend/threads.c | 26 ++++++++-------- src/backend/threads.h | 4 +-- tests/backend/test-threads.c | 22 +++++++------- 5 files changed, 57 insertions(+), 61 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 706f5bb3b..8b86617ff 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -57,12 +57,10 @@ lumiera_threadpool_init() //TODO: configure each pools' pthread_attrs appropriately pthread_attr_init (&threadpool.pool[i].pthread_attrs); - // cehteh prefers that threads are joinable by default - //pthread_attr_setdetachstate (&threadpool.pool[i].pthread_attrs, PTHREAD_CREATE_DETACHED); + // cehteh says that threads must be joinable //cancel... - lumiera_mutex_init(&threadpool.pool[i].lock,"pool of threads", &NOBUG_FLAG(threadpool)); - lumiera_reccondition_init (&threadpool.pool[i].signal, "thread-signal", &NOBUG_FLAG(threadpool)); + lumiera_condition_init (&threadpool.pool[i].sync, "threadpool", &NOBUG_FLAG(cond_sync)); } } @@ -74,7 +72,7 @@ lumiera_threadpool_destroy(void) for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { TRACE (threadpool, "destroying individual pool #%d", i); - LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[i].lock) + LUMIERA_CONDITION_SECTION (threadpool, &threadpool.pool[i].sync) { REQUIRE (0 == threadpool.pool[i].working_thread_count, "%d threads are running", threadpool.pool[i].working_thread_count); // TODO need to have a stronger assertion that no threads are really running because they will not even be in the list @@ -84,9 +82,8 @@ lumiera_threadpool_destroy(void) lumiera_thread_delete((LumieraThread)t); } } - ECHO ("destroying the pool mutex"); - lumiera_mutex_destroy (&threadpool.pool[i].lock, &NOBUG_FLAG (threadpool)); - ECHO ("pool mutex destroyed"); + + lumiera_condition_destroy (&threadpool.pool[i].sync, &NOBUG_FLAG (cond_sync)); pthread_attr_destroy (&threadpool.pool[i].pthread_attrs); } } @@ -100,16 +97,17 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, TRACE(threadpool); LumieraThread ret = NULL; REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "unknown pool kind specified: %d", kind); - LUMIERA_RECCONDITION_SECTION (threadpool, &threadpool.pool[kind].signal) - { - if (llist_is_empty (&threadpool.pool[kind].list)) - { - ret = lumiera_thread_new (kind, purpose, flag, - &threadpool.pool[kind].pthread_attrs); - threadpool.pool[kind].idle_thread_count++; - ENSURE (ret, "did not create a valid thread"); - LUMIERA_RECCONDITION_WAIT (!llist_is_empty (&threadpool.pool[kind].list)); + LUMIERA_CONDITION_SECTION (threadpool, &threadpool.pool[kind].sync) + { + if (llist_is_empty (&threadpool.pool[kind].list)) + { + + ret = lumiera_thread_new (kind, purpose, flag, + &threadpool.pool[kind].pthread_attrs); + ENSURE (ret, "did not create a valid thread"); + TODO("no error handling but let the resourcecollector do, no need for return the thread"); + LUMIERA_CONDITION_WAIT (!llist_is_empty (&threadpool.pool[kind].list)); } // use an existing thread, pick the first one // remove it from the pool's list @@ -129,7 +127,7 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, // TODO: rename to lumiera_threadpool_park_thread void -lumiera_threadpool_park_thread(LumieraThread thread) +lumiera_threadpool_release_thread(LumieraThread thread) { TRACE(threadpool); REQUIRE (thread, "invalid thread given"); @@ -137,20 +135,22 @@ lumiera_threadpool_park_thread(LumieraThread thread) REQUIRE (thread->state != LUMIERA_THREADSTATE_IDLE, "trying to park an already idle thread"); - LUMIERA_RECCONDITION_SECTION (threadpool, &threadpool.pool[thread->kind].signal) + LUMIERA_CONDITION_SECTION (threadpool, &threadpool.pool[thread->kind].sync) { thread->state = LUMIERA_THREADSTATE_IDLE; - REQUIRE (llist_is_single(&thread->node), "thread already belongs to some list"); + REQUIRE (!llist_is_empty(&thread->node), "thread already belongs to some list"); llist_insert_head(&threadpool.pool[thread->kind].list, &thread->node); - threadpool.pool[thread->kind].working_thread_count--; - threadpool.pool[thread->kind].idle_thread_count++; // cheaper than using llist_count - ENSURE (threadpool.pool[thread->kind].idle_thread_count == - llist_count(&threadpool.pool[thread->kind].list), - "idle thread count %d is wrong, should be %d", - threadpool.pool[thread->kind].idle_thread_count, - llist_count(&threadpool.pool[thread->kind].list)); - // REQUIRE (!llist_is_empty (&threadpool.pool[thread->kind].list), "thread pool is still empty after insertion"); - LUMIERA_RECCONDITION_BROADCAST; + + threadpool.pool[thread->kind].working_thread_count--; + threadpool.pool[thread->kind].idle_thread_count++; // cheaper than using llist_count + + ENSURE (threadpool.pool[thread->kind].idle_thread_count == + llist_count(&threadpool.pool[thread->kind].list), + "idle thread count %d is wrong, should be %d", + threadpool.pool[thread->kind].idle_thread_count, + llist_count(&threadpool.pool[thread->kind].list)); + REQUIRE (!llist_is_empty (&threadpool.pool[thread->kind].list), "thread pool is still empty after insertion"); + LUMIERA_CONDITION_BROADCAST; } } diff --git a/src/backend/threadpool.h b/src/backend/threadpool.h index 572727e3e..a8fa457c5 100644 --- a/src/backend/threadpool.h +++ b/src/backend/threadpool.h @@ -23,9 +23,8 @@ #define LUMIERA_THREADPOOL_H //TODO: Support library includes// -#include "lib/reccondition.h" +#include "lib/condition.h" #include "lib/llist.h" -#include "lib/mutex.h" //TODO: Forward declarations// @@ -60,7 +59,7 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, * This function doesn't need to be accessible outside of the threadpool implementation. */ void -lumiera_threadpool_park_thread(LumieraThread thread); +lumiera_threadpool_release_thread(LumieraThread thread); typedef struct lumiera_threadpool_struct lumiera_threadpool; typedef lumiera_threadpool* LumieraThreadpool; @@ -70,11 +69,10 @@ struct lumiera_threadpool_struct struct { llist list; - lumiera_mutex lock; unsigned working_thread_count; unsigned idle_thread_count; pthread_attr_t pthread_attrs; - lumiera_reccondition signal; + lumiera_condition sync; } pool[LUMIERA_THREADCLASS_COUNT]; }; diff --git a/src/backend/threads.c b/src/backend/threads.c index a34dcde4a..a7f09b763 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -22,7 +22,6 @@ //TODO: Support library includes// #include "include/logging.h" -#include "lib/mutex.h" #include "lib/safeclib.h" @@ -64,7 +63,7 @@ struct lumiera_thread_mockup { void (*fn)(void*); void* arg; - LumieraReccondition finished; + LumieraCondition finished; }; static void* thread_loop (void* thread) @@ -73,21 +72,20 @@ static void* thread_loop (void* thread) LumieraThread t = (LumieraThread)thread; pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL); - + REQUIRE (t, "thread does not exist"); - ECHO ("entering section 1"); // this seems to deadlock unexpectedly: - LUMIERA_RECCONDITION_SECTION (threads, &t->signal) + LUMIERA_CONDITION_SECTION (threads, &t->signal) { do { // NULL function means: no work to do INFO(threads, "function %p", t->function); if (t->function) t->function (t->arguments); + lumiera_threadpool_release_thread(t); + LUMIERA_CONDITION_WAIT(t->state != LUMIERA_THREADSTATE_IDLE); INFO(threads, "Thread awaken with state %d", t->state); - lumiera_threadpool_park_thread(t); - LUMIERA_RECCONDITION_WAIT(t->state != LUMIERA_THREADSTATE_IDLE); } while (t->state != LUMIERA_THREADSTATE_SHUTDOWN); // SHUTDOWN state @@ -117,9 +115,9 @@ lumiera_thread_run (enum lumiera_thread_class kind, // and let it really run (signal the condition var, the thread waits on it) self->state = LUMIERA_THREADSTATE_WAKEUP; - ECHO ("entering section 2"); - LUMIERA_RECCONDITION_SECTION(threads, &self->signal) - LUMIERA_RECCONDITION_BROADCAST; + + LUMIERA_CONDITION_SECTION(threads, &self->signal) + LUMIERA_CONDITION_SIGNAL; // NOTE: example only, add solid error handling! @@ -142,7 +140,7 @@ lumiera_thread_new (enum lumiera_thread_class kind, LumieraThread self = lumiera_malloc (sizeof (*self)); llist_init(&self->node); - lumiera_reccondition_init (&self->signal, "thread-control", flag); + lumiera_condition_init (&self->signal, "thread-control", flag); self->kind = kind; self->state = LUMIERA_THREADSTATE_STARTUP; self->function = NULL; @@ -170,20 +168,20 @@ lumiera_thread_destroy (LumieraThread self) // get the pthread out of the processing loop // need to signal to the thread that it should start quitting // should this be within the section? - LUMIERA_RECCONDITION_SECTION(threads, &self->signal) + LUMIERA_CONDITION_SECTION(threads, &self->signal) { REQUIRE (self->state == LUMIERA_THREADSTATE_IDLE, "trying to delete a thread in state other than IDLE (%s)", lumiera_threadstate_names[self->state]); self->state = LUMIERA_THREADSTATE_SHUTDOWN; self->function = NULL; self->arguments = NULL; - LUMIERA_RECCONDITION_SIGNAL; + LUMIERA_CONDITION_SIGNAL; } int error = pthread_join(self->id, NULL); ENSURE (0 == error, "pthread_join returned %d:%s", error, strerror(error)); // condition has to be destroyed after joining with the thread - lumiera_reccondition_destroy (&self->signal, &NOBUG_FLAG(threads)); + lumiera_condition_destroy (&self->signal, &NOBUG_FLAG(threads)); return self; } diff --git a/src/backend/threads.h b/src/backend/threads.h index 9a4e6bbdf..d4282da17 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -23,7 +23,7 @@ #define LUMIERA_THREADS_H //TODO: Support library includes// -#include "lib/reccondition.h" +#include "lib/condition.h" //TODO: Forward declarations// @@ -132,7 +132,7 @@ struct lumiera_thread_struct // void* arg; pthread_t id; // TODO: maybe this condition variable should be renamed when we have a better understanding of how it will be used - lumiera_reccondition signal; // control signal, state change signal + lumiera_condition signal; // control signal, state change signal // the following member could have been called "class" except that it would conflict with C++ keyword // as consequence, it's been decided to leave the type name containing the word "class", // while all members/variables called "kind" diff --git a/tests/backend/test-threads.c b/tests/backend/test-threads.c index 21786ae8b..ddf43214e 100644 --- a/tests/backend/test-threads.c +++ b/tests/backend/test-threads.c @@ -47,15 +47,15 @@ void threadfn(void* blah) void threadsyncfn(void* blah) { struct timespec wait = {0,200000000}; - LumieraReccondition sync = (LumieraReccondition) blah; + LumieraCondition sync = (LumieraCondition) blah; ECHO ("thread starting up %s", NOBUG_THREAD_ID_GET); - LUMIERA_RECCONDITION_SECTION(cond_sync, sync) + LUMIERA_CONDITION_SECTION(cond_sync, sync) { ECHO ("send startup signal %s", NOBUG_THREAD_ID_GET); - LUMIERA_RECCONDITION_SIGNAL; + LUMIERA_CONDITION_SIGNAL; ECHO ("wait for trigger %s", NOBUG_THREAD_ID_GET); - LUMIERA_RECCONDITION_WAIT(1); + LUMIERA_CONDITION_WAIT(1); } ECHO ("thread running %s", NOBUG_THREAD_ID_GET); @@ -101,10 +101,10 @@ TEST ("simple_thread") TEST ("thread_synced") { - lumiera_reccondition cnd; - lumiera_reccondition_init (&cnd, "threadsync", &NOBUG_FLAG(NOBUG_ON)); + lumiera_condition cnd; + lumiera_condition_init (&cnd, "threadsync", &NOBUG_FLAG(NOBUG_ON)); - LUMIERA_RECCONDITION_SECTION(cond_sync, &cnd) + LUMIERA_CONDITION_SECTION(cond_sync, &cnd) { ECHO ("main before thread %s", NOBUG_THREAD_ID_GET); @@ -115,17 +115,17 @@ TEST ("thread_synced") NULL); ECHO ("main wait for thread being ready %s", NOBUG_THREAD_ID_GET); - LUMIERA_RECCONDITION_WAIT(1); + LUMIERA_CONDITION_WAIT(1); ECHO ("main trigger thread %s", NOBUG_THREAD_ID_GET); - LUMIERA_RECCONDITION_SIGNAL; + LUMIERA_CONDITION_SIGNAL; ECHO ("wait for thread end %s", NOBUG_THREAD_ID_GET); - LUMIERA_RECCONDITION_WAIT(1); + LUMIERA_CONDITION_WAIT(1); ECHO ("thread ended %s", NOBUG_THREAD_ID_GET); } - lumiera_reccondition_destroy (&cnd, &NOBUG_FLAG(NOBUG_ON)); + lumiera_condition_destroy (&cnd, &NOBUG_FLAG(NOBUG_ON)); } From a698128cfc75aba631f0dec8da1d45bfc63b0464 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 24 Dec 2009 01:55:24 +0100 Subject: [PATCH 11/48] new no-function test, sleep a bit before destroying the threadpool --- tests/backend/test-threadpool.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/backend/test-threadpool.c b/tests/backend/test-threadpool.c index ea5d60a76..b83920330 100644 --- a/tests/backend/test-threadpool.c +++ b/tests/backend/test-threadpool.c @@ -26,6 +26,7 @@ #include #include #include +#include void is_prime(void * arg) { @@ -158,6 +159,25 @@ TEST ("toomany-acquire-release") } #endif +TEST ("no-function") +{ + LumieraThread t; + + lumiera_threadpool_init(10); + + t = lumiera_thread_run (LUMIERA_THREADCLASS_INTERACTIVE, + NULL, + NULL, + "process my test function", + &NOBUG_FLAG(NOBUG_ON)); + + // cleanup + ECHO("wait 1 sec"); + usleep(1000000); + ECHO("finished waiting"); + lumiera_threadpool_destroy(); +} + TEST ("process-function") { // this is what the scheduler would do once it figures out what function a job needs to run @@ -175,6 +195,9 @@ TEST ("process-function") &NOBUG_FLAG(NOBUG_ON)); // struct nobug_flag* flag) // cleanup + ECHO("wait 1 sec"); + usleep(1000000); + ECHO("finished waiting"); lumiera_threadpool_destroy(); } From 12a2eed583634732479e0c976b63e79e8d66f8d2 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Tue, 29 Dec 2009 16:52:39 -0500 Subject: [PATCH 12/48] fix variable names in the LUMIERA_RECCONDITION_SECTION_CHAIN macro (seems like a copy+paste error from recmutex.h) --- src/lib/reccondition.h | 6 +++--- tests/15locking.tests | 9 +++++++++ tests/library/test-locking.c | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/lib/reccondition.h b/src/lib/reccondition.h index f9bcd59d1..51ce6ef07 100644 --- a/src/lib/reccondition.h +++ b/src/lib/reccondition.h @@ -65,13 +65,13 @@ #define LUMIERA_RECCONDITION_SECTION_CHAIN(nobugflag, cnd) \ - for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \ + for (lumiera_sectionlock *lumiera_reccond_section_old_ = &lumiera_reccond_section_, \ NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_reccond_section_ = { \ (void*)1, lumiera_reccondition_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ lumiera_reccond_section_.lock;) \ for ( \ ({ \ - REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ + REQUIRE (lumiera_reccond_section_old_->lock, "section prematurely unlocked"); \ lumiera_reccond_section_.lock = (cnd); \ NOBUG_IF_ALPHA(lumiera_reccond_section_.flag = &NOBUG_FLAG(nobugflag);) \ RESOURCE_WAIT (nobugflag, (cnd)->rh, "acquire reccondmutex", lumiera_reccond_section_.rh) \ @@ -79,7 +79,7 @@ if (pthread_mutex_lock (&(cnd)->reccndmutex)) \ LUMIERA_DIE (LOCK_ACQUIRE); \ RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_reccond_section_.rh); \ - LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ + LUMIERA_SECTION_UNLOCK_(lumiera_reccond_section_old_); \ } \ }); \ lumiera_reccond_section_.lock; \ diff --git a/tests/15locking.tests b/tests/15locking.tests index 0936499f2..7401d4b58 100644 --- a/tests/15locking.tests +++ b/tests/15locking.tests @@ -86,3 +86,12 @@ PLANNED "reccondition broadcasting" < Date: Thu, 31 Dec 2009 07:18:29 -0500 Subject: [PATCH 13/48] remove unused function pool_thread_loop() --- src/backend/threadpool.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 66ecd4e33..acde943e9 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -42,16 +42,6 @@ NOBUG_DEFINE_FLAG_PARENT (threadpool, threads_dbg); /*TODO insert a suitable/bet //code goes here// -void* pool_thread_loop(void * arg) -{ - (void) arg; - while (1) - { - ; - } - return arg; -} - void lumiera_threadpool_init(unsigned limit) { From 9c60d88c565dc8006cc71ca52223df1b63d9c197 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 31 Dec 2009 07:24:07 -0500 Subject: [PATCH 14/48] remove thread limiting logic from the threadpool --- src/backend/threadpool.c | 21 +++++---------------- src/backend/threadpool.h | 4 +--- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index acde943e9..3ab589179 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -43,12 +43,11 @@ NOBUG_DEFINE_FLAG_PARENT (threadpool, threads_dbg); /*TODO insert a suitable/bet //code goes here// void -lumiera_threadpool_init(unsigned limit) +lumiera_threadpool_init(void) { for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { llist_init(&threadpool.pool[i].list); - threadpool.pool[i].max_threads = limit; threadpool.pool[i].working_thread_count = 0; threadpool.pool[i].idle_thread_count = 0; @@ -90,20 +89,10 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, if (llist_is_empty (&threadpool.pool[kind].list)) { // TODO: fill in the reccondition argument, currently NULL - FIXME ("this max thread logic needs to be deeply thought about and made more efficient as well as rebust"); - if (threadpool.pool[kind].working_thread_count - + threadpool.pool[kind].idle_thread_count - < threadpool.pool[kind].max_threads) { - ret = lumiera_thread_new (kind, NULL, purpose, flag, - &threadpool.pool[kind].pthread_attrs); - threadpool.pool[kind].working_thread_count++; - ENSURE (ret, "did not create a valid thread"); - } - else - { - //ERROR (threadpool, "did not create a new thread because per-pool limit was reached: %d", threadpool.pool[kind].max_threads); - LUMIERA_DIE(ERRNO); - } + ret = lumiera_thread_new (kind, NULL, purpose, flag, + &threadpool.pool[kind].pthread_attrs); + threadpool.pool[kind].working_thread_count++; + ENSURE (ret, "did not create a valid thread"); } else { diff --git a/src/backend/threadpool.h b/src/backend/threadpool.h index 03b56a4fe..0c56de62d 100644 --- a/src/backend/threadpool.h +++ b/src/backend/threadpool.h @@ -71,7 +71,6 @@ struct lumiera_threadpool_struct { llist list; lumiera_mutex lock; - unsigned max_threads; unsigned working_thread_count; unsigned idle_thread_count; pthread_attr_t pthread_attrs; @@ -80,10 +79,9 @@ struct lumiera_threadpool_struct /** * Initialize the thread pool. - * @param limit the maximum number of threads (idle+working) allowed per pool */ void -lumiera_threadpool_init(unsigned limit); +lumiera_threadpool_init(void); void lumiera_threadpool_destroy(void); From d63a6066a0b8c5dfd592db321c5a12bd00ad81d5 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 31 Dec 2009 07:27:45 -0500 Subject: [PATCH 15/48] insert a space between the function name and the ( in each function call --- src/backend/threadpool.c | 24 ++++++++++++------------ src/backend/threads.c | 16 ++++++++-------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 3ab589179..55ae77842 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -47,7 +47,7 @@ lumiera_threadpool_init(void) { for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { - llist_init(&threadpool.pool[i].list); + llist_init (&threadpool.pool[i].list); threadpool.pool[i].working_thread_count = 0; threadpool.pool[i].idle_thread_count = 0; @@ -56,7 +56,7 @@ lumiera_threadpool_init(void) pthread_attr_setdetachstate (&threadpool.pool[i].pthread_attrs, PTHREAD_CREATE_DETACHED); //cancel... - lumiera_mutex_init(&threadpool.pool[i].lock,"pool of threads", &NOBUG_FLAG(threadpool)); + lumiera_mutex_init (&threadpool.pool[i].lock,"pool of threads", &NOBUG_FLAG (threadpool)); } } @@ -68,9 +68,9 @@ lumiera_threadpool_destroy(void) { ECHO ("destroying individual pool #%d", i); // no locking is done at this point - ECHO ("number of threads in the pool=%d", llist_count(&threadpool.pool[i].list)); - LLIST_WHILE_HEAD(&threadpool.pool[i].list, thread) - lumiera_thread_delete((LumieraThread)thread); + ECHO ("number of threads in the pool=%d", llist_count (&threadpool.pool[i].list)); + LLIST_WHILE_HEAD (&threadpool.pool[i].list, thread) + lumiera_thread_delete ((LumieraThread)thread); ECHO ("destroying the pool mutex"); lumiera_mutex_destroy (&threadpool.pool[i].lock, &NOBUG_FLAG (threadpool)); ECHO ("pool mutex destroyed"); @@ -100,14 +100,14 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, // remove it from the pool's list LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[kind].lock) { - ret = (LumieraThread)(llist_unlink(llist_head (&threadpool.pool[kind].list))); + ret = (LumieraThread)(llist_unlink (llist_head (&threadpool.pool[kind].list))); threadpool.pool[kind].working_thread_count++; threadpool.pool[kind].idle_thread_count--; // cheaper than using llist_count ENSURE (threadpool.pool[kind].idle_thread_count == - llist_count(&threadpool.pool[kind].list), + llist_count (&threadpool.pool[kind].list), "idle thread count %d is wrong, should be %d", threadpool.pool[kind].idle_thread_count, - llist_count(&threadpool.pool[kind].list)); + llist_count (&threadpool.pool[kind].list)); } ENSURE (ret, "did not find a valid thread"); } @@ -122,15 +122,15 @@ lumiera_threadpool_release_thread(LumieraThread thread) LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[thread->kind].lock) { - REQUIRE (llist_is_single(&thread->node), "thread already belongs to some list"); - llist_insert_head(&threadpool.pool[thread->kind].list, &thread->node); + REQUIRE (llist_is_single (&thread->node), "thread already belongs to some list"); + llist_insert_head (&threadpool.pool[thread->kind].list, &thread->node); threadpool.pool[thread->kind].working_thread_count--; threadpool.pool[thread->kind].idle_thread_count++; // cheaper than using llist_count ENSURE (threadpool.pool[thread->kind].idle_thread_count == - llist_count(&threadpool.pool[thread->kind].list), + llist_count (&threadpool.pool[thread->kind].list), "idle thread count %d is wrong, should be %d", threadpool.pool[thread->kind].idle_thread_count, - llist_count(&threadpool.pool[thread->kind].list)); + llist_count (&threadpool.pool[thread->kind].list)); // REQUIRE (!llist_is_empty (&threadpool.pool[thread->kind].list), "thread pool is still empty after insertion"); } } diff --git a/src/backend/threads.c b/src/backend/threads.c index 62f0d14a6..ef45b1ee8 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -62,7 +62,7 @@ const char* lumiera_threadstate_names[] = { struct lumiera_thread_mockup { - void (*fn)(void*); + void (*fn) (void*); void* arg; LumieraReccondition finished; }; @@ -86,7 +86,7 @@ static void* pthread_runner (void* thread) if (!thread_end_notification) return NULL; // no signalling of thread termination desired - LUMIERA_RECCONDITION_SECTION(cond_sync, thread_end_notification) + LUMIERA_RECCONDITION_SECTION (cond_sync, thread_end_notification) LUMIERA_RECCONDITION_BROADCAST; return NULL; @@ -140,13 +140,13 @@ lumiera_thread_run (enum lumiera_thread_class kind, (void)function; (void)arg; // ask the threadpool for a thread (it might create a new one) - LumieraThread self = lumiera_threadpool_acquire_thread(kind, purpose, flag); + LumieraThread self = lumiera_threadpool_acquire_thread (kind, purpose, flag); // TODO: set the function and data to be run // lumiera_thread_set_func_data (self, start_routine, arg, purpose, flag); // and let it really run (signal the condition var, the thread waits on it) - LUMIERA_RECCONDITION_SECTION(cond_sync, self->finished) + LUMIERA_RECCONDITION_SECTION (cond_sync, self->finished) LUMIERA_RECCONDITION_SIGNAL; // NOTE: example only, add solid error handling! @@ -174,14 +174,14 @@ lumiera_thread_new (enum lumiera_thread_class kind, LumieraThread self = lumiera_malloc (sizeof (*self)); - llist_init(&self->node); + llist_init (&self->node); self->finished = finished; self->kind = kind; self->state = LUMIERA_THREADSTATE_IDLE; //REQUIRE (thread_loop); int error = pthread_create (&self->id, attrs, &thread_loop, self); - ENSURE(error == 0 || EAGAIN == error, "pthread returned %d:%s", error, strerror(error)); + ENSURE (error == 0 || EAGAIN == error, "pthread returned %d:%s", error, strerror (error)); if (error) { // error here can only be EAGAIN, given the above ENSURE @@ -197,9 +197,9 @@ lumiera_thread_destroy (LumieraThread self) REQUIRE (self, "trying to destroy an invalid thread"); // TODO: stop the pthread - llist_unlink(&self->node); + llist_unlink (&self->node); //finished = NULL; // or free(finished)? - lumiera_reccondition_destroy (self->finished, &NOBUG_FLAG(threads)); + lumiera_reccondition_destroy (self->finished, &NOBUG_FLAG (threads)); //kind = 0; //state = 0; return self; From ad404bd41a91f1958ae76a620b8c07eaa722a868 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 31 Dec 2009 07:30:46 -0500 Subject: [PATCH 16/48] remove unused old code --- src/backend/threads.c | 58 ------------------------------------------- 1 file changed, 58 deletions(-) diff --git a/src/backend/threads.c b/src/backend/threads.c index ef45b1ee8..3a20901d8 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -60,70 +60,12 @@ const char* lumiera_threadstate_names[] = { }; #undef LUMIERA_THREAD_STATE -struct lumiera_thread_mockup -{ - void (*fn) (void*); - void* arg; - LumieraReccondition finished; -}; - static void* thread_loop (void* arg) { (void)arg; return 0; } -#if 0 -static void* pthread_runner (void* thread) -{ - pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL); - - struct lumiera_thread_mockup* starter = (struct lumiera_thread_mockup*) thread; - LumieraReccondition thread_end_notification = starter->finished; - - starter->fn (starter->arg); - - if (!thread_end_notification) - return NULL; // no signalling of thread termination desired - - LUMIERA_RECCONDITION_SECTION (cond_sync, thread_end_notification) - LUMIERA_RECCONDITION_BROADCAST; - - return NULL; -} -#endif - -#if 0 -// TODO: rewrite this using lumiera_threadpool_acquire() -LumieraThread -lumiera_thread_run (enum lumiera_thread_class kind, - void (*start_routine)(void *), - void * arg, - LumieraReccondition finished, - const char* purpose, - struct nobug_flag* flag) -{ - (void) kind; - (void) purpose; - (void) flag; - - if (attr_once == PTHREAD_ONCE_INIT) - pthread_once (&attr_once, thread_attr_init); - - static struct lumiera_thread_mockup thread; - - thread.fn = start_routine; - thread.arg = arg; - thread.finished = finished; - - pthread_t dummy; - int error = pthread_create (&dummy, &attrs, pthread_runner, &thread); - - if (error) return 0; /////TODO temporary addition by Ichthyo; probably we'll set lumiera_error? - return (LumieraThread) 1; -} -#endif - // TODO: new implementation, remove the above one // maybe this shouldn't return LumieraThread at all // when this is called it should have already been decided that the function From c4e1fdaf9a239fa88af6bdfcdb8237db57c6f189 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 31 Dec 2009 07:32:55 -0500 Subject: [PATCH 17/48] document lumiera_thread_destroy() and lumiera_thread_delete() --- src/backend/threads.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/backend/threads.h b/src/backend/threads.h index e8b774299..303b9acf2 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -142,9 +142,17 @@ lumiera_thread_new (enum lumiera_thread_class kind, struct nobug_flag* flag, pthread_attr_t* attrs); +/** + * Destroy and de-initialize a thread structure. + * Memory is not freed by this function. + */ LumieraThread lumiera_thread_destroy (LumieraThread self); +/** + * Actually free the memory used by the thread structure. + * Make sure to destroy the structure first. + */ void lumiera_thread_delete (LumieraThread self); From 03fe6dd65831a6c6d52a23048cc916586de5e552 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 31 Dec 2009 07:37:28 -0500 Subject: [PATCH 18/48] properly initialize and de-initialize the thread condition variable --- src/backend/threads.c | 9 +-------- src/backend/threads.h | 4 ---- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/backend/threads.c b/src/backend/threads.c index 3a20901d8..7b03f57fe 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -74,11 +74,9 @@ LumieraThread lumiera_thread_run (enum lumiera_thread_class kind, void (*function)(void *), void * arg, - LumieraReccondition finished, const char* purpose, struct nobug_flag* flag) { - (void)finished; (void)function; (void)arg; // ask the threadpool for a thread (it might create a new one) @@ -101,7 +99,6 @@ lumiera_thread_run (enum lumiera_thread_class kind, */ LumieraThread lumiera_thread_new (enum lumiera_thread_class kind, - LumieraReccondition finished, const char* purpose, struct nobug_flag* flag, pthread_attr_t* attrs) @@ -112,12 +109,9 @@ lumiera_thread_new (enum lumiera_thread_class kind, REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "invalid thread kind specified: %d", kind); REQUIRE (attrs, "invalid pthread attributes structure passed"); - //REQUIRE (finished, "invalid finished flag passed"); - - LumieraThread self = lumiera_malloc (sizeof (*self)); llist_init (&self->node); - self->finished = finished; + lumiera_reccondition_init (&self->finished, "thread-control-condition", flag); self->kind = kind; self->state = LUMIERA_THREADSTATE_IDLE; @@ -140,7 +134,6 @@ lumiera_thread_destroy (LumieraThread self) // TODO: stop the pthread llist_unlink (&self->node); - //finished = NULL; // or free(finished)? lumiera_reccondition_destroy (self->finished, &NOBUG_FLAG (threads)); //kind = 0; //state = 0; diff --git a/src/backend/threads.h b/src/backend/threads.h index 303b9acf2..d91ae7bee 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -137,7 +137,6 @@ struct lumiera_thread_struct */ LumieraThread lumiera_thread_new (enum lumiera_thread_class kind, - LumieraReccondition finished, const char* purpose, struct nobug_flag* flag, pthread_attr_t* attrs); @@ -169,8 +168,6 @@ lumiera_thread_delete (LumieraThread self); * @param kind class of the thread to start * @param function pointer to a function to execute in a thread (returning void, not void* as in pthreads) * @param arg generic pointer passed to the thread - * @param finished a condition variable to be broadcasted, if not NULL. - * The associated mutex should be locked at thread_run time already, else the signal can get lost. * @param purpose descriptive name of this thread, used by NoBug * @param flag NoBug flag used for logging the thread startup and return */ @@ -178,7 +175,6 @@ LumieraThread lumiera_thread_run (enum lumiera_thread_class kind, void (*function)(void *), void * arg, - LumieraReccondition finished, const char* purpose, struct nobug_flag* flag); From 7a507a0ceeb8298719b0d16f47987256d0e8d8cb Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 31 Dec 2009 15:09:22 -0500 Subject: [PATCH 19/48] don't put threads in a detached state --- src/backend/threadpool.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 55ae77842..fc6041b5f 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -53,7 +53,6 @@ lumiera_threadpool_init(void) //TODO: configure each pools' pthread_attrs appropriately pthread_attr_init (&threadpool.pool[i].pthread_attrs); - pthread_attr_setdetachstate (&threadpool.pool[i].pthread_attrs, PTHREAD_CREATE_DETACHED); //cancel... lumiera_mutex_init (&threadpool.pool[i].lock,"pool of threads", &NOBUG_FLAG (threadpool)); From 223e79cc4ad74bb4c308fee55adba710c45f87a3 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Mon, 4 Jan 2010 17:03:47 -0500 Subject: [PATCH 20/48] replace mutex with condition variable in threadpool use TRACE instead of ECHO (based on cehteh's suggested code) --- src/backend/threadpool.c | 99 +++++++++++++++++++++++----------------- src/backend/threadpool.h | 5 +- 2 files changed, 58 insertions(+), 46 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index fc6041b5f..6a4f90289 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -45,6 +45,9 @@ NOBUG_DEFINE_FLAG_PARENT (threadpool, threads_dbg); /*TODO insert a suitable/bet void lumiera_threadpool_init(void) { + NOBUG_INIT_FLAG (threadpool); + TRACE (threadpool); + for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { llist_init (&threadpool.pool[i].list); @@ -55,24 +58,28 @@ lumiera_threadpool_init(void) pthread_attr_init (&threadpool.pool[i].pthread_attrs); //cancel... - lumiera_mutex_init (&threadpool.pool[i].lock,"pool of threads", &NOBUG_FLAG (threadpool)); + lumiera_condition_init (&threadpool.pool[i].sync,"pool of threads", &NOBUG_FLAG (threadpool)); } } void lumiera_threadpool_destroy(void) { - ECHO ("destroying threadpool"); + TRACE (threadpool); for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { - ECHO ("destroying individual pool #%d", i); - // no locking is done at this point - ECHO ("number of threads in the pool=%d", llist_count (&threadpool.pool[i].list)); - LLIST_WHILE_HEAD (&threadpool.pool[i].list, thread) - lumiera_thread_delete ((LumieraThread)thread); - ECHO ("destroying the pool mutex"); - lumiera_mutex_destroy (&threadpool.pool[i].lock, &NOBUG_FLAG (threadpool)); - ECHO ("pool mutex destroyed"); + TRACE (threadpool, "destroying individual pool #%d", i); + LUMIERA_CONDITION_SECTION (threadpool, &threadpool.pool[i].sync) + { + REQUIRE (0 == threadpool.pool[i].working_thread_count, "%d threads are still running", threadpool.pool[i].working_thread_count); + // TODO need to have a stronger assertion that no threads are really running because they will not even be in the list + INFO (threadpool, "number of threads in the pool=%d", llist_count(&threadpool.pool[i].list)); + LLIST_WHILE_HEAD (&threadpool.pool[i].list, t) + { + lumiera_thread_delete ((LumieraThread)t); + } + } + lumiera_condition_destroy (&threadpool.pool[i].sync, &NOBUG_FLAG (threadpool)); pthread_attr_destroy (&threadpool.pool[i].pthread_attrs); } } @@ -82,55 +89,61 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, const char* purpose, struct nobug_flag* flag) { - LumieraThread ret; + TRACE (threadpool); + LumieraThread ret = NULL; REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "unknown pool kind specified: %d", kind); - if (llist_is_empty (&threadpool.pool[kind].list)) + + LUMIERA_CONDITION_SECTION (threadpool, &threadpool.pool[kind].sync) { - // TODO: fill in the reccondition argument, currently NULL - ret = lumiera_thread_new (kind, NULL, purpose, flag, - &threadpool.pool[kind].pthread_attrs); + if (llist_is_empty (&threadpool.pool[kind].list)) + { + ret = lumiera_thread_new (kind, purpose, flag, + &threadpool.pool[kind].pthread_attrs); + ENSURE (ret, "did not create a valid thread"); + TODO ("no error handing, let the resourcecollector do it, no need when returning the thread"); + LUMIERA_CONDITION_WAIT (!llist_is_empty (&threadpool.pool[kind].list)); + } + // use an existing thread, pick the first one + // remove it from the pool's list + ret = (LumieraThread)(llist_unlink (llist_head (&threadpool.pool[kind].list))); + REQUIRE (ret->state == LUMIERA_THREADSTATE_IDLE, "trying to return a non-idle thread (state=%s)", lumiera_threadstate_names[ret->state]); threadpool.pool[kind].working_thread_count++; - ENSURE (ret, "did not create a valid thread"); + threadpool.pool[kind].idle_thread_count--; // cheaper than using llist_count + ENSURE (threadpool.pool[kind].idle_thread_count == + llist_count (&threadpool.pool[kind].list), + "idle thread count %d is wrong, should be %d", + threadpool.pool[kind].idle_thread_count, + llist_count (&threadpool.pool[kind].list)); + ENSURE (ret, "did not find a valid thread"); } - else - { - // use an existing thread, pick the first one - // remove it from the pool's list - LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[kind].lock) - { - ret = (LumieraThread)(llist_unlink (llist_head (&threadpool.pool[kind].list))); - threadpool.pool[kind].working_thread_count++; - threadpool.pool[kind].idle_thread_count--; // cheaper than using llist_count - ENSURE (threadpool.pool[kind].idle_thread_count == - llist_count (&threadpool.pool[kind].list), - "idle thread count %d is wrong, should be %d", - threadpool.pool[kind].idle_thread_count, - llist_count (&threadpool.pool[kind].list)); - } - ENSURE (ret, "did not find a valid thread"); - } return ret; } void lumiera_threadpool_release_thread(LumieraThread thread) { + TRACE (threadpool); REQUIRE (thread, "invalid thread given"); REQUIRE (thread->kind < LUMIERA_THREADCLASS_COUNT, "thread belongs to an unknown pool kind: %d", thread->kind); - LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[thread->kind].lock) + REQUIRE (thread->state != LUMIERA_THREADSTATE_IDLE, "trying to park an already idle thread"); + LUMIERA_CONDITION_SECTION (threadpool, &threadpool.pool[thread->kind].sync) { - REQUIRE (llist_is_single (&thread->node), "thread already belongs to some list"); + thread->state = LUMIERA_THREADSTATE_IDLE; + REQUIRE (llist_is_empty (&thread->node), "thread already belongs to some list"); llist_insert_head (&threadpool.pool[thread->kind].list, &thread->node); - threadpool.pool[thread->kind].working_thread_count--; - threadpool.pool[thread->kind].idle_thread_count++; // cheaper than using llist_count - ENSURE (threadpool.pool[thread->kind].idle_thread_count == - llist_count (&threadpool.pool[thread->kind].list), - "idle thread count %d is wrong, should be %d", - threadpool.pool[thread->kind].idle_thread_count, - llist_count (&threadpool.pool[thread->kind].list)); - // REQUIRE (!llist_is_empty (&threadpool.pool[thread->kind].list), "thread pool is still empty after insertion"); + + threadpool.pool[thread->kind].working_thread_count--; + threadpool.pool[thread->kind].idle_thread_count++; // cheaper than using llist_count + + ENSURE (threadpool.pool[thread->kind].idle_thread_count == + llist_count (&threadpool.pool[thread->kind].list), + "idle thread count %d is wrong, should be %d", + threadpool.pool[thread->kind].idle_thread_count, + llist_count (&threadpool.pool[thread->kind].list)); + REQUIRE (!llist_is_empty (&threadpool.pool[thread->kind].list), "thread pool is still empty after insertion"); + LUMIERA_CONDITION_BROADCAST; } } diff --git a/src/backend/threadpool.h b/src/backend/threadpool.h index 0c56de62d..a14c87b50 100644 --- a/src/backend/threadpool.h +++ b/src/backend/threadpool.h @@ -23,9 +23,8 @@ #define LUMIERA_THREADPOOL_H //TODO: Support library includes// -#include "lib/reccondition.h" +#include "lib/condition.h" #include "lib/llist.h" -#include "lib/mutex.h" //TODO: Forward declarations// @@ -70,7 +69,7 @@ struct lumiera_threadpool_struct struct { llist list; - lumiera_mutex lock; + lumiera_condition sync; unsigned working_thread_count; unsigned idle_thread_count; pthread_attr_t pthread_attrs; From a668095f601cfad7a6c58c81d8fff6e30b34ae02 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Tue, 5 Jan 2010 20:11:34 -0500 Subject: [PATCH 21/48] ignore automake-related files in the m4 directory --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c89dffc5e..f66bd5b09 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ autom4te.cache semantic.cache wiki/backups/* doc/devel/draw/*.png +m4/* From c707f949295a85881f56bf312b6b8c165f8e7b4a Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Wed, 6 Jan 2010 07:42:42 -0500 Subject: [PATCH 22/48] update c++ wrapper to match the C API --- src/backend/thread-wrapper.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/backend/thread-wrapper.hpp b/src/backend/thread-wrapper.hpp index 3f897b582..7259e4fbc 100644 --- a/src/backend/thread-wrapper.hpp +++ b/src/backend/thread-wrapper.hpp @@ -177,10 +177,11 @@ namespace backend { lumiera_thread_run ( kind , &run // invoking the run helper and.. , this // passing this start context as parameter - , joinCond // maybe wait-blocking for the thread to terminate , purpose.c() , logging_flag ); + (void)joinCond; // TODO: this is a temporary fix to match the C API + // we might have to re-write more of this file or even remove it later if (!res) throw lumiera::error::State("failed to create new thread."); From 56cf53adb3fe2602e9a1e4ebed4dd84f3a35352e Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 7 Jan 2010 18:36:51 -0500 Subject: [PATCH 23/48] fix compilation --- src/backend/threads.c | 2 +- tests/backend/test-threadpool.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/backend/threads.c b/src/backend/threads.c index d7d7a242f..773568f7b 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -109,7 +109,7 @@ lumiera_thread_run (enum lumiera_thread_class kind, // and let it really run (signal the condition var, the thread waits on it) self->state = LUMIERA_THREADSTATE_WAKEUP; - LUMIERA_CONDITION_SECTION (cond_sync, self->finished) + LUMIERA_CONDITION_SECTION (cond_sync, &self->signal) LUMIERA_CONDITION_SIGNAL; // NOTE: example only, add solid error handling! diff --git a/tests/backend/test-threadpool.c b/tests/backend/test-threadpool.c index b83920330..2acb8b861 100644 --- a/tests/backend/test-threadpool.c +++ b/tests/backend/test-threadpool.c @@ -48,14 +48,14 @@ TESTS_BEGIN TEST ("threadpool-basic") { - lumiera_threadpool_init(100); + lumiera_threadpool_init(); lumiera_threadpool_destroy(); } TEST ("threadpool1") { ECHO("start by initializing the threadpool"); - lumiera_threadpool_init(100); + lumiera_threadpool_init(); LumieraThread t1 = lumiera_threadpool_acquire_thread(LUMIERA_THREADCLASS_INTERACTIVE, "test purpose", @@ -69,7 +69,7 @@ TEST ("threadpool1") TEST ("basic-acquire-release") { ECHO("start by initializing the threadpool"); - lumiera_threadpool_init(100); + lumiera_threadpool_init(); ECHO("acquiring thread 1"); LumieraThread t1 = lumiera_threadpool_acquire_thread(LUMIERA_THREADCLASS_INTERACTIVE, @@ -163,7 +163,7 @@ TEST ("no-function") { LumieraThread t; - lumiera_threadpool_init(10); + lumiera_threadpool_init(); t = lumiera_thread_run (LUMIERA_THREADCLASS_INTERACTIVE, NULL, @@ -184,7 +184,7 @@ TEST ("process-function") LumieraThread t; int number = 440616; - lumiera_threadpool_init(10); + lumiera_threadpool_init(); ECHO ("the input to the function is %d", number); From b679bfa236f1e33a41e6e18e82f91ba3db1b8376 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Fri, 8 Jan 2010 07:33:25 -0500 Subject: [PATCH 24/48] don't expect any more output from the basic test --- tests/30backend-threadpool.tests | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/tests/30backend-threadpool.tests b/tests/30backend-threadpool.tests index 2cad43477..bd59e0792 100644 --- a/tests/30backend-threadpool.tests +++ b/tests/30backend-threadpool.tests @@ -6,32 +6,6 @@ PLANNED "yield" PLANNED "cancel" TEST "Most basic threadpool test" threadpool-basic < Date: Fri, 8 Jan 2010 16:38:35 -0500 Subject: [PATCH 25/48] merge ECHO with TRACE --- src/backend/threads.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/backend/threads.c b/src/backend/threads.c index 773568f7b..1781832e3 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -182,8 +182,7 @@ lumiera_thread_destroy (LumieraThread self) void lumiera_thread_delete (LumieraThread self) { - TRACE(threads); - ECHO ("deleting thread"); + TRACE(threads, "deleting thread"); lumiera_free (lumiera_thread_destroy (self)); } From 925442b3d91321d508fd225afb9fb3efe81ffa44 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Sat, 9 Jan 2010 21:36:20 -0500 Subject: [PATCH 26/48] begin adding a second list to store working threads --- src/backend/threadpool.c | 13 +++++++++---- src/backend/threadpool.h | 3 ++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index b423d3e5a..346a847d2 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -52,7 +52,8 @@ lumiera_threadpool_init(void) for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { - llist_init (&threadpool.pool[i].list); + llist_init (&threadpool.pool[i].working_list); + llist_init (&threadpool.pool[i].idle_list); threadpool.pool[i].working_thread_count = 0; threadpool.pool[i].idle_thread_count = 0; @@ -74,10 +75,14 @@ lumiera_threadpool_destroy(void) TRACE (threadpool, "destroying individual pool #%d", i); LUMIERA_CONDITION_SECTION (threadpool, &threadpool.pool[i].sync) { - REQUIRE (0 == threadpool.pool[i].working_thread_count, "%d threads are still running", threadpool.pool[i].working_thread_count); + REQUIRE (0 == threadpool.pool[i].working_thread_count && + 0 = llist_count (&threadpool.pool[i].working_list), + "%d(%d) threads are still running", + threadpool.pool[i].working_thread_count, + llist_count (&threadpool.pool[i].working_list)); // TODO need to have a stronger assertion that no threads are really running because they will not even be in the list - INFO (threadpool, "number of threads in the pool=%d", llist_count (&threadpool.pool[i].list)); - LLIST_WHILE_HEAD (&threadpool.pool[i].list, t) + INFO (threadpool, "working threads count=%d, idle threads count=%d", llist_count (&threadpool.pool[i].working_list), llist_count (&threadpool.pool[i].idle_list)); + LLIST_WHILE_HEAD (&threadpool.pool[i].idle_list, t) { lumiera_thread_delete ((LumieraThread)t); } diff --git a/src/backend/threadpool.h b/src/backend/threadpool.h index c2ec10785..b3fb5a18e 100644 --- a/src/backend/threadpool.h +++ b/src/backend/threadpool.h @@ -68,7 +68,8 @@ struct lumiera_threadpool_struct { struct { - llist list; + llist working_list; + llist working_idle; unsigned working_thread_count; unsigned idle_thread_count; pthread_attr_t pthread_attrs; From f890b35a039134145dddb224a49bf4c71bc51d3e Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Mon, 11 Jan 2010 15:04:52 -0500 Subject: [PATCH 27/48] continuation of working_list introduction --- src/backend/threadpool.c | 31 ++++++++++++++++++++++++------- src/backend/threadpool.h | 2 +- src/backend/threads.c | 3 +++ 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 346a847d2..f08bfd0e0 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -105,26 +105,37 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, LUMIERA_CONDITION_SECTION (threadpool, &threadpool.pool[kind].sync) { - if (llist_is_empty (&threadpool.pool[kind].list)) + if (llist_is_empty (&threadpool.pool[kind].idle_list)) { ret = lumiera_thread_new (kind, purpose, flag, &threadpool.pool[kind].pthread_attrs); ENSURE (ret, "did not create a valid thread"); TODO ("no error handing, let the resourcecollector do it, no need when returning the thread"); - LUMIERA_CONDITION_WAIT (!llist_is_empty (&threadpool.pool[kind].list)); + LUMIERA_CONDITION_WAIT (!llist_is_empty (&threadpool.pool[kind].idel_list)); } // use an existing thread, pick the first one // remove it from the pool's list - ret = (LumieraThread)(llist_unlink (llist_head (&threadpool.pool[kind].list))); + ret = (LumieraThread)(llist_unlink (llist_head (&threadpool.pool[kind].idle_list))); + + ENSURE (ret, "did not find a valid thread"); + REQUIRE (ret->state == LUMIERA_THREADSTATE_IDLE, "trying to return a non-idle thread (state=%s)", lumiera_threadstate_names[ret->state]); + + llist_insert_head (&threadpool.pool[kind].working_list, ret); + threadpool.pool[kind].working_thread_count++; threadpool.pool[kind].idle_thread_count--; // cheaper than using llist_count + ENSURE (threadpool.pool[kind].working_thread_count == + llist_count (&threadpool.pool[kind].working_list), + "working thread count %d is wrong, should be %d", + threadpool.pool[kind].working_thread_count, + llist_count (&threadpool.pool[kind].working_list)); + ENSURE (threadpool.pool[kind].idle_thread_count == - llist_count (&threadpool.pool[kind].list), + llist_count (&threadpool.pool[kind].idle_list), "idle thread count %d is wrong, should be %d", threadpool.pool[kind].idle_thread_count, - llist_count (&threadpool.pool[kind].list)); - ENSURE (ret, "did not find a valid thread"); + llist_count (&threadpool.pool[kind].idle_list)); } return ret; } @@ -142,7 +153,8 @@ lumiera_threadpool_release_thread(LumieraThread thread) { thread->state = LUMIERA_THREADSTATE_IDLE; REQUIRE (llist_is_empty (&thread->node), "thread already belongs to some list"); - llist_insert_head (&threadpool.pool[thread->kind].list, &thread->node); + llist_unlink (&thread); // remove thread from the working_list + llist_insert_head (&threadpool.pool[thread->kind].idle_list, &thread->node); threadpool.pool[thread->kind].working_thread_count--; threadpool.pool[thread->kind].idle_thread_count++; // cheaper than using llist_count @@ -152,6 +164,11 @@ lumiera_threadpool_release_thread(LumieraThread thread) "idle thread count %d is wrong, should be %d", threadpool.pool[thread->kind].idle_thread_count, llist_count (&threadpool.pool[thread->kind].list)); + ENSURE (threadpool.pool[thread->kind].working_thread_count == + llist_count (&threadpool.pool[thread->kind].working_list), + "working thread count %d is wrong, should be %d", + threadpool.pool[thread->kind].working_thread_count, + llist_count (&threadpool.pool[thread->kind].workinglist)); REQUIRE (!llist_is_empty (&threadpool.pool[thread->kind].list), "thread pool is still empty after insertion"); LUMIERA_CONDITION_BROADCAST; } diff --git a/src/backend/threadpool.h b/src/backend/threadpool.h index b3fb5a18e..ac3a52ad2 100644 --- a/src/backend/threadpool.h +++ b/src/backend/threadpool.h @@ -69,7 +69,7 @@ struct lumiera_threadpool_struct struct { llist working_list; - llist working_idle; + llist idle_list; unsigned working_thread_count; unsigned idle_thread_count; pthread_attr_t pthread_attrs; diff --git a/src/backend/threads.c b/src/backend/threads.c index 1781832e3..5c8d69eba 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -76,6 +76,9 @@ static void* thread_loop (void* thread) INFO(threads, "function %p", t->function); if (t->function) t->function (t->arguments); + // TODO: problem: + // calling release on a not-yet properly setup thread + // threadpool.pool[thread->kind].working_thread_count == 0 lumiera_threadpool_release_thread(t); LUMIERA_CONDITION_WAIT(t->state != LUMIERA_THREADSTATE_IDLE); INFO(threads, "Thread awaken with state %d", t->state); From ecbcfdefd78adbcef60f7a2b62f8f98d77494976 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Tue, 12 Jan 2010 07:39:12 -0500 Subject: [PATCH 28/48] remote unnecessary calls to llist_unlink() insert is enough --- src/backend/threadpool.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index f08bfd0e0..c0757a28d 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -115,12 +115,13 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, } // use an existing thread, pick the first one // remove it from the pool's list - ret = (LumieraThread)(llist_unlink (llist_head (&threadpool.pool[kind].idle_list))); + ret = (LumieraThread) (llist_head (&threadpool.pool[kind].idle_list)); ENSURE (ret, "did not find a valid thread"); REQUIRE (ret->state == LUMIERA_THREADSTATE_IDLE, "trying to return a non-idle thread (state=%s)", lumiera_threadstate_names[ret->state]); + // move thread to the working_list llist_insert_head (&threadpool.pool[kind].working_list, ret); threadpool.pool[kind].working_thread_count++; @@ -153,7 +154,7 @@ lumiera_threadpool_release_thread(LumieraThread thread) { thread->state = LUMIERA_THREADSTATE_IDLE; REQUIRE (llist_is_empty (&thread->node), "thread already belongs to some list"); - llist_unlink (&thread); // remove thread from the working_list + // move thread to the idle_list llist_insert_head (&threadpool.pool[thread->kind].idle_list, &thread->node); threadpool.pool[thread->kind].working_thread_count--; From b49a5abff271723479b3807c191b6574aecb4431 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Tue, 12 Jan 2010 07:47:28 -0500 Subject: [PATCH 29/48] mark thread as worker --- src/backend/threads.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/threads.c b/src/backend/threads.c index 5c8d69eba..ea565ca0a 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -62,6 +62,7 @@ const char* lumiera_threadstate_names[] = { static void* thread_loop (void* thread) { TRACE(threads); + NOBUG_THREAD_ID_SET("worker"); LumieraThread t = (LumieraThread)thread; pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL); From 09fd15d5f84529b9baae60136c8e4cd00656fcc0 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Tue, 12 Jan 2010 08:01:54 -0500 Subject: [PATCH 30/48] die regardless of what type of failure pthread_create() encounters --- src/backend/threads.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/backend/threads.c b/src/backend/threads.c index ea565ca0a..74efb6687 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -144,11 +144,8 @@ lumiera_thread_new (enum lumiera_thread_class kind, self->arguments = NULL; int error = pthread_create (&self->id, attrs, &thread_loop, self); - ENSURE(error == 0 || EAGAIN == error, "pthread_create returned %d:%s", error, strerror(error)); if (error) { - // error here can only be EAGAIN, given the above ENSURE - FIXME ("error is %d:%s, see if this can be improved", error, strerror(error)); LUMIERA_DIE (ERRNO); } return self; From f62513dea89550c74a9e09c1bcd5e7d3fe5dc1e5 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 14 Jan 2010 16:46:27 -0500 Subject: [PATCH 31/48] fix compilation errors --- src/backend/threadpool.c | 14 +++++++------- src/lib/condition.h | 4 ++-- src/proc/mobject/placement.hpp | 1 + src/proc/mobject/session/placement-index.cpp | 3 ++- src/proc/mobject/session/placement-index.hpp | 3 ++- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index c0757a28d..ce8a7d3e9 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -76,7 +76,7 @@ lumiera_threadpool_destroy(void) LUMIERA_CONDITION_SECTION (threadpool, &threadpool.pool[i].sync) { REQUIRE (0 == threadpool.pool[i].working_thread_count && - 0 = llist_count (&threadpool.pool[i].working_list), + 0 == llist_count (&threadpool.pool[i].working_list), "%d(%d) threads are still running", threadpool.pool[i].working_thread_count, llist_count (&threadpool.pool[i].working_list)); @@ -111,7 +111,7 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, &threadpool.pool[kind].pthread_attrs); ENSURE (ret, "did not create a valid thread"); TODO ("no error handing, let the resourcecollector do it, no need when returning the thread"); - LUMIERA_CONDITION_WAIT (!llist_is_empty (&threadpool.pool[kind].idel_list)); + LUMIERA_CONDITION_WAIT (!llist_is_empty (&threadpool.pool[kind].idle_list)); } // use an existing thread, pick the first one // remove it from the pool's list @@ -122,7 +122,7 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, REQUIRE (ret->state == LUMIERA_THREADSTATE_IDLE, "trying to return a non-idle thread (state=%s)", lumiera_threadstate_names[ret->state]); // move thread to the working_list - llist_insert_head (&threadpool.pool[kind].working_list, ret); + llist_insert_head (&threadpool.pool[kind].working_list, &ret->node); threadpool.pool[kind].working_thread_count++; threadpool.pool[kind].idle_thread_count--; // cheaper than using llist_count @@ -161,16 +161,16 @@ lumiera_threadpool_release_thread(LumieraThread thread) threadpool.pool[thread->kind].idle_thread_count++; // cheaper than using llist_count ENSURE (threadpool.pool[thread->kind].idle_thread_count == - llist_count (&threadpool.pool[thread->kind].list), + llist_count (&threadpool.pool[thread->kind].idle_list), "idle thread count %d is wrong, should be %d", threadpool.pool[thread->kind].idle_thread_count, - llist_count (&threadpool.pool[thread->kind].list)); + llist_count (&threadpool.pool[thread->kind].idle_list)); ENSURE (threadpool.pool[thread->kind].working_thread_count == llist_count (&threadpool.pool[thread->kind].working_list), "working thread count %d is wrong, should be %d", threadpool.pool[thread->kind].working_thread_count, - llist_count (&threadpool.pool[thread->kind].workinglist)); - REQUIRE (!llist_is_empty (&threadpool.pool[thread->kind].list), "thread pool is still empty after insertion"); + llist_count (&threadpool.pool[thread->kind].working_list)); + REQUIRE (!llist_is_empty (&threadpool.pool[thread->kind].idle_list), "thread pool is still empty after insertion"); LUMIERA_CONDITION_BROADCAST; } } diff --git a/src/lib/condition.h b/src/lib/condition.h index 293d0143e..d75844144 100644 --- a/src/lib/condition.h +++ b/src/lib/condition.h @@ -123,7 +123,7 @@ */ #define LUMIERA_CONDITION_SIGNAL \ do { \ - REQUIRE (lumiera_cond_section_.lock, "Condition mutex not locked"); \ + REQUIRE (lumiera_lock_section_.lock, "Condition mutex not locked"); \ lumiera_condition_signal (lumiera_lock_section_.lock, \ lumiera_lock_section_.flag); \ } while (0) @@ -136,7 +136,7 @@ */ #define LUMIERA_CONDITION_BROADCAST \ do { \ - REQUIRE (lumiera_cond_section_.lock, "Condition mutex not locked"); \ + REQUIRE (lumiera_lock_section_.lock, "Condition mutex not locked"); \ lumiera_condition_broadcast (lumiera_lock_section_.lock, \ lumiera_lock_section_.flag); \ } while (0) diff --git a/src/proc/mobject/placement.hpp b/src/proc/mobject/placement.hpp index 1ebb966ac..569dc6686 100644 --- a/src/proc/mobject/placement.hpp +++ b/src/proc/mobject/placement.hpp @@ -242,6 +242,7 @@ namespace mobject { /** @todo cleanup uses of ref-to-placement. See Ticket #115 */ typedef Placement PlacementMO; + //‘typedef class mobject::Placement mobject::PlacementMO’ typedef Placement PMO; diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp index f55e6fc3a..adbad89b8 100644 --- a/src/proc/mobject/session/placement-index.cpp +++ b/src/proc/mobject/session/placement-index.cpp @@ -95,7 +95,8 @@ namespace session { /* some type shorthands */ - typedef PlacementIndex::PlacementMO PlacementMO; + //typedef PlacementIndex::PlacementMO PlacementMO; + typedef mobject::PlacementMO PlacementMO; typedef PlacementIndex::PRef PRef; typedef PlacementIndex::ID ID; diff --git a/src/proc/mobject/session/placement-index.hpp b/src/proc/mobject/session/placement-index.hpp index a8df50b2a..537212a8d 100644 --- a/src/proc/mobject/session/placement-index.hpp +++ b/src/proc/mobject/session/placement-index.hpp @@ -160,7 +160,8 @@ namespace session { public: - typedef Placement PlacementMO; + //typedef Placement PlacementMO; + // ‘typedef class mobject::Placement mobject::session::PlacementIndex::PlacementMO’ typedef PlacementRef PRef; typedef PlacementMO::ID const& ID; From 1db2a4733997e3937eb77f4fe48addd229206424 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 15 Jan 2010 03:27:09 +0100 Subject: [PATCH 32/48] python-2.6 fix: loading the icon_rener.py script (Ticket #222) --- SConstruct | 5 +++-- admin/{render-icon.py => render_icon.py} | 0 admin/scons/Buildhelper.py | 5 +++-- icons/Makefile.am | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) rename admin/{render-icon.py => render_icon.py} (100%) diff --git a/SConstruct b/SConstruct index 1f1673f6c..c40c90ce2 100644 --- a/SConstruct +++ b/SConstruct @@ -33,7 +33,7 @@ TESTDIR = 'tests' ICONDIR = 'icons' VERSION = '0.1+pre.01' TOOLDIR = './admin/scons' -SVGRENDERER = 'admin/render-icon' +SCRIPTDIR = './admin' #-----------------------------------Configuration # NOTE: scons -h for help. @@ -47,6 +47,7 @@ import os import sys sys.path.append(TOOLDIR) +sys.path.append(SCRIPTDIR) from Buildhelper import * from LumieraEnvironment import * @@ -84,7 +85,7 @@ def setupBasicEnvironment(): , CCFLAGS='-Wall -Wextra ' , CFLAGS='-std=gnu99' ) - RegisterIcon_Builder(env,SVGRENDERER) + RegisterIcon_Builder(env) handleNoBugSwitches(env) env.Append(CPPDEFINES = '_GNU_SOURCE') diff --git a/admin/render-icon.py b/admin/render_icon.py similarity index 100% rename from admin/render-icon.py rename to admin/render_icon.py diff --git a/admin/scons/Buildhelper.py b/admin/scons/Buildhelper.py index 159dc4721..f8e349a5e 100644 --- a/admin/scons/Buildhelper.py +++ b/admin/scons/Buildhelper.py @@ -196,12 +196,13 @@ def checkCommandOption(env, optID, val=None, cmdName=None): -def RegisterIcon_Builder(env, renderer): +def RegisterIcon_Builder(env): """ Registers Custom Builders for generating and installing Icons. Additionally you need to build the tool (rsvg-convert.c) used to generate png from the svg source using librsvg. """ - renderer = __import__(renderer) # load python script for invoking the render + + import render_icon as renderer # load Joel's python script for invoking the rsvg-convert (SVG render) renderer.rsvgPath = env.subst("$BINDIR/rsvg-convert") def invokeRenderer(target, source, env): diff --git a/icons/Makefile.am b/icons/Makefile.am index 97d817ab4..ce0990f26 100644 --- a/icons/Makefile.am +++ b/icons/Makefile.am @@ -18,7 +18,7 @@ svgdir = $(top_srcdir)/icons/svg prerendereddir = $(top_srcdir)/icons/prerendered icondir = $(top_builddir) -iconcommand = python $(top_srcdir)/admin/render-icon.py +iconcommand = python $(top_srcdir)/admin/render_icon.py 16x16 = $(icondir)/16x16 22x22 = $(icondir)/22x22 From e9ae8c8601ed98dab865c605b2c2b788d5f54613 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Fri, 15 Jan 2010 07:35:28 -0500 Subject: [PATCH 33/48] add a thread state check and remove an old comment --- src/backend/threadpool.c | 1 + src/backend/threads.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index ce8a7d3e9..8166e39f8 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -110,6 +110,7 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, ret = lumiera_thread_new (kind, purpose, flag, &threadpool.pool[kind].pthread_attrs); ENSURE (ret, "did not create a valid thread"); + ENSURE (ret->state == LUMIERA_THREADSTATE_IDLE, "a non-idle thread found in the idle pool"); TODO ("no error handing, let the resourcecollector do it, no need when returning the thread"); LUMIERA_CONDITION_WAIT (!llist_is_empty (&threadpool.pool[kind].idle_list)); } diff --git a/src/backend/threads.c b/src/backend/threads.c index 74efb6687..0675e6187 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -69,7 +69,6 @@ static void* thread_loop (void* thread) REQUIRE (t, "thread does not exist"); - // this seems to deadlock unexpectedly: LUMIERA_CONDITION_SECTION (threads, &t->signal) { do { From 55859bcb14fb772050206ce57540784953bb93a4 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Fri, 15 Jan 2010 17:15:58 -0500 Subject: [PATCH 34/48] match the filename in the header comment --- admin/render_icon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/render_icon.py b/admin/render_icon.py index 0f9cee294..e3f76c129 100755 --- a/admin/render_icon.py +++ b/admin/render_icon.py @@ -1,6 +1,6 @@ #!/usr/bin/python # -# render-icons.py - Icon rendering utility script +# render_icons.py - Icon rendering utility script # # Copyright (C) Lumiera.org # 2008, Joel Holdsworth From c85dc85ec137da3bbd4af044f62466dae2ec5ce6 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 16 Jan 2010 11:47:58 +0100 Subject: [PATCH 35/48] planned test for clearing errors, just a note not to forget this --- tests/backend/test-threads.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/backend/test-threads.c b/tests/backend/test-threads.c index 14237f7a2..48fc3a114 100644 --- a/tests/backend/test-threads.c +++ b/tests/backend/test-threads.c @@ -156,4 +156,9 @@ TEST ("mutex_thread") } +PLANNED ("error_cleared_on_join") +{ + //when a thread/job is finished, there must be no pending errors +} + TESTS_END From e60c10a01d90ee544287effb6c9504a85b9b16ac Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Sat, 16 Jan 2010 10:39:45 -0500 Subject: [PATCH 36/48] remove redundant info from TRACE and add spaces for formatting --- src/backend/threads.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/backend/threads.c b/src/backend/threads.c index 0675e6187..5038c76dc 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -61,7 +61,7 @@ const char* lumiera_threadstate_names[] = { static void* thread_loop (void* thread) { - TRACE(threads); + TRACE (threads); NOBUG_THREAD_ID_SET("worker"); LumieraThread t = (LumieraThread)thread; @@ -99,7 +99,7 @@ lumiera_thread_run (enum lumiera_thread_class kind, const char* purpose, struct nobug_flag* flag) { - TRACE(threads); + TRACE (threads); // REQUIRE (function, "invalid function"); // ask the threadpool for a thread (it might create a new one) @@ -153,7 +153,7 @@ lumiera_thread_new (enum lumiera_thread_class kind, LumieraThread lumiera_thread_destroy (LumieraThread self) { - TRACE(threads); + TRACE (threads); REQUIRE (self, "trying to destroy an invalid thread"); llist_unlink (&self->node); @@ -182,7 +182,7 @@ lumiera_thread_destroy (LumieraThread self) void lumiera_thread_delete (LumieraThread self) { - TRACE(threads, "deleting thread"); + TRACE (threads); lumiera_free (lumiera_thread_destroy (self)); } From 02c9ee33c701b7b6a616cea9111c010e953730e0 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Sat, 16 Jan 2010 11:48:48 -0500 Subject: [PATCH 37/48] fix the code by re-merging some of cehteh's changes test still fails --- src/backend/threadpool.c | 64 ++++++++++++++++---------------- src/backend/threadpool.h | 4 +- src/backend/threads.c | 3 -- tests/30backend-threadpool.tests | 5 +-- 4 files changed, 36 insertions(+), 40 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 8166e39f8..3f475d9d7 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -54,7 +54,7 @@ lumiera_threadpool_init(void) { llist_init (&threadpool.pool[i].working_list); llist_init (&threadpool.pool[i].idle_list); - threadpool.pool[i].working_thread_count = 0; + threadpool.pool[i].thread_count = 0; threadpool.pool[i].idle_thread_count = 0; //TODO: configure each pools' pthread_attrs appropriately @@ -75,16 +75,24 @@ lumiera_threadpool_destroy(void) TRACE (threadpool, "destroying individual pool #%d", i); LUMIERA_CONDITION_SECTION (threadpool, &threadpool.pool[i].sync) { - REQUIRE (0 == threadpool.pool[i].working_thread_count && - 0 == llist_count (&threadpool.pool[i].working_list), - "%d(%d) threads are still running", - threadpool.pool[i].working_thread_count, + REQUIRE (threadpool.pool[i].thread_count + == threadpool.pool[i].idle_thread_count + && 0 == llist_count (&threadpool.pool[i].working_list), + "%d(llist_count=%d) threads are still running", + threadpool.pool[i].thread_count + - threadpool.pool[i].idle_thread_count, llist_count (&threadpool.pool[i].working_list)); - // TODO need to have a stronger assertion that no threads are really running because they will not even be in the list - INFO (threadpool, "working threads count=%d, idle threads count=%d", llist_count (&threadpool.pool[i].working_list), llist_count (&threadpool.pool[i].idle_list)); + REQUIRE ((int)(llist_count (&threadpool.pool[i].working_list) + + llist_count (&threadpool.pool[i].idle_list)) + == threadpool.pool[i].thread_count, + "threadpool counter miscalculation (working_list count = %u, idle_list count = %u, thread_count = %d )", + llist_count (&threadpool.pool[i].working_list), + llist_count (&threadpool.pool[i].idle_list), + threadpool.pool[i].thread_count); LLIST_WHILE_HEAD (&threadpool.pool[i].idle_list, t) { lumiera_thread_delete ((LumieraThread)t); + threadpool.pool[i].thread_count--; } } lumiera_condition_destroy (&threadpool.pool[i].sync, &NOBUG_FLAG (threadpool)); @@ -110,8 +118,8 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, ret = lumiera_thread_new (kind, purpose, flag, &threadpool.pool[kind].pthread_attrs); ENSURE (ret, "did not create a valid thread"); - ENSURE (ret->state == LUMIERA_THREADSTATE_IDLE, "a non-idle thread found in the idle pool"); TODO ("no error handing, let the resourcecollector do it, no need when returning the thread"); + threadpool.pool[kind].thread_count++; LUMIERA_CONDITION_WAIT (!llist_is_empty (&threadpool.pool[kind].idle_list)); } // use an existing thread, pick the first one @@ -125,19 +133,14 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, // move thread to the working_list llist_insert_head (&threadpool.pool[kind].working_list, &ret->node); - threadpool.pool[kind].working_thread_count++; threadpool.pool[kind].idle_thread_count--; // cheaper than using llist_count - ENSURE (threadpool.pool[kind].working_thread_count == - llist_count (&threadpool.pool[kind].working_list), - "working thread count %d is wrong, should be %d", - threadpool.pool[kind].working_thread_count, - llist_count (&threadpool.pool[kind].working_list)); - - ENSURE (threadpool.pool[kind].idle_thread_count == - llist_count (&threadpool.pool[kind].idle_list), - "idle thread count %d is wrong, should be %d", - threadpool.pool[kind].idle_thread_count, - llist_count (&threadpool.pool[kind].idle_list)); + REQUIRE ((int)(llist_count (&threadpool.pool[kind].working_list) + + llist_count (&threadpool.pool[kind].idle_list)) + == threadpool.pool[kind].thread_count, + "threadpool counter miscalculation (working_list count = %u, idle_list count = %u, thread_count = %d )", + llist_count (&threadpool.pool[kind].working_list), + llist_count (&threadpool.pool[kind].idle_list), + threadpool.pool[kind].thread_count); } return ret; } @@ -154,23 +157,20 @@ lumiera_threadpool_release_thread(LumieraThread thread) LUMIERA_CONDITION_SECTION (threadpool, &threadpool.pool[thread->kind].sync) { thread->state = LUMIERA_THREADSTATE_IDLE; - REQUIRE (llist_is_empty (&thread->node), "thread already belongs to some list"); + REQUIRE (!llist_is_member (&threadpool.pool[thread->kind].idle_list, &thread->node), "thread is already in the idle list"); + // REQUIRE (llist_is_member (&threadpool.pool[thread->kind].working_list, &thread->node), "thread is not in the working list"); // does not make sense for when the thread was just created, check for state==STARTUP // move thread to the idle_list llist_insert_head (&threadpool.pool[thread->kind].idle_list, &thread->node); - threadpool.pool[thread->kind].working_thread_count--; threadpool.pool[thread->kind].idle_thread_count++; // cheaper than using llist_count + REQUIRE ((int)(llist_count (&threadpool.pool[thread->kind].working_list) + + llist_count (&threadpool.pool[thread->kind].idle_list)) + == threadpool.pool[thread->kind].thread_count, + "threadpool counter miscalculation (working_list count = %u, idle_list count = %u, thread_count = %d )", + llist_count (&threadpool.pool[thread->kind].working_list), + llist_count (&threadpool.pool[thread->kind].idle_list), + threadpool.pool[thread->kind].thread_count); - ENSURE (threadpool.pool[thread->kind].idle_thread_count == - llist_count (&threadpool.pool[thread->kind].idle_list), - "idle thread count %d is wrong, should be %d", - threadpool.pool[thread->kind].idle_thread_count, - llist_count (&threadpool.pool[thread->kind].idle_list)); - ENSURE (threadpool.pool[thread->kind].working_thread_count == - llist_count (&threadpool.pool[thread->kind].working_list), - "working thread count %d is wrong, should be %d", - threadpool.pool[thread->kind].working_thread_count, - llist_count (&threadpool.pool[thread->kind].working_list)); REQUIRE (!llist_is_empty (&threadpool.pool[thread->kind].idle_list), "thread pool is still empty after insertion"); LUMIERA_CONDITION_BROADCAST; } diff --git a/src/backend/threadpool.h b/src/backend/threadpool.h index ac3a52ad2..47d90e6fc 100644 --- a/src/backend/threadpool.h +++ b/src/backend/threadpool.h @@ -70,8 +70,8 @@ struct lumiera_threadpool_struct { llist working_list; llist idle_list; - unsigned working_thread_count; - unsigned idle_thread_count; + int thread_count; + int idle_thread_count; pthread_attr_t pthread_attrs; lumiera_condition sync; } pool[LUMIERA_THREADCLASS_COUNT]; diff --git a/src/backend/threads.c b/src/backend/threads.c index 5038c76dc..6eb31533f 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -76,9 +76,6 @@ static void* thread_loop (void* thread) INFO(threads, "function %p", t->function); if (t->function) t->function (t->arguments); - // TODO: problem: - // calling release on a not-yet properly setup thread - // threadpool.pool[thread->kind].working_thread_count == 0 lumiera_threadpool_release_thread(t); LUMIERA_CONDITION_WAIT(t->state != LUMIERA_THREADSTATE_IDLE); INFO(threads, "Thread awaken with state %d", t->state); diff --git a/tests/30backend-threadpool.tests b/tests/30backend-threadpool.tests index bd59e0792..b3727bb48 100644 --- a/tests/30backend-threadpool.tests +++ b/tests/30backend-threadpool.tests @@ -10,7 +10,6 @@ END TEST "process a function" process-function < Date: Sat, 16 Jan 2010 12:52:30 -0500 Subject: [PATCH 38/48] ignore RESOURCE_ANNOUNCE in tests makes my threadpool process-function test pass :) --- tests/test.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test.conf b/tests/test.conf index c86e03260..38cdca9cc 100755 --- a/tests/test.conf +++ b/tests/test.conf @@ -1 +1 @@ -LOGSUPPRESS='^\(\*\*[0-9]*\*\* \)\?[0-9]\{10,\}: \(TRACE\|INFO\|NOTICE\|WARNING\|ERR\|TODO\|PLANNED\|FIXME\|DEPRECATED\|UNIMPLEMENTED\):' +LOGSUPPRESS='^\(\*\*[0-9]*\*\* \)\?[0-9]\{10,\}: \(TRACE\|INFO\|NOTICE\|WARNING\|ERR\|TODO\|PLANNED\|FIXME\|DEPRECATED\|UNIMPLEMENTED\|RESOURCE_ANNOUNCE\):' From fa85a01818a339fee647ca24984d9c99f77eab30 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Sat, 16 Jan 2010 13:13:02 -0500 Subject: [PATCH 39/48] add a stronger REQUIRE check --- src/backend/threadpool.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 3f475d9d7..7633229f2 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -156,9 +156,12 @@ lumiera_threadpool_release_thread(LumieraThread thread) REQUIRE (thread->state != LUMIERA_THREADSTATE_IDLE, "trying to park an already idle thread"); LUMIERA_CONDITION_SECTION (threadpool, &threadpool.pool[thread->kind].sync) { - thread->state = LUMIERA_THREADSTATE_IDLE; REQUIRE (!llist_is_member (&threadpool.pool[thread->kind].idle_list, &thread->node), "thread is already in the idle list"); - // REQUIRE (llist_is_member (&threadpool.pool[thread->kind].working_list, &thread->node), "thread is not in the working list"); // does not make sense for when the thread was just created, check for state==STARTUP + REQUIRE (llist_is_member (&threadpool.pool[thread->kind].working_list, &thread->node) + || thread->state == LUMIERA_THREADSTATE_STARTUP, + "thread is not in the working list (state=%s)", + lumiera_threadstate_names[thread->state]); + thread->state = LUMIERA_THREADSTATE_IDLE; // move thread to the idle_list llist_insert_head (&threadpool.pool[thread->kind].idle_list, &thread->node); From c78571be55982c51e0ce708cd4389741acec1039 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Sat, 16 Jan 2010 13:53:42 -0500 Subject: [PATCH 40/48] more formatting fixes to put spaces before function/macro call opening brackets --- src/backend/threadpool.c | 2 +- src/backend/threads.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 7633229f2..ea88b4503 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -46,7 +46,7 @@ void lumiera_threadpool_init(void) { NOBUG_INIT_FLAG (threadpool); - NOBUG_INIT_FLAG(threads); + NOBUG_INIT_FLAG (threads); TRACE (threadpool); NOBUG_INIT_FLAG (threads); diff --git a/src/backend/threads.c b/src/backend/threads.c index 6eb31533f..3dd1bdbae 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -62,7 +62,7 @@ const char* lumiera_threadstate_names[] = { static void* thread_loop (void* thread) { TRACE (threads); - NOBUG_THREAD_ID_SET("worker"); + NOBUG_THREAD_ID_SET ("worker"); LumieraThread t = (LumieraThread)thread; pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL); @@ -73,16 +73,16 @@ static void* thread_loop (void* thread) { do { // NULL function means: no work to do - INFO(threads, "function %p", t->function); + INFO (threads, "function %p", t->function); if (t->function) t->function (t->arguments); lumiera_threadpool_release_thread(t); - LUMIERA_CONDITION_WAIT(t->state != LUMIERA_THREADSTATE_IDLE); - INFO(threads, "Thread awaken with state %d", t->state); + LUMIERA_CONDITION_WAIT (t->state != LUMIERA_THREADSTATE_IDLE); + INFO (threads, "Thread awaken with state %d", t->state); } while (t->state != LUMIERA_THREADSTATE_SHUTDOWN); // SHUTDOWN state - INFO(threads, "Thread Shutdown"); + INFO (threads, "Thread Shutdown"); } return 0; } @@ -158,7 +158,7 @@ lumiera_thread_destroy (LumieraThread self) // get the pthread out of the processing loop // need to signal to the thread that it should start quitting // should this be within the section? - LUMIERA_CONDITION_SECTION(threads, &self->signal) + LUMIERA_CONDITION_SECTION (threads, &self->signal) { REQUIRE (self->state == LUMIERA_THREADSTATE_IDLE, "trying to delete a thread in state other than IDLE (%s)", lumiera_threadstate_names[self->state]); self->state = LUMIERA_THREADSTATE_SHUTDOWN; @@ -167,11 +167,11 @@ lumiera_thread_destroy (LumieraThread self) LUMIERA_CONDITION_SIGNAL; } - int error = pthread_join(self->id, NULL); - ENSURE (0 == error, "pthread_join returned %d:%s", error, strerror(error)); + int error = pthread_join (self->id, NULL); + ENSURE (0 == error, "pthread_join returned %d:%s", error, strerror (error)); // condition has to be destroyed after joining with the thread - lumiera_condition_destroy (&self->signal, &NOBUG_FLAG(threads)); + lumiera_condition_destroy (&self->signal, &NOBUG_FLAG (threads)); return self; } From de7debc55731adf575b0c1329d65fe1a4fd59957 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Sat, 16 Jan 2010 17:27:02 -0500 Subject: [PATCH 41/48] fix comilation by using an existing TEST macro --- tests/backend/test-threads.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/backend/test-threads.c b/tests/backend/test-threads.c index b4373c1ff..1a22d361c 100644 --- a/tests/backend/test-threads.c +++ b/tests/backend/test-threads.c @@ -153,7 +153,7 @@ TEST ("mutex_thread") } -PLANNED ("error_cleared_on_join") +TEST ("error_cleared_on_join") { //when a thread/job is finished, there must be no pending errors } From b8336879f7997e26e661eaf7dcbd3390f201b09e Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 17 Jan 2010 15:48:30 +0100 Subject: [PATCH 42/48] autoconf/automake cleanup * refactor configure.ac to have distinct sections to configure each subsystem. * Dedicated LUMIERA__CFLAGS|_LIBS vars * Fix Makefile.am's to use them, remove unnecessary dependencies Stray dependencies to be refacored: * tests/Makefile.am has dependencies on proc and backend - should be moved to tests/library/Makefile.am etc anyways * tests/lib/Makefile.am has dependency on GUI left * src/tool/Makefile.am links GUI stuff generally, thats ok * one threading test is broken, we don't care, merging new threadpool in next. --- Makefile.am | 3 +- configure.ac | 173 ++++++++++++++++++++++++++--------- src/backend/Makefile.am | 4 +- src/common/Makefile.am | 11 ++- src/gui/Makefile.am | 11 +-- src/lib/Makefile.am | 15 ++- src/lumiera/Makefile.am | 14 +-- src/proc/Makefile.am | 38 ++++---- src/tool/Makefile.am | 8 +- tests/Makefile.am | 56 ++++-------- tests/components/Makefile.am | 2 +- tests/lib/Makefile.am | 9 +- tests/tool/Makefile.am | 2 +- 13 files changed, 212 insertions(+), 134 deletions(-) diff --git a/Makefile.am b/Makefile.am index c23c7611c..8fc724603 100644 --- a/Makefile.am +++ b/Makefile.am @@ -36,8 +36,7 @@ CLEANFILES = # global pre-processor flags. Per-target variables should include # these at the front (if possible) for consistency AM_CPPFLAGS = -I$(top_srcdir)/src/ \ - $(NOBUGMT_LUMIERA_CFLAGS) \ - $(VALGRIND_CFLAGS) + $(LUMIERA_CFLAGS) # Only use subdirs if really needed, prefer the include scheme below #SUBDIRS += diff --git a/configure.ac b/configure.ac index 297b9c2cc..c93198edf 100644 --- a/configure.ac +++ b/configure.ac @@ -7,8 +7,9 @@ AC_PREREQ(2.59) AC_COPYRIGHT([ Copyright (C) Lumiera.org - 2008, Christian Thaeter + 2008, 2009, 2010 Christian Thaeter Joel Holdsworth + et. al. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -25,12 +26,14 @@ AC_COPYRIGHT([ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ]) +################################################################################# # # Global configuration # AC_GNU_SOURCE AC_DISABLE_STATIC +################################################################################# # # Required programs # @@ -42,26 +45,12 @@ AC_LIBTOOL_DLOPEN AC_PROG_LIBTOOL PKG_PROG_PKG_CONFIG([0.22]) -# -# test for headers -# -AC_STDC_HEADERS - -ACX_PTHREAD -LIBS="$PTHREAD_LIBS $LIBS" -CFLAGS="$CFLAGS $PTHREAD_CFLAGS" -CC="$PTHREAD_CC" - -##AM_CONDITIONAL([HAVE_THREADING], [test x"$acx_pthread_ok" = xyes]) - - - +################################################################################# # # user options # - -############## NoBug build levels +# NoBug build levels AH_TEMPLATE(EBUG_ALPHA, [Define to 1 for selecting NoBug ALPHA build level]) AH_TEMPLATE(EBUG_BETA, [Define to 1 for selecting NoBug BETA build level]) AH_TEMPLATE(NDEBUG, [Define to 1 for selecting NoBug RELEASE build level]) @@ -83,18 +72,44 @@ AC_ARG_ENABLE(release, AC_HELP_STRING([--enable-release], [select NoBug RELEASE )])]) # END NoBug -# C headers and libraries -AC_LANG_PUSH([C]) -AC_CHECK_LIB(dl, dlopen, [LUMIERA_PLUGIN_LIBS="$LUMIERA_PLUGIN_LIBS -ldl"], - [AC_MSG_ERROR([Dynamic linking not supported, report a bug])] + + +################################################################################# +# +# global test for headers and functions +# +AC_STDC_HEADERS + + +ACX_PTHREAD +LIBS="$PTHREAD_LIBS $LIBS" +CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +CC="$PTHREAD_CC" + +# Nobug Dependencies +AC_CHECK_HEADER([execinfo.h], AC_DEFINE(HAVE_EXECINFO_H)) +PKG_CHECK_MODULES(VALGRIND, [valgrind], AC_DEFINE(HAVE_VALGRIND_H), + AC_MSG_NOTICE([valgrind not found (optional)])) + +PKG_CHECK_MODULES(NOBUGMT, [nobugmt >= 201001.1], + AC_DEFINE(HAVE_NOBUGMT_H), + AC_MSG_ERROR([Missing required nobug version (http://www.lumiera.org/nobug_manual.html)]) ) -AC_LANG_POP([C]) +LUMIERA_CFLAGS="$NOBUGMT_CFLAGS $VALGRIND_CFLAGS" +LUMIERA_LIBS="$NOBUGMT_LIBS" + +AC_SUBST(LUMIERA_CFLAGS) +AC_SUBST(LUMIERA_LIBS) +#boost # C++ headers and libraries AC_LANG_PUSH([C++]) +# check for the minimum Boost version +# (http://www.randspringer.de/boost/upt.html) +AX_BOOST_BASE([1.34.1]) AC_CHECK_HEADER([tr1/memory], , @@ -107,22 +122,87 @@ AC_CHECK_HEADER([boost/shared_ptr.hpp], ) AC_CHECK_HEADER([boost/program_options.hpp], - , + [LUMIERA_BOOST_LIBS="$LUMIERA_BOOST_LIBS -lboost_program_options-mt"], AC_MSG_ERROR([boost::program_options missing (http://www.boost.org/)]) ) -# check for the minimum Boost version -# (http://www.randspringer.de/boost/upt.html) -AX_BOOST_BASE([1.34.1]) - AC_CHECK_HEADER([boost/regex.hpp], - , + [LUMIERA_BOOST_LIBS="$LUMIERA_BOOST_LIBS -lboost_regex-mt"], AC_MSG_ERROR([boost::regex missing (http://www.boost.org/)]) ) AC_LANG_POP([C++]) +AC_SUBST(LUMIERA_BOOST_CFLAGS) +AC_SUBST(LUMIERA_BOOST_LIBS) -PKG_CHECK_MODULES(LUMIERA_COMMON_LIBS, [sigc++-2.0 >= 2.0.17]) + + +################################################################################# +# +# Configs for subsystems +# ---------------------- +# + +################################################################################# +# +# library +# + +PKG_CHECK_MODULES(LUMIERA_LIBRARY, [ + gavl >= 1.0.1 + ]) + +LUMIERA_LIBRARY_CFLAGS="$LUMIERA_LIBRARY_CFLAGS $LUMIERA_CFLAGS" +LUMIERA_LIBRARY_LIBS="$LUMIERA_LIBRARY_CFLAGS $LUMIERA_LIBS $LUMIERA_BOOST_LIBS" + +AC_SUBST(LUMIERA_LIBRARY_CFLAGS) +AC_SUBST(LUMIERA_LIBRARY_LIBS) + +################################################################################# +# +# common +# +PKG_CHECK_MODULES(LUMIERA_COMMON, [sigc++-2.0 >= 2.0.17]) + +AC_LANG_PUSH([C]) +AC_CHECK_LIB(dl, dlopen, [LUMIERA_COMMON_LIBS="$LUMIERA_COMMON_LIBS -ldl"], + [AC_MSG_ERROR([Dynamic linking not supported, report a bug])] +) +AC_LANG_POP([C]) + +LUMIERA_COMMON_CFLAGS="$LUMIERA_COMMON_CFLAGS $LUMIERA_CFLAGS" +LUMIERA_COMMON_LIBS="$LUMIERA_COMMON_LIBS $LUMIERA_LIBS" + +AC_SUBST(LUMIERA_COMMON_CFLAGS) +AC_SUBST(LUMIERA_COMMON_LIBS) + +################################################################################# +# +# backend +# + +LUMIERA_BACKEND_CFLAGS="$LUMIERA_CFLAGS" +LUMIERA_BACKEND_LIBS="$LUMIERA_LIBS" + +AC_SUBST(LUMIERA_BACKEND_CFLAGS) +AC_SUBST(LUMIERA_BACKEND_LIBS) + +################################################################################# +# +# proc +# + + +LUMIERA_PROC_CFLAGS="$LUMIERA_PROC_CFLAGS $LUMIERA_CFLAGS" +LUMIERA_PROC_LIBS="$LUMIERA_PROC_CFLAGS $LUMIERA_LIBS" + +AC_SUBST(LUMIERA_PROC_CFLAGS) +AC_SUBST(LUMIERA_PROC_LIBS) + +################################################################################# +# +# gui +# ############## Internatinalization #GETTEXT_PACKAGE=gtk-lumiera @@ -143,14 +223,12 @@ PKG_CHECK_MODULES(LUMIERA_GUI, [ gtkmm-2.4 >= 2.12 cairomm-1.0 >= 0.6.0 librsvg-2.0 >= 2.18.1 - gavl >= 0.2.5 + gavl >= 1.0.1 gthread-2.0 >= 2.12.4]) # Check for gdl-1.0 with a gdl-lum fallback PKG_CHECK_MODULES(GDL, gdl-1.0 >= 2.27.1, , [PKG_CHECK_MODULES(GDL, gdl-lum >= 2.27.1) ]) -LUMIERA_GUI_CFLAGS="$LUMIERA_GUI_CFLAGS $GDL_CFLAGS" -LUMIERA_GUI_LIBS="$LUMIERA_GUI_LIBS $GDL_LIBS" # END Gtk Dependancies @@ -178,21 +256,28 @@ AC_CHECK_LIB(Xv, XvQueryAdaptors, [LUMIERA_GUI_LIBS="$LUMIERA_GUI_LIBS -lXv"], # END X11 Dependancies -AC_SUBST(LUMIERA_COMMON_LIBS) -AC_SUBST(LUMIERA_PLUGIN_LIBS) -AC_SUBST(LUMIERA_GUI_LIBS) +LUMIERA_GUI_CFLAGS="$LUMIERA_GUI_CFLAGS $LUMIERA_CFLAGS $GDL_CFLAGS" +LUMIERA_GUI_LIBS="$LUMIERA_GUI_LIBS $LUMIERA_LIBS $GDL_LIBS" + AC_SUBST(LUMIERA_GUI_CFLAGS) +AC_SUBST(LUMIERA_GUI_LIBS) -############## Nobug Dependancies -AC_CHECK_HEADER([execinfo.h], AC_DEFINE(HAVE_EXECINFO_H)) -PKG_CHECK_MODULES(VALGRIND, [valgrind], AC_DEFINE(HAVE_VALGRIND_H), - AC_MSG_NOTICE([valgrind not found (optional)])) -PKG_CHECK_MODULES(NOBUGMT_LUMIERA, [nobugmt >= 201001.1], - AC_DEFINE(HAVE_NOBUGMT_H), - AC_MSG_ERROR([Missing required nobug version (http://www.lumiera.org/nobug_manual.html)]) -) -# END Nobug Dependancies +################################################################################# +# +# tools +# + +LUMIERA_TOOL_CFLAGS="$LUMIERA_TOOL_CFLAGS $LUMIERA_CFLAGS $LUMIERA_GUI_CFLAGS" +LUMIERA_TOOL_LIBS="$LUMIERA_TOOL_CFLAGS $LUMIERA_LIBS $LUMIERA_BOOST_LIBS $LUMIERA_GUI_LIBS" + +AC_SUBST(LUMIERA_TOOL_CFLAGS) +AC_SUBST(LUMIERA_TOOL_LIBS) + +################################################################################# +# +# Generate output +# # Print a summary AC_MSG_RESULT([ diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 5729d910b..cb52fba55 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -19,8 +19,8 @@ liblumierabackend_la_srcdir = $(top_srcdir)/src/backend lib_LTLIBRARIES += liblumierabackend.la liblumierabackend_la_CPPFLAGS = $(AM_CPPFLAGS) -liblumierabackend_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wextra -Wall -Werror -liblumierabackend_la_LIBADD = liblumiera.la +liblumierabackend_la_CFLAGS = $(AM_CFLAGS) $(LUMIERA_BACKEND_CFLAGS) -std=gnu99 -Wextra -Wall -Werror +liblumierabackend_la_LIBADD = $(LUMIERA_BACKEND_LIBS) liblumiera.la liblumierabackend_la_SOURCES = \ $(liblumierabackend_la_srcdir)/mediaaccessfacade.cpp \ diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 451b0a982..5defb5b98 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -18,10 +18,13 @@ liblumieracommon_la_srcdir = $(top_srcdir)/src/common lib_LTLIBRARIES += liblumieracommon.la -liblumieracommon_la_CPPFLAGS = $(AM_CPPFLAGS) -DLUMIERA_CONFIG_PATH="\"$(pkgdatadir)/config:.\"" -DLUMIERA_PLUGIN_PATH="\"$(pkglibdir)/:./.libs\"" -liblumieracommon_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wextra -Wall -Werror -liblumieracommon_la_CXXFLAGS = $(AM_CXXFLAGS) -Wextra -Wall -liblumieracommon_la_LIBADD = liblumiera.la +liblumieracommon_la_CPPFLAGS = $(AM_CPPFLAGS) -DLUMIERA_CONFIG_PATH="\"$(pkgdatadir)/config:.\"" -DLUMIERA_PLUGIN_PATH="\"$(pkglibdir)/:./.libs\"" +liblumieracommon_la_CFLAGS = $(AM_CFLAGS) $(LUMIERA_COMMON_CFLAGS) -std=gnu99 -Wextra -Wall -Werror +liblumieracommon_la_CXXFLAGS = $(AM_CXXFLAGS) $(LUMIERA_COMMON_CFLAGS) -Wextra -Wall +liblumieracommon_la_LIBADD = \ + $(LUMIERA_COMMON_LIBS) \ + liblumiera.la + liblumieracommon_la_SOURCES = \ $(liblumieracommon_la_srcdir)/config.c \ diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 14cd4c8fe..021f29ddd 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -32,15 +32,15 @@ lumiera_ui.rc: # pkglib_LTLIBRARIES += gtk_gui.la -gtk_gui_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror -gtk_gui_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra +gtk_gui_la_CFLAGS = $(AM_CFLAGS) $(LUMIERA_GUI_CFLAGS) -std=gnu99 -Wall -Wextra -Werror +gtk_gui_la_CXXFLAGS = $(AM_CXXFLAGS) $(LUMIERA_GUI_CFLAGS) -Wall -Wextra gtk_gui_la_CPPFLAGS = $(AM_CPPFLAGS) \ $(LUMIERA_GUI_CFLAGS) \ -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ -DPACKAGE_SRC_DIR=\""$(srcdir)"\" \ -DPACKAGE_DATA_DIR=\""$(datadir)"\" \ - -DLUMIERA_PLUGIN -I$(top_srcdir)/src/ \ - $(LUMIERA_GUI_CFLAGS) + -DLUMIERA_PLUGIN -I$(top_srcdir)/src/ + gtk_gui_la_LDFLAGS = -module -avoid-version -no-undefined -rpath /dev/null -shrext .lum gtk_gui_la_LIBADD = \ @@ -48,8 +48,7 @@ gtk_gui_la_LIBADD = \ liblumierabackend.la \ liblumieracommon.la \ liblumiera.la \ - $(LUMIERA_GUI_LIBS) \ - $(NOBUGMT_LUMIERA_LIBS) + $(LUMIERA_GUI_LIBS) gtk_gui_la_SOURCES = \ $(lumigui_srcdir)/guistart.cpp \ diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index eb1a20548..7b6218ad8 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -18,8 +18,19 @@ liblumiera_la_srcdir = $(top_srcdir)/src/lib lib_LTLIBRARIES += liblumiera.la -liblumiera_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror -liblumiera_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra +liblumiera_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(LUMIERA_LIBRARY_CFLAGS) \ + -std=gnu99 -Wall -Wextra -Werror + +liblumiera_la_CXXFLAGS = \ + $(AM_CXXFLAGS) \ + $(LUMIERA_LIBRARY_CFLAGS) \ + -Wall -Wextra + +liblumiera_la_LIBADD = \ + $(LUMIERA_LIBRARY_LIBS) + liblumiera_la_SOURCES = \ $(liblumiera_la_srcdir)/error.c \ diff --git a/src/lumiera/Makefile.am b/src/lumiera/Makefile.am index 7085d32db..5f346beb7 100644 --- a/src/lumiera/Makefile.am +++ b/src/lumiera/Makefile.am @@ -18,20 +18,16 @@ lumiera_srcdir = $(top_srcdir)/src/lumiera bin_PROGRAMS += lumiera -lumiera_CPPFLAGS = $(AM_CPPFLAGS) $(LUMIERA_GUI_CFLAGS) -lumiera_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror -lumiera_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra +lumiera_CPPFLAGS = $(AM_CPPFLAGS) +lumiera_CFLAGS = $(AM_CFLAGS) $(LUMIERA_CFLAGS) -std=gnu99 -Wall -Wextra -Werror +lumiera_CXXFLAGS = $(AM_CXXFLAGS) $(LUMIERA_CFLAGS) -Wall -Wextra lumiera_LDADD = \ + $(LUMIERA_LIBS) \ liblumieracommon.la \ liblumierabackend.la \ liblumieraproc.la \ - liblumiera.la \ - $(LUMIERA_PLUGIN_LIBS) \ - $(LUMIERA_GUI_LIBS) \ - $(NOBUGMT_LUMIERA_LIBS) \ - -lboost_program_options-mt \ - -lboost_regex-mt + liblumiera.la lumiera_SOURCES = \ $(lumiera_srcdir)/main.cpp diff --git a/src/proc/Makefile.am b/src/proc/Makefile.am index 7d4d331df..4c220197c 100644 --- a/src/proc/Makefile.am +++ b/src/proc/Makefile.am @@ -21,8 +21,8 @@ liblumiproc_la_srcdir = $(top_srcdir)/src/proc noinst_LTLIBRARIES += liblumiproc.la -liblumiproc_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror -liblumiproc_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra +liblumiproc_la_CFLAGS = $(AM_CFLAGS) $(LUMIERA_PROC_CFLAGS) -std=gnu99 -Wall -Wextra -Werror +liblumiproc_la_CXXFLAGS = $(AM_CXXFLAGS) $(LUMIERA_PROC_CFLAGS) -Wall -Wextra liblumiproc_la_SOURCES = \ $(liblumiproc_la_srcdir)/controllerfacade.cpp \ @@ -36,8 +36,8 @@ liblumiproc_la_SOURCES = \ liblumiprocasset_la_srcdir = $(top_srcdir)/src/proc/asset noinst_LTLIBRARIES += liblumiprocasset.la -liblumiprocasset_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror -liblumiprocasset_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra +liblumiprocasset_la_CFLAGS = $(AM_CFLAGS) $(LUMIERA_PROC_CFLAGS) -std=gnu99 -Wall -Wextra -Werror +liblumiprocasset_la_CXXFLAGS = $(AM_CXXFLAGS) $(LUMIERA_PROC_CFLAGS) -Wall -Wextra liblumiprocasset_la_SOURCES = \ $(liblumiprocasset_la_srcdir)/codec.cpp \ @@ -61,8 +61,8 @@ liblumiprocasset_la_SOURCES = \ liblumiprocengine_la_srcdir = $(top_srcdir)/src/proc/engine noinst_LTLIBRARIES += liblumiprocengine.la -liblumiprocengine_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror -liblumiprocengine_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra +liblumiprocengine_la_CFLAGS = $(AM_CFLAGS) $(LUMIERA_PROC_CFLAGS) -std=gnu99 -Wall -Wextra -Werror +liblumiprocengine_la_CXXFLAGS = $(AM_CXXFLAGS) $(LUMIERA_PROC_CFLAGS) -Wall -Wextra liblumiprocengine_la_SOURCES = \ $(liblumiprocengine_la_srcdir)/buffhandle.cpp \ @@ -84,8 +84,8 @@ liblumiprocengine_la_SOURCES = \ liblumiprocmobject_la_srcdir = $(top_srcdir)/src/proc/mobject noinst_LTLIBRARIES += liblumiprocmobject.la -liblumiprocmobject_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror -liblumiprocmobject_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra +liblumiprocmobject_la_CFLAGS = $(AM_CFLAGS) $(LUMIERA_PROC_CFLAGS) -std=gnu99 -Wall -Wextra -Werror +liblumiprocmobject_la_CXXFLAGS = $(AM_CXXFLAGS) $(LUMIERA_PROC_CFLAGS) -Wall -Wextra liblumiprocmobject_la_SOURCES = \ $(liblumiprocmobject_la_srcdir)/builderfacade.cpp \ @@ -101,8 +101,8 @@ liblumiprocmobject_la_SOURCES = \ liblumiprocmobjectbuilder_la_srcdir = $(top_srcdir)/src/proc/mobject/builder noinst_LTLIBRARIES += liblumiprocmobjectbuilder.la -liblumiprocmobjectbuilder_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror -liblumiprocmobjectbuilder_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra +liblumiprocmobjectbuilder_la_CFLAGS = $(AM_CFLAGS) $(LUMIERA_PROC_CFLAGS) -std=gnu99 -Wall -Wextra -Werror +liblumiprocmobjectbuilder_la_CXXFLAGS = $(AM_CXXFLAGS) $(LUMIERA_PROC_CFLAGS) -Wall -Wextra liblumiprocmobjectbuilder_la_SOURCES = \ $(liblumiprocmobjectbuilder_la_srcdir)/assembler.cpp \ @@ -115,8 +115,8 @@ liblumiprocmobjectbuilder_la_SOURCES = \ liblumiproccontrol_la_srcdir = $(top_srcdir)/src/proc/control noinst_LTLIBRARIES += liblumiproccontrol.la -liblumiproccontrol_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror -liblumiproccontrol_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra +liblumiproccontrol_la_CFLAGS = $(AM_CFLAGS) $(LUMIERA_PROC_CFLAGS) -std=gnu99 -Wall -Wextra -Werror +liblumiproccontrol_la_CXXFLAGS = $(AM_CXXFLAGS) $(LUMIERA_PROC_CFLAGS) -Wall -Wextra liblumiproccontrol_la_SOURCES = \ $(liblumiproccontrol_la_srcdir)/command.cpp \ @@ -130,8 +130,8 @@ liblumiproccontrol_la_SOURCES = \ liblumiprocplay_la_srcdir = $(top_srcdir)/src/proc/play noinst_LTLIBRARIES += liblumiprocplay.la -liblumiprocplay_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror -liblumiprocplay_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra +liblumiprocplay_la_CFLAGS = $(AM_CFLAGS) $(LUMIERA_PROC_CFLAGS) -std=gnu99 -Wall -Wextra -Werror +liblumiprocplay_la_CXXFLAGS = $(AM_CXXFLAGS) $(LUMIERA_PROC_CFLAGS) -Wall -Wextra liblumiprocplay_la_SOURCES = \ $(liblumiprocplay_la_srcdir)/dummy-player-service.cpp \ @@ -141,8 +141,8 @@ liblumiprocplay_la_SOURCES = \ liblumiprocmobjectsession_la_srcdir = $(top_srcdir)/src/proc/mobject/session noinst_LTLIBRARIES += liblumiprocmobjectsession.la -liblumiprocmobjectsession_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror -liblumiprocmobjectsession_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra +liblumiprocmobjectsession_la_CFLAGS = $(AM_CFLAGS) $(LUMIERA_PROC_CFLAGS) -std=gnu99 -Wall -Wextra -Werror +liblumiprocmobjectsession_la_CXXFLAGS = $(AM_CXXFLAGS) $(LUMIERA_PROC_CFLAGS) -Wall -Wextra liblumiprocmobjectsession_la_SOURCES = \ $(liblumiprocmobjectsession_la_srcdir)/abstractmo.cpp \ @@ -265,12 +265,13 @@ noinst_HEADERS += \ liblumieraproc_la_srcdir = $(top_srcdir)/src/proc lib_LTLIBRARIES += liblumieraproc.la -liblumieraproc_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror -liblumieraproc_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra +liblumieraproc_la_CFLAGS = $(AM_CFLAGS) $(LUMIERA_PROC_CFLAGS) -std=gnu99 -Wall -Wextra -Werror +liblumieraproc_la_CXXFLAGS = $(AM_CXXFLAGS) $(LUMIERA_PROC_CFLAGS) -Wall -Wextra liblumieraproc_la_SOURCES = liblumieraproc_la_LIBADD = \ + $(LUMIERA_PROC_LIBS) \ liblumiproc.la \ liblumiprocasset.la \ liblumiprocengine.la \ @@ -279,4 +280,3 @@ liblumieraproc_la_LIBADD = \ liblumiproccontrol.la \ liblumiprocplay.la \ liblumiprocmobjectsession.la - diff --git a/src/tool/Makefile.am b/src/tool/Makefile.am index 2bf1acf99..4c1c50fd9 100644 --- a/src/tool/Makefile.am +++ b/src/tool/Makefile.am @@ -18,13 +18,13 @@ lumitool_srcdir = $(top_srcdir)/src/tool noinst_PROGRAMS += luidgen -luidgen_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror +luidgen_CFLAGS = $(CFLAGS) $(LUMIERA_TOOL_CFLAGS) -std=gnu99 -Wall -Werror luidgen_CPPFLAGS = -I$(top_srcdir)/src/ -luidgen_LDADD = liblumiera.la $(NOBUGMT_LUMIERA_LIBS) -lboost_regex-mt -lboost_program_options-mt +luidgen_LDADD = liblumiera.la $(LUMIERA_TOOL_LIBS) luidgen_SOURCES = $(lumitool_srcdir)/luidgen.c noinst_PROGRAMS += rsvg-convert -rsvg_convert_CPPFLAGS = $(AM_CPPFLAGS) $(LUMIERA_GUI_CFLAGS) -std=gnu99 -Wall -Werror -rsvg_convert_LDADD = -lcairo -lglib-2.0 -lgthread-2.0 -lrsvg-2 +rsvg_convert_CPPFLAGS = $(AM_CPPFLAGS) $(LUMIERA_TOOL_CFLAGS) -std=gnu99 -Wall -Werror +rsvg_convert_LDADD = $(LUMIERA_TOOL_LIBS) rsvg_convert_SOURCES = $(lumitool_srcdir)/rsvg-convert.c diff --git a/tests/Makefile.am b/tests/Makefile.am index c33287932..d6cda64ff 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -22,79 +22,71 @@ tests_srcdir = $(top_srcdir)/tests check_PROGRAMS += test-error test_error_SOURCES = $(tests_srcdir)/library/test-error.c test_error_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_error_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumiera.la -lboost_program_options-mt -lboost_regex-mt +test_error_LDADD = $(LUMIERA_LIBS) liblumiera.la check_PROGRAMS += test-locking test_locking_SOURCES = $(tests_srcdir)/library/test-locking.c test_locking_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_locking_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumiera.la -lboost_program_options-mt -lboost_regex-mt +test_locking_LDADD = $(LUMIERA_LIBS) liblumiera.la check_PROGRAMS += test-llist test_llist_SOURCES = $(tests_srcdir)/library/test-llist.c test_llist_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_llist_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumiera.la -lboost_program_options-mt -lboost_regex-mt +test_llist_LDADD = $(LUMIERA_LIBS) liblumiera.la check_PROGRAMS += test-mpool test_mpool_SOURCES = $(tests_srcdir)/library/test-mpool.c test_mpool_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_mpool_LDADD = $(NOBUGMT_LUMIERA_LIBS) \ - liblumiera.la liblumieracommon.la liblumierabackend.la liblumieraproc.la -lboost_program_options-mt -lboost_regex-mt -ldl +test_mpool_LDADD = $(LUMIERA_LIBS) liblumiera.la check_PROGRAMS += test-psplay test_psplay_SOURCES = $(tests_srcdir)/library/test-psplay.c test_psplay_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ -test_psplay_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumiera.la -lboost_program_options-mt -lboost_regex-mt +test_psplay_LDADD = $(LUMIERA_LIBS) liblumiera.la check_PROGRAMS += test-safeclib test_safeclib_SOURCES = $(tests_srcdir)/library/test-safeclib.c test_safeclib_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_safeclib_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumiera.la -lboost_program_options-mt -lboost_regex-mt +test_safeclib_LDADD = $(LUMIERA_LIBS) liblumiera.la check_PROGRAMS += test-luid test_luid_SOURCES = $(tests_srcdir)/library/test-luid.c test_luid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_luid_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumiera.la -lboost_program_options-mt -lboost_regex-mt +test_luid_LDADD = $(LUMIERA_LIBS) liblumiera.la check_PROGRAMS += test-filedescriptors test_filedescriptors_SOURCES = $(tests_srcdir)/backend/test-filedescriptors.c test_filedescriptors_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_filedescriptors_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumierabackend.la liblumieracommon.la liblumieraproc.la -ldl liblumiera.la -lboost_program_options-mt -lboost_regex-mt +test_filedescriptors_LDADD = $(LUMIERA_LIBS) liblumierabackend.la liblumieracommon.la liblumieraproc.la +# FIXME stray dependencies on proc check_PROGRAMS += test-filehandles test_filehandles_SOURCES = $(tests_srcdir)/backend/test-filehandles.c test_filehandles_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_filehandles_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumierabackend.la liblumieracommon.la liblumieraproc.la -ldl liblumiera.la -lboost_program_options-mt -lboost_regex-mt +test_filehandles_LDADD = $(LUMIERA_LIBS) liblumierabackend.la liblumieracommon.la liblumieraproc.la +# FIXME stray dependencies on proc check_PROGRAMS += test-filemmap test_filemmap_SOURCES = $(tests_srcdir)/backend/test-filemmap.c test_filemmap_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ -test_filemmap_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumierabackend.la liblumieracommon.la liblumieraproc.la -ldl liblumiera.la -lboost_program_options-mt -lboost_regex-mt +test_filemmap_LDADD = $(LUMIERA_LIBS) liblumierabackend.la liblumieracommon.la liblumieraproc.la +# FIXME stray dependencies on proc check_PROGRAMS += test-resourcecollector test_resourcecollector_SOURCES = $(tests_srcdir)/library/test-resourcecollector.c test_resourcecollector_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ -test_resourcecollector_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumierabackend.la liblumieracommon.la liblumieraproc.la -ldl liblumiera.la -lboost_program_options-mt -lboost_regex-mt +test_resourcecollector_LDADD = $(LUMIERA_LIBS) liblumiera.la check_PROGRAMS += test-slist test_slist_SOURCES = $(tests_srcdir)/library/test-slist.c test_slist_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_slist_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumiera.la -lboost_program_options-mt -lboost_regex-mt +test_slist_LDADD = $(LUMIERA_LIBS) liblumiera.la check_PROGRAMS += test-config test_config_SOURCES = $(tests_srcdir)/common/test-config.c test_config_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ -test_config_LDADD = \ - liblumieraproc.la \ - liblumierabackend.la \ - liblumieracommon.la \ - liblumiera.la \ - $(LUMIERA_PLUGIN_LIBS) \ - $(NOBUGMT_LUMIERA_LIBS) \ - -ldl \ - -lboost_program_options-mt \ - -lboost_regex-mt - - +test_config_LDADD = $(LUMIERA_LIBS) liblumieracommon.la liblumieraproc.la liblumierabackend.la +# FIXME stray dependencies on proc check_LTLIBRARIES += examplepluginc.la examplepluginc_la_SOURCES = $(tests_srcdir)/plugin/examplepluginc/example_plugin.c @@ -104,21 +96,13 @@ examplepluginc_la_LDFLAGS = -module -avoid-version -no-undefined -rpath /dev/nul check_PROGRAMS += test-interfaces test_interfaces_SOURCES = $(tests_srcdir)/common/test-interfaces.c test_interfaces_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_interfaces_LDADD = \ - liblumieraproc.la \ - liblumierabackend.la \ - liblumieracommon.la \ - liblumiera.la \ - $(LUMIERA_PLUGIN_LIBS) \ - $(NOBUGMT_LUMIERA_LIBS) \ - -ldl \ - -lboost_program_options-mt \ - -lboost_regex-mt +test_interfaces_LDADD = $(LUMIERA_LIBS) liblumieracommon.la liblumierabackend.la liblumieraproc.la +# FIXME stray dependency on backend, proc check_PROGRAMS += test-threads test_threads_SOURCES = $(tests_srcdir)/backend/test-threads.c test_threads_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ test_threads_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) -test_threads_LDADD = liblumierabackend.la liblumiera.la -lnobugmt -lpthread -ldl -lm liblumieracommon.la liblumieraproc.la -ldl -lboost_program_options-mt -lboost_regex-mt +test_threads_LDADD = liblumierabackend.la liblumieracommon.la liblumieraproc.la TESTS = $(tests_srcdir)/test.sh diff --git a/tests/components/Makefile.am b/tests/components/Makefile.am index 04eb5a685..a62bfcdf4 100644 --- a/tests/components/Makefile.am +++ b/tests/components/Makefile.am @@ -31,7 +31,7 @@ test_components_LDADD = \ liblumierabackend.la \ liblumieracommon.la \ liblumiera.la \ - $(NOBUGMT_LUMIERA_LIBS) -ldl -lboost_program_options-mt -lboost_regex-mt + $(LUMIERA_LIBS) test_components_SOURCES = \ $(testcomponents_srcdir)/backend/mediaaccessmock.cpp \ diff --git a/tests/lib/Makefile.am b/tests/lib/Makefile.am index d3626c720..d70cd432e 100644 --- a/tests/lib/Makefile.am +++ b/tests/lib/Makefile.am @@ -19,9 +19,12 @@ testlib_srcdir = $(top_srcdir)/tests/lib check_PROGRAMS += test-lib -test_lib_CPPFLAGS = $(AM_CPPFLAGS) -Wall -I$(testlib_srcdir) $(LUMIERA_GUI_CFLAGS) +test_lib_CPPFLAGS = $(AM_CPPFLAGS) -Wall -I$(testlib_srcdir) $(LUMIERA_GUI_CFLAGS) +#why gui cflags/libs? test_lib_LDADD = \ + $(LUMIERA_LIBRARY_LIBS) \ + $(LUMIERA_GUI_LIBS) \ liblumiprocmobjectbuilder.la \ liblumiprocmobjectsession.la \ liblumiprocmobject.la \ @@ -31,9 +34,7 @@ test_lib_LDADD = \ liblumiprocasset.la \ liblumierabackend.la \ liblumieracommon.la \ - liblumiera.la \ - $(LUMIERA_GUI_LIBS) \ - $(NOBUGMT_LUMIERA_LIBS) -ldl -lboost_program_options-mt -lboost_regex-mt + liblumiera.la test_lib_SOURCES = \ $(testlib_srcdir)/mainsuite.cpp \ diff --git a/tests/tool/Makefile.am b/tests/tool/Makefile.am index 7cd7e7e6b..b4762e9b1 100644 --- a/tests/tool/Makefile.am +++ b/tests/tool/Makefile.am @@ -19,6 +19,6 @@ lumitesttool_srcdir = $(top_srcdir)/tests/tool noinst_PROGRAMS += vgsuppression vgsuppression_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -vgsuppression_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumieraproc.la liblumierabackend.la liblumieracommon.la liblumiera.la -lboost_regex-mt -lboost_program_options-mt -ldl +vgsuppression_LDADD = $(LUMIERA_LIBS) liblumieraproc.la liblumierabackend.la liblumieracommon.la liblumiera.la -lboost_regex-mt -lboost_program_options-mt -ldl vgsuppression_SOURCES = $(lumitesttool_srcdir)/vgsuppression.c From d659b1e8e70958a466260dcb0627d0456cb60341 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 17 Jan 2010 17:34:23 +0100 Subject: [PATCH 43/48] fix a PLANNED test glitch --- tests/30backend-threadpool.tests | 2 ++ tests/backend/test-threads.c | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/30backend-threadpool.tests b/tests/30backend-threadpool.tests index b3727bb48..7296a7764 100644 --- a/tests/30backend-threadpool.tests +++ b/tests/30backend-threadpool.tests @@ -13,3 +13,5 @@ err: the input to the function is 440616 err: wait 1 sec err: finished waiting END + +PLANNED "error cleared on join" diff --git a/tests/backend/test-threads.c b/tests/backend/test-threads.c index 1a22d361c..ddf43214e 100644 --- a/tests/backend/test-threads.c +++ b/tests/backend/test-threads.c @@ -153,9 +153,4 @@ TEST ("mutex_thread") } -TEST ("error_cleared_on_join") -{ - //when a thread/job is finished, there must be no pending errors -} - TESTS_END From e55e648f29b4c7654bc6a04edc276d5be21cf106 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 18 Jan 2010 00:34:53 +0100 Subject: [PATCH 44/48] Thread syncronization and joining add a custom defined range for states provide functions for barrier like syncing between 2 threads provide joinable threads and a thread_join() function --- src/backend/threads.c | 100 ++++++++++++++++++++++++++++++++++++++++-- src/backend/threads.h | 76 ++++++++++++++++++++++++++++---- 2 files changed, 164 insertions(+), 12 deletions(-) diff --git a/src/backend/threads.c b/src/backend/threads.c index 3dd1bdbae..3c175e81a 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -59,18 +59,37 @@ const char* lumiera_threadstate_names[] = { }; #undef LUMIERA_THREAD_STATE -static void* thread_loop (void* thread) +LUMIERA_ERROR_DEFINE(THREAD, "fatal threads initialization error"); + +/* thread local storage pointing back to the thread structure of each thread */ +static pthread_key_t lumiera_thread_tls; +static pthread_once_t lumiera_thread_initialized = PTHREAD_ONCE_INIT; + +static void +lumiera_thread_tls_init (void) +{ + if (!!pthread_key_create (&lumiera_thread_tls, NULL)) + LUMIERA_DIE (THREAD); /* should never happen */ +} + + +static void* +thread_loop (void* thread) { TRACE (threads); NOBUG_THREAD_ID_SET ("worker"); LumieraThread t = (LumieraThread)thread; + pthread_setspecific (lumiera_thread_tls, t); + pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL); REQUIRE (t, "thread does not exist"); LUMIERA_CONDITION_SECTION (threads, &t->signal) { + t->rh = &lumiera_lock_section_.rh; + do { // NULL function means: no work to do INFO (threads, "function %p", t->function); @@ -80,10 +99,21 @@ static void* thread_loop (void* thread) LUMIERA_CONDITION_WAIT (t->state != LUMIERA_THREADSTATE_IDLE); INFO (threads, "Thread awaken with state %d", t->state); } while (t->state != LUMIERA_THREADSTATE_SHUTDOWN); - // SHUTDOWN state + // SHUTDOWN state + + if (t->kind & LUMIERA_THREAD_JOINABLE) + { + INFO (threads, "Thread zombified"); + /* move error state to data the other thread will it pick up from there */ + t->arguments = (void*)lumiera_error (); + t->state = LUMIERA_THREADSTATE_ZOMBIE; + LUMIERA_CONDITION_WAIT (t->state == LUMIERA_THREADSTATE_JOINED); + INFO (threads, "Thread joined"); + } INFO (threads, "Thread Shutdown"); } + TODO ("no error must be pending here, else do app shutdown"); return 0; } @@ -126,9 +156,10 @@ lumiera_thread_new (enum lumiera_thread_class kind, struct nobug_flag* flag, pthread_attr_t* attrs) { + pthread_once (&lumiera_thread_initialized, lumiera_thread_tls_init); + // TODO: do something with these: (void) purpose; - REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "invalid thread kind specified: %d", kind); REQUIRE (attrs, "invalid pthread attributes structure passed"); LumieraThread self = lumiera_malloc (sizeof (*self)); @@ -183,6 +214,69 @@ lumiera_thread_delete (LumieraThread self) lumiera_free (lumiera_thread_destroy (self)); } + +LumieraThread +lumiera_thread_self (void) +{ + pthread_once (&lumiera_thread_initialized, lumiera_thread_tls_init); + return pthread_getspecific (lumiera_thread_tls); +} + + +LumieraThread +lumiera_thread_sync_other (LumieraThread other, int state) +{ + TRACE(threads); + + LUMIERA_CONDITION_SECTION (threads, &other->signal) + { + REQUIRE (other->state == ~state); TODO("Runtime error when state expectation isnt met"); + other->state = state; + LUMIERA_CONDITION_SIGNAL; + } + return other; +} + + +LumieraThread +lumiera_thread_sync (int state) +{ + TRACE(threads); + + LumieraThread self = lumiera_thread_self (); + REQUIRE(self, "not a lumiera thread"); + + self->state = ~state; + + TODO("error handing, maybe timed mutex (using the threads heartbeat timeout, shortly before timeout)"); + + do { + lumiera_condition_wait (&self->signal, &NOBUG_FLAG(threads), self->rh); + } while (self->state != state); + + return self; +} + + + +lumiera_err +lumiera_thread_join (LumieraThread thread) +{ + TRACE(threads); + lumiera_err ret = NULL; + + LUMIERA_CONDITION_SECTION (threads, &thread->signal) + { + LUMIERA_CONDITION_WAIT (thread->state == LUMIERA_THREADSTATE_ZOMBIE); + ret = (lumiera_err)thread->arguments; + thread->state = LUMIERA_THREADSTATE_JOINED; + LUMIERA_CONDITION_SIGNAL; /* kiss it a last goodbye */ + } + return ret; +} + + + /* // Local Variables: // mode: C diff --git a/src/backend/threads.h b/src/backend/threads.h index 42d76bcfe..34a38eb40 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -80,10 +80,15 @@ enum lumiera_thread_class * flag to let the decision to run the function in a thread open to the backend. * depending on load it might decide to run it sequentially. * This has some constraints: - * The condition variable to signal the finish of the thread must not be used. * The Thread must be very careful with locking, better don't. + * TODO explain syncronization issues **/ - LUMIERA_THREAD_OR_NOT = 1<<16 + LUMIERA_THREAD_OR_NOT = 1<<16, + + /** + * Thread must be joined finally + **/ + LUMIERA_THREAD_JOINABLE = 1<<17 }; #undef LUMIERA_THREAD_CLASS @@ -95,11 +100,13 @@ extern const char* lumiera_threadclass_names[]; // on one hand it could be used to tell the current state of the thread // on the other, it is used to tell the thread which state to enter on next iteration #define LUMIERA_THREAD_STATES \ - LUMIERA_THREAD_STATE(IDLE) \ LUMIERA_THREAD_STATE(ERROR) \ + LUMIERA_THREAD_STATE(IDLE) \ LUMIERA_THREAD_STATE(RUNNING) \ LUMIERA_THREAD_STATE(WAKEUP) \ LUMIERA_THREAD_STATE(SHUTDOWN) \ + LUMIERA_THREAD_STATE(ZOMBIE) \ + LUMIERA_THREAD_STATE(JOINED) \ LUMIERA_THREAD_STATE(STARTUP) #define LUMIERA_THREAD_STATE(name) LUMIERA_THREADSTATE_##name, @@ -108,9 +115,12 @@ extern const char* lumiera_threadclass_names[]; * Thread state. * These are the only states our threads can be in. */ -typedef enum +typedef enum { LUMIERA_THREAD_STATES + + LUMIERA_THREADSTATE_CUSTOM_START = 1024, + LUMIERA_THREADSTATE_CUSTOM_END = 32768, } lumiera_thread_state; @@ -127,18 +137,20 @@ extern const char* lumiera_threadstate_names[]; struct lumiera_thread_struct { llist node; // this should be first for easy casting - // the function and argument can be passed to the thread at creation time - // void (*function)(void*); - // void* arg; + pthread_t id; // TODO: maybe this condition variable should be renamed when we have a better understanding of how it will be used lumiera_condition signal; // control signal, state change signal + + struct nobug_resource_user** rh; + // the following member could have been called "class" except that it would conflict with C++ keyword // as consequence, it's been decided to leave the type name containing the word "class", // while all members/variables called "kind" - enum lumiera_thread_class kind; + int kind; + // this is used both as a command and as a state tracker - lumiera_thread_state state; + int state; void (*function)(void *); void * arguments; }; @@ -189,6 +201,52 @@ lumiera_thread_run (enum lumiera_thread_class kind, const char* purpose, struct nobug_flag* flag); +/** + * Query the LumieraThread handle of the current thread + * + * + * @return pointer to the (opaque) handle of the current lumiera thread or NULL when this is not a lumiera thread + */ +LumieraThread +lumiera_thread_self (void); + + +/** + * Thread syncronization + * Lumiera threads can be syncronized with custom states. + * The syncronization primitives act as barrier over 2 threads, any thread reaching a syncronization + * point first is blocked until the other one reaches it with the same state. + * Providing different states is errorneous! + */ + + +/** + * Syncronize with another threads state + * + * this blocks until/unless the other thread reaches 'state' + */ +LumieraThread +lumiera_thread_sync_other (LumieraThread other, int state); + +/** + * Syncronize current thread + * + * signifies that this thread reached 'state' and blocks until/unless + * some other thread synced with this state + * @return on success pointer to self (opaque), or NULL on error + */ +LumieraThread +lumiera_thread_sync (int state); + +/** + * Joining threads + * a thread can be set up with the LUMEIRA_THREAD_JOINABLE flag, if so + * then it must be joined finally. Joining clears the error state of the joined thread + * and returns it to the joiner. + * + */ +lumiera_err +lumiera_thread_join (LumieraThread thread); #endif /* From 87918c657c4d013489dd9f8fcb052c15b7e7a57f Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 18 Jan 2010 14:23:23 +0100 Subject: [PATCH 45/48] check wait condition before loop body --- src/lib/condition.h | 9 ++++----- src/lib/reccondition.h | 9 ++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/lib/condition.h b/src/lib/condition.h index 51abfb61a..9ad3370d7 100644 --- a/src/lib/condition.h +++ b/src/lib/condition.h @@ -92,12 +92,12 @@ * @param expr Conditon which must become true, else the condition variable goes back into sleep */ #define LUMIERA_CONDITION_WAIT(expr) \ - do { \ + while (!(expr)) { \ REQUIRE (lumiera_lock_section_.lock, "Condition mutex not locked"); \ lumiera_condition_wait (lumiera_lock_section_.lock, \ lumiera_lock_section_.flag, \ &lumiera_lock_section_.rh); \ - } while (!(expr)) + } /** @@ -108,15 +108,14 @@ * sets LUMIERA_ERROR_LOCK_TIMEOUT when the timeout passed */ #define LUMIERA_CONDITION_TIMEDWAIT(expr, timeout) \ - do { \ + while (!(expr)) { \ REQUIRE (lumiera_lock_section_.lock, "Condition mutex not locked"); \ if (!lumiera_condition_timedwait (lumiera_lock_section_.lock, \ timeout, \ lumiera_lock_section_.flag, \ &lumiera_lock_section_.rh)) \ break; \ - } while (!(expr)) - + } /** * Signal a condition variable diff --git a/src/lib/reccondition.h b/src/lib/reccondition.h index bbb321861..b8b8fbd97 100644 --- a/src/lib/reccondition.h +++ b/src/lib/reccondition.h @@ -91,12 +91,12 @@ * @param expr Condition which must become true, else the condition variable goes back into sleep */ #define LUMIERA_RECCONDITION_WAIT(expr) \ - do { \ + while (!(expr)) { \ REQUIRE (lumiera_lock_section_.lock, "Reccondition mutex not locked"); \ lumiera_reccondition_wait (lumiera_lock_section_.lock, \ lumiera_lock_section_.flag, \ &lumiera_lock_section_.rh); \ - } while (!(expr)) + } /** @@ -107,15 +107,14 @@ * sets LUMIERA_ERROR_LOCK_TIMEOUT when the timeout passed */ #define LUMIERA_RECCONDITION_TIMEDWAIT(expr, timeout) \ - do { \ + while (!(expr)) { \ REQUIRE (lumiera_lock_section_.lock, "Reccondition mutex not locked"); \ if (!lumiera_reccondition_timedwait (lumiera_lock_section_.lock, \ timeout, \ lumiera_lock_section_.flag, \ &lumiera_lock_section_.rh)) \ break; \ - } while (!(expr)) - + } From cc4dc25f4ad88402988f08cdbd642d5790e8a3e7 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 18 Jan 2010 16:23:28 +0100 Subject: [PATCH 46/48] while loop is little more solid than do..while --- src/backend/threads.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/threads.c b/src/backend/threads.c index 3c175e81a..d52c7eb2c 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -250,9 +250,9 @@ lumiera_thread_sync (int state) TODO("error handing, maybe timed mutex (using the threads heartbeat timeout, shortly before timeout)"); - do { + while (self->state != state) { lumiera_condition_wait (&self->signal, &NOBUG_FLAG(threads), self->rh); - } while (self->state != state); + } return self; } From 7371db8a2c385ef7dfc326268f2bdfd96d933a2d Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 18 Jan 2010 16:24:45 +0100 Subject: [PATCH 47/48] thread deadlines, first implementation --- src/backend/threads.c | 64 +++++++++++++++++++++++++++++++++++++++++++ src/backend/threads.h | 36 ++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/src/backend/threads.c b/src/backend/threads.c index d52c7eb2c..ded04a60e 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -33,6 +33,7 @@ //TODO: System includes// #include +#include #include /** @@ -136,6 +137,8 @@ lumiera_thread_run (enum lumiera_thread_class kind, self->function = function; self->arguments = arg; + self->deadline.tv_sec = 0; + // and let it really run (signal the condition var, the thread waits on it) self->state = LUMIERA_THREADSTATE_WAKEUP; @@ -169,6 +172,8 @@ lumiera_thread_new (enum lumiera_thread_class kind, self->state = LUMIERA_THREADSTATE_STARTUP; self->function = NULL; self->arguments = NULL; + self->deadline.tv_sec = 0; + self->deadline.tv_nsec = 0; int error = pthread_create (&self->id, attrs, &thread_loop, self); if (error) @@ -223,6 +228,65 @@ lumiera_thread_self (void) } +/** + * Set a threads deadline + * A thread must finish before its deadline is hit. Otherwise it counts as stalled + * which is a fatal error which might pull the application down. + */ +LumieraThread +lumiera_thread_deadline_set (struct timespec deadline) +{ + LumieraThread self = lumiera_thread_self (); + if (self) + self->deadline = deadline; + return self; +} + + +/** + * Extend a threads deadline + * sets the deadline to now+ms in future. This can be used to implement a heartbeat. + */ +LumieraThread +lumiera_thread_deadline_extend (unsigned ms) +{ + LumieraThread self = lumiera_thread_self (); + if (self) + { + struct timespec deadline; + clock_gettime (CLOCK_REALTIME, &deadline); + deadline.tv_sec += ms / 1000; + deadline.tv_nsec += 1000000 * (ms % 1000); + if (deadline.tv_nsec > 1000000000) + { + deadline.tv_sec += (deadline.tv_nsec / 1000000000); + deadline.tv_nsec %= 1000000000; + } + self->deadline = deadline; + } + + return self; +} + + +/** + * Clear a threads deadline + * Threads without deadline will not be checked against deadlocks (this is the default) + */ +LumieraThread +lumiera_thread_deadline_clear (void) +{ + LumieraThread self = lumiera_thread_self (); + if (self) + { + self->deadline.tv_sec = 0; + self->deadline.tv_nsec = 0; + } + return self; +} + + + LumieraThread lumiera_thread_sync_other (LumieraThread other, int state) { diff --git a/src/backend/threads.h b/src/backend/threads.h index 34a38eb40..131d25911 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -142,6 +142,8 @@ struct lumiera_thread_struct // TODO: maybe this condition variable should be renamed when we have a better understanding of how it will be used lumiera_condition signal; // control signal, state change signal + struct timespec deadline; + struct nobug_resource_user** rh; // the following member could have been called "class" except that it would conflict with C++ keyword @@ -210,6 +212,40 @@ lumiera_thread_run (enum lumiera_thread_class kind, LumieraThread lumiera_thread_self (void); +/** + * Heartbeat and Deadlines + * + * Any thread can have an optional 'deadline' which must never be hit. + * This deadlines are lazily checked and if hit this is a fatal error which triggers + * an emergency shutdown. Thus threads are obliged to set and extend their deadlines + * accordingly. + * + */ + +/** + * Set a threads deadline + * A thread must finish before its deadline is hit. Otherwise it counts as stalled + * which is a fatal error which might pull the application down. + */ +LumieraThread +lumiera_thread_deadline_set (struct timespec deadline); + + +/** + * Extend a threads deadline + * sets the deadline to now+ms in future. This can be used to implement a heartbeat. + */ +LumieraThread +lumiera_thread_deadline_extend (unsigned ms); + + +/** + * Clear a threads deadline + * Threads without deadline will not be checked against deadlocks (this is the default) + */ +LumieraThread +lumiera_thread_deadline_clear (void); + /** * Thread syncronization From 020908d6238147ca35a053f8e3f98408d758985f Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 18 Jan 2010 17:53:33 +0100 Subject: [PATCH 48/48] Make threadpool_destroy wait until all threads are finished adds a state to each threadpool which can be only offline or online. One can not acquire new threads when the pool is offline. no need for waits in the teststuite anymore. --- src/backend/threadpool.c | 88 ++++++++++++++++++++++----------- src/backend/threadpool.h | 6 +++ tests/backend/test-threadpool.c | 4 -- 3 files changed, 64 insertions(+), 34 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index ea88b4503..9de1e6d81 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -39,6 +39,7 @@ static lumiera_threadpool threadpool; */ NOBUG_DEFINE_FLAG_PARENT (threadpool, threads_dbg); /*TODO insert a suitable/better parent flag here */ +LUMIERA_ERROR_DEFINE(THREADPOOL_OFFLINE, "tried to acquire thread while threadpool is not available"); //code goes here// @@ -56,6 +57,7 @@ lumiera_threadpool_init(void) llist_init (&threadpool.pool[i].idle_list); threadpool.pool[i].thread_count = 0; threadpool.pool[i].idle_thread_count = 0; + threadpool.pool[i].status = LUMIERA_THREADPOOL_ONLINE; //TODO: configure each pools' pthread_attrs appropriately pthread_attr_init (&threadpool.pool[i].pthread_attrs); @@ -70,9 +72,27 @@ lumiera_threadpool_destroy(void) { TRACE (threadpool); + /* set all threadpools offline must be done first, since running threads may attempt to start new ones */ + for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) + LUMIERA_CONDITION_SECTION (threadpool, &threadpool.pool[i].sync) + threadpool.pool[i].status = LUMIERA_THREADPOOL_OFFLINE; + + /* wait that all theads have finished */ + for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) + { + LUMIERA_CONDITION_SECTION (threadpool, &threadpool.pool[i].sync) + { + TODO ("check threads deadlines, kill them when they are stalled"); + TODO ("for threads without deadline use a timeout from config system, 500ms or so by default"); + LUMIERA_CONDITION_WAIT(llist_is_empty (&threadpool.pool[i].working_list)); + } + } + + /* now we can delete all threads */ for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { TRACE (threadpool, "destroying individual pool #%d", i); + LUMIERA_CONDITION_SECTION (threadpool, &threadpool.pool[i].sync) { REQUIRE (threadpool.pool[i].thread_count @@ -100,11 +120,14 @@ lumiera_threadpool_destroy(void) } } - +/** + * + * @return thread handle or NULL on error (lumiera error will be set) + */ LumieraThread -lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, - const char* purpose, - struct nobug_flag* flag) +lumiera_threadpool_acquire_thread (enum lumiera_thread_class kind, + const char* purpose, + struct nobug_flag* flag) { TRACE (threadpool); LumieraThread ret = NULL; @@ -113,34 +136,39 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, LUMIERA_CONDITION_SECTION (threadpool, &threadpool.pool[kind].sync) { - if (llist_is_empty (&threadpool.pool[kind].idle_list)) + if (threadpool.pool[kind].status != LUMIERA_THREADPOOL_ONLINE) + LUMIERA_ERROR_SET_WARNING (threadpool, THREADPOOL_OFFLINE, purpose); + else { - ret = lumiera_thread_new (kind, purpose, flag, - &threadpool.pool[kind].pthread_attrs); - ENSURE (ret, "did not create a valid thread"); - TODO ("no error handing, let the resourcecollector do it, no need when returning the thread"); - threadpool.pool[kind].thread_count++; - LUMIERA_CONDITION_WAIT (!llist_is_empty (&threadpool.pool[kind].idle_list)); + if (llist_is_empty (&threadpool.pool[kind].idle_list)) + { + ret = lumiera_thread_new (kind, purpose, flag, + &threadpool.pool[kind].pthread_attrs); + ENSURE (ret, "did not create a valid thread"); + TODO ("no error handing, let the resourcecollector do it, no need when returning the thread"); + threadpool.pool[kind].thread_count++; + LUMIERA_CONDITION_WAIT (!llist_is_empty (&threadpool.pool[kind].idle_list)); + } + // use an existing thread, pick the first one + // remove it from the pool's list + ret = (LumieraThread) (llist_head (&threadpool.pool[kind].idle_list)); + + ENSURE (ret, "did not find a valid thread"); + + REQUIRE (ret->state == LUMIERA_THREADSTATE_IDLE, "trying to return a non-idle thread (state=%s)", lumiera_threadstate_names[ret->state]); + + // move thread to the working_list + llist_insert_head (&threadpool.pool[kind].working_list, &ret->node); + + threadpool.pool[kind].idle_thread_count--; // cheaper than using llist_count + REQUIRE ((int)(llist_count (&threadpool.pool[kind].working_list) + + llist_count (&threadpool.pool[kind].idle_list)) + == threadpool.pool[kind].thread_count, + "threadpool counter miscalculation (working_list count = %u, idle_list count = %u, thread_count = %d )", + llist_count (&threadpool.pool[kind].working_list), + llist_count (&threadpool.pool[kind].idle_list), + threadpool.pool[kind].thread_count); } - // use an existing thread, pick the first one - // remove it from the pool's list - ret = (LumieraThread) (llist_head (&threadpool.pool[kind].idle_list)); - - ENSURE (ret, "did not find a valid thread"); - - REQUIRE (ret->state == LUMIERA_THREADSTATE_IDLE, "trying to return a non-idle thread (state=%s)", lumiera_threadstate_names[ret->state]); - - // move thread to the working_list - llist_insert_head (&threadpool.pool[kind].working_list, &ret->node); - - threadpool.pool[kind].idle_thread_count--; // cheaper than using llist_count - REQUIRE ((int)(llist_count (&threadpool.pool[kind].working_list) - + llist_count (&threadpool.pool[kind].idle_list)) - == threadpool.pool[kind].thread_count, - "threadpool counter miscalculation (working_list count = %u, idle_list count = %u, thread_count = %d )", - llist_count (&threadpool.pool[kind].working_list), - llist_count (&threadpool.pool[kind].idle_list), - threadpool.pool[kind].thread_count); } return ret; } diff --git a/src/backend/threadpool.h b/src/backend/threadpool.h index 47d90e6fc..5a3455d39 100644 --- a/src/backend/threadpool.h +++ b/src/backend/threadpool.h @@ -64,6 +64,11 @@ lumiera_threadpool_release_thread(LumieraThread thread); typedef struct lumiera_threadpool_struct lumiera_threadpool; typedef lumiera_threadpool* LumieraThreadpool; +enum lumiera_threadpool_state { + LUMIERA_THREADPOOL_OFFLINE, + LUMIERA_THREADPOOL_ONLINE +}; + struct lumiera_threadpool_struct { struct @@ -74,6 +79,7 @@ struct lumiera_threadpool_struct int idle_thread_count; pthread_attr_t pthread_attrs; lumiera_condition sync; + enum lumiera_threadpool_state status; } pool[LUMIERA_THREADCLASS_COUNT]; }; diff --git a/tests/backend/test-threadpool.c b/tests/backend/test-threadpool.c index 2acb8b861..952bfac2b 100644 --- a/tests/backend/test-threadpool.c +++ b/tests/backend/test-threadpool.c @@ -172,8 +172,6 @@ TEST ("no-function") &NOBUG_FLAG(NOBUG_ON)); // cleanup - ECHO("wait 1 sec"); - usleep(1000000); ECHO("finished waiting"); lumiera_threadpool_destroy(); } @@ -195,8 +193,6 @@ TEST ("process-function") &NOBUG_FLAG(NOBUG_ON)); // struct nobug_flag* flag) // cleanup - ECHO("wait 1 sec"); - usleep(1000000); ECHO("finished waiting"); lumiera_threadpool_destroy(); }