summaryrefslogtreecommitdiffstats
path: root/libhb/taskset.c
diff options
context:
space:
mode:
authorjstebbins <[email protected]>2012-05-18 06:54:25 +0000
committerjstebbins <[email protected]>2012-05-18 06:54:25 +0000
commit6a31263baa876f3cf0eba0aa88a7dbc69239b8ab (patch)
treeb08444c845d3cb2a9e4961f11f2f80969542b1f4 /libhb/taskset.c
parent5a0673d1572fdfcd00063cfa9dffba907c808056 (diff)
Forgot to svn add some taskset files
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@4686 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb/taskset.c')
-rw-r--r--libhb/taskset.c231
1 files changed, 231 insertions, 0 deletions
diff --git a/libhb/taskset.c b/libhb/taskset.c
new file mode 100644
index 000000000..2721139a5
--- /dev/null
+++ b/libhb/taskset.c
@@ -0,0 +1,231 @@
+/* $Id$
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
+#include "hb.h"
+#include "ports.h"
+#include "taskset.h"
+
+int
+taskset_init( taskset_t *ts, int thread_count, size_t arg_size )
+{
+ int init_step;
+
+ init_step = 0;
+ memset( ts, 0, sizeof( *ts ) );
+ ts->thread_count = thread_count;
+ ts->arg_size = arg_size;
+ ts->bitmap_elements = ( ts->thread_count + 31 ) / 32;
+ ts->task_threads = malloc( sizeof( hb_thread_t* ) * ts->thread_count );
+ if( ts->task_threads == NULL )
+ goto fail;
+ init_step++;
+
+ if( arg_size != 0 )
+ {
+ ts->task_threads_args = malloc( arg_size * ts->thread_count );
+ if( ts->task_threads == NULL )
+ goto fail;
+ }
+ init_step++;
+
+ ts->task_begin_bitmap = malloc( sizeof( uint32_t ) * ts->bitmap_elements );
+ if( ts->task_begin_bitmap == NULL )
+ goto fail;
+ init_step++;
+
+ ts->task_complete_bitmap = malloc( sizeof( uint32_t ) * ts->bitmap_elements );
+ if( ts->task_complete_bitmap == NULL )
+ goto fail;
+ init_step++;
+
+ ts->task_stop_bitmap = malloc( sizeof( uint32_t ) * ts->bitmap_elements );
+ if( ts->task_stop_bitmap == NULL )
+ goto fail;
+ init_step++;
+
+ ts->task_cond_lock = hb_lock_init();
+ if( ts->task_cond_lock == NULL)
+ goto fail;
+ init_step++;
+
+ ts->task_begin = hb_cond_init();
+ if( ts->task_begin == NULL)
+ goto fail;
+ init_step++;
+
+ ts->task_complete = hb_cond_init();
+ if( ts->task_complete == NULL)
+ goto fail;
+ init_step++;
+
+ /*
+ * Initialize all arg data to 0.
+ */
+ memset(ts->task_threads_args, 0, ts->arg_size * ts->thread_count );
+
+ /*
+ * Inialize bitmaps to all bits set. This means that any unused bits
+ * in the bitmap are already in the "condition satisfied" state allowing
+ * us to test the bitmap 32bits at a time without having to mask off
+ * the end.
+ */
+ memset(ts->task_begin_bitmap, 0xFF, sizeof( uint32_t ) * ts->bitmap_elements );
+ memset(ts->task_complete_bitmap, 0xFF, sizeof( uint32_t ) * ts->bitmap_elements );
+ memset(ts->task_stop_bitmap, 0, sizeof( uint32_t ) * ts->bitmap_elements );
+
+ /*
+ * Important to start off with the threads locked waiting
+ * on input, no work completed, and not asked to stop.
+ */
+ bit_nclear( ts->task_begin_bitmap, 0, ts->thread_count - 1 );
+ bit_nclear( ts->task_complete_bitmap, 0, ts->thread_count - 1 );
+ bit_nclear( ts->task_stop_bitmap, 0, ts->thread_count - 1 );
+ return (1);
+
+fail:
+ switch (init_step)
+ {
+ default:
+ hb_cond_close( &ts->task_complete );
+ /* FALL THROUGH */
+ case 7:
+ hb_cond_close( &ts->task_begin );
+ /* FALL THROUGH */
+ case 6:
+ hb_lock_close( &ts->task_cond_lock );
+ /* FALL THROUGH */
+ case 5:
+ free( ts->task_stop_bitmap );
+ /* FALL THROUGH */
+ case 4:
+ free( ts->task_complete_bitmap );
+ /* FALL THROUGH */
+ case 3:
+ free( ts->task_begin_bitmap );
+ /* FALL THROUGH */
+ case 2:
+ if( ts->task_threads_args == NULL )
+ free( ts->task_threads_args );
+ /* FALL THROUGH */
+ case 1:
+ free( ts->task_threads );
+ /* FALL THROUGH */
+ case 0:
+ break;
+ }
+ return (0);
+}
+
+int
+taskset_thread_spawn( taskset_t *ts, int thr_idx, const char *descr,
+ thread_func_t *func, int priority )
+{
+ ts->task_threads[thr_idx] = hb_thread_init( descr, func,
+ taskset_thread_args( ts, thr_idx ),
+ priority);
+ return( ts->task_threads[thr_idx] != NULL );
+}
+
+void
+taskset_cycle( taskset_t *ts )
+{
+ hb_lock( ts->task_cond_lock );
+
+ /*
+ * Signal all threads that their work is available.
+ */
+ bit_nset( ts->task_begin_bitmap, 0, ts->thread_count - 1 );
+ hb_cond_broadcast( ts->task_begin );
+
+ /*
+ * Wait until all threads have completed. Note that we must
+ * loop here as hb_cond_wait() on some platforms (e.g pthead_cond_wait)
+ * may unblock prematurely.
+ */
+ do
+ {
+ hb_cond_wait( ts->task_complete, ts->task_cond_lock );
+ } while ( !allbits_set( ts->task_complete_bitmap, ts->bitmap_elements ) );
+
+ /*
+ * Clear completion indications for next time.
+ */
+ bit_nclear( ts->task_complete_bitmap, 0, ts->thread_count - 1 );
+
+ hb_unlock( ts->task_cond_lock );
+}
+
+/*
+ * Block current thread until work is available for it.
+ */
+void
+taskset_thread_wait4start( taskset_t *ts, int thr_idx )
+{
+ hb_lock( ts->task_cond_lock );
+ while ( bit_is_clear( ts->task_begin_bitmap, thr_idx ) )
+ hb_cond_wait( ts->task_begin, ts->task_cond_lock );
+
+ /*
+ * We've been released for one run. Insure we block the next
+ * time through the loop.
+ */
+ bit_clear( ts->task_begin_bitmap, thr_idx );
+ hb_unlock( ts->task_cond_lock );
+}
+
+/*
+ * Current thread has completed its work. Indicate completion,
+ * and if all threads in this task set have completed, wakeup
+ * anyone waiting for this condition.
+ */
+void
+taskset_thread_complete( taskset_t *ts, int thr_idx )
+{
+ hb_lock( ts->task_cond_lock );
+ bit_set( ts->task_complete_bitmap, thr_idx );
+ if( allbits_set( ts->task_complete_bitmap, ts->bitmap_elements ) )
+ {
+ hb_cond_signal( ts->task_complete );
+ }
+ hb_unlock( ts->task_cond_lock );
+}
+
+void
+taskset_fini( taskset_t *ts )
+{
+ int i;
+
+ hb_lock( ts->task_cond_lock );
+ /*
+ * Tell each thread to stop, and then cleanup.
+ */
+ bit_nset( ts->task_stop_bitmap, 0, ts->thread_count - 1 );
+ bit_nset( ts->task_begin_bitmap, 0, ts->thread_count - 1 );
+ hb_cond_broadcast( ts->task_begin );
+
+ /*
+ * Wait for all threads to exit.
+ */
+ hb_cond_wait( ts->task_complete, ts->task_cond_lock );
+ hb_unlock( ts->task_cond_lock );
+
+ /*
+ * Clean up taskset memory.
+ */
+ for( i = 0; i < ts->thread_count; i++)
+ {
+ hb_thread_close( &ts->task_threads[i] );
+ }
+ hb_lock_close( &ts->task_cond_lock );
+ hb_cond_close( &ts->task_begin );
+ hb_cond_close( &ts->task_complete );
+ free( ts->task_threads );
+ if( ts->task_threads_args != NULL )
+ free( ts->task_threads_args );
+ free( ts->task_begin_bitmap );
+ free( ts->task_complete_bitmap );
+ free( ts->task_stop_bitmap );
+}