2009-11-23 01:55:08 +01:00
/*
threadpool . c - Manage pools of threads
Copyright ( C ) Lumiera . org
2009 , Michael Ploujnikov < ploujj @ gmail . com >
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation ; either version 2 of the
License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
//TODO: Support library includes//
# include "include/logging.h"
# include "lib/safeclib.h"
//TODO: Lumiera header includes//
# include "backend/threadpool.h"
//TODO: internal/static forward declarations//
2009-11-23 22:40:31 +01:00
static lumiera_threadpool threadpool ;
2009-11-23 01:55:08 +01:00
//TODO: System includes//
# include <pthread.h>
/**
* @ file
*
*/
2009-11-25 04:25:00 +01:00
NOBUG_DEFINE_FLAG_PARENT ( threadpool , threads_dbg ) ; /*TODO insert a suitable/better parent flag here */
2009-11-23 01:55:08 +01:00
//code goes here//
void
2009-12-31 13:24:07 +01:00
lumiera_threadpool_init ( void )
2009-11-23 01:55:08 +01:00
{
2010-01-04 23:03:47 +01:00
NOBUG_INIT_FLAG ( threadpool ) ;
2009-12-24 01:50:59 +01:00
NOBUG_INIT_FLAG ( threads ) ;
2010-01-04 23:03:47 +01:00
TRACE ( threadpool ) ;
2010-01-07 13:18:23 +01:00
NOBUG_INIT_FLAG ( threads ) ;
2010-01-04 23:03:47 +01:00
2009-11-23 22:40:31 +01:00
for ( int i = 0 ; i < LUMIERA_THREADCLASS_COUNT ; + + i )
{
2010-01-10 03:36:20 +01:00
llist_init ( & threadpool . pool [ i ] . working_list ) ;
llist_init ( & threadpool . pool [ i ] . idle_list ) ;
2010-01-16 17:48:48 +01:00
threadpool . pool [ i ] . thread_count = 0 ;
2009-11-26 17:27:50 +01:00
threadpool . pool [ i ] . idle_thread_count = 0 ;
2009-12-03 04:21:49 +01:00
//TODO: configure each pools' pthread_attrs appropriately
pthread_attr_init ( & threadpool . pool [ i ] . pthread_attrs ) ;
//cancel...
2010-01-04 23:03:47 +01:00
lumiera_condition_init ( & threadpool . pool [ i ] . sync , " pool of threads " , & NOBUG_FLAG ( threadpool ) ) ;
2009-11-23 22:40:31 +01:00
}
}
2009-11-23 01:55:08 +01:00
2009-11-25 04:25:00 +01:00
void
lumiera_threadpool_destroy ( void )
{
2010-01-04 23:03:47 +01:00
TRACE ( threadpool ) ;
2009-12-24 01:50:59 +01:00
2009-11-25 04:25:00 +01:00
for ( int i = 0 ; i < LUMIERA_THREADCLASS_COUNT ; + + i )
{
2010-01-04 23:03:47 +01:00
TRACE ( threadpool , " destroying individual pool #%d " , i ) ;
LUMIERA_CONDITION_SECTION ( threadpool , & threadpool . pool [ i ] . sync )
{
2010-01-16 17:48:48 +01:00
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 ,
2010-01-10 03:36:20 +01:00
llist_count ( & threadpool . pool [ i ] . working_list ) ) ;
2010-01-16 17:48:48 +01:00
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 ) ;
2010-01-10 03:36:20 +01:00
LLIST_WHILE_HEAD ( & threadpool . pool [ i ] . idle_list , t )
2010-01-04 23:03:47 +01:00
{
lumiera_thread_delete ( ( LumieraThread ) t ) ;
2010-01-16 17:48:48 +01:00
threadpool . pool [ i ] . thread_count - - ;
2010-01-04 23:03:47 +01:00
}
}
lumiera_condition_destroy ( & threadpool . pool [ i ] . sync , & NOBUG_FLAG ( threadpool ) ) ;
2009-12-03 04:21:49 +01:00
pthread_attr_destroy ( & threadpool . pool [ i ] . pthread_attrs ) ;
2009-11-25 04:25:00 +01:00
}
}
2009-12-23 19:10:31 +01:00
2009-11-23 01:55:08 +01:00
LumieraThread
lumiera_threadpool_acquire_thread ( enum lumiera_thread_class kind ,
const char * purpose ,
struct nobug_flag * flag )
{
2010-01-04 23:03:47 +01:00
TRACE ( threadpool ) ;
LumieraThread ret = NULL ;
2009-11-25 04:25:00 +01:00
REQUIRE ( kind < LUMIERA_THREADCLASS_COUNT , " unknown pool kind specified: %d " , kind ) ;
2010-01-04 23:03:47 +01:00
LUMIERA_CONDITION_SECTION ( threadpool , & threadpool . pool [ kind ] . sync )
2009-11-23 02:08:08 +01:00
{
2010-01-11 21:04:52 +01:00
if ( llist_is_empty ( & threadpool . pool [ kind ] . idle_list ) )
2010-01-04 23:03:47 +01:00
{
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 " ) ;
2010-01-16 17:48:48 +01:00
threadpool . pool [ kind ] . thread_count + + ;
2010-01-14 22:46:27 +01:00
LUMIERA_CONDITION_WAIT ( ! llist_is_empty ( & threadpool . pool [ kind ] . idle_list ) ) ;
2010-01-04 23:03:47 +01:00
}
// use an existing thread, pick the first one
// remove it from the pool's list
2010-01-12 13:39:12 +01:00
ret = ( LumieraThread ) ( llist_head ( & threadpool . pool [ kind ] . idle_list ) ) ;
2010-01-11 21:04:52 +01:00
ENSURE ( ret , " did not find a valid thread " ) ;
2010-01-04 23:03:47 +01:00
REQUIRE ( ret - > state = = LUMIERA_THREADSTATE_IDLE , " trying to return a non-idle thread (state=%s) " , lumiera_threadstate_names [ ret - > state ] ) ;
2010-01-11 21:04:52 +01:00
2010-01-12 13:39:12 +01:00
// move thread to the working_list
2010-01-14 22:46:27 +01:00
llist_insert_head ( & threadpool . pool [ kind ] . working_list , & ret - > node ) ;
2010-01-11 21:04:52 +01:00
2010-01-04 23:03:47 +01:00
threadpool . pool [ kind ] . idle_thread_count - - ; // cheaper than using llist_count
2010-01-16 17:48:48 +01:00
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 ) ;
2009-11-23 02:08:08 +01:00
}
2009-11-25 04:25:00 +01:00
return ret ;
2009-11-23 01:55:08 +01:00
}
2009-12-23 19:10:31 +01:00
// TODO: rename to lumiera_threadpool_park_thread
2009-11-23 22:51:18 +01:00
void
lumiera_threadpool_release_thread ( LumieraThread thread )
{
2010-01-04 23:03:47 +01:00
TRACE ( threadpool ) ;
2009-11-25 17:06:53 +01:00
REQUIRE ( thread , " invalid thread given " ) ;
REQUIRE ( thread - > kind < LUMIERA_THREADCLASS_COUNT , " thread belongs to an unknown pool kind: %d " , thread - > kind ) ;
2009-11-25 23:43:22 +01:00
2010-01-04 23:03:47 +01:00
REQUIRE ( thread - > state ! = LUMIERA_THREADSTATE_IDLE , " trying to park an already idle thread " ) ;
LUMIERA_CONDITION_SECTION ( threadpool , & threadpool . pool [ thread - > kind ] . sync )
2009-12-02 19:48:08 +01:00
{
2010-01-04 23:03:47 +01:00
thread - > state = LUMIERA_THREADSTATE_IDLE ;
2010-01-16 17:48:48 +01:00
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
2010-01-12 13:39:12 +01:00
// move thread to the idle_list
2010-01-11 21:04:52 +01:00
llist_insert_head ( & threadpool . pool [ thread - > kind ] . idle_list , & thread - > node ) ;
2010-01-04 23:03:47 +01:00
threadpool . pool [ thread - > kind ] . idle_thread_count + + ; // cheaper than using llist_count
2010-01-16 17:48:48 +01:00
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 ) ;
2010-01-04 23:03:47 +01:00
2010-01-14 22:46:27 +01:00
REQUIRE ( ! llist_is_empty ( & threadpool . pool [ thread - > kind ] . idle_list ) , " thread pool is still empty after insertion " ) ;
2010-01-04 23:03:47 +01:00
LUMIERA_CONDITION_BROADCAST ;
2009-12-02 19:48:08 +01:00
}
2009-11-23 22:51:18 +01:00
}
2009-11-23 01:55:08 +01:00
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/