summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libhb/bits.h87
-rw-r--r--libhb/taskset.c231
-rw-r--r--libhb/taskset.h52
3 files changed, 370 insertions, 0 deletions
diff --git a/libhb/bits.h b/libhb/bits.h
new file mode 100644
index 000000000..6338edcf3
--- /dev/null
+++ b/libhb/bits.h
@@ -0,0 +1,87 @@
+/* $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. */
+
+#ifndef HB_BITS_H
+#define HB_BITS_H
+
+static inline int
+allbits_set(uint32_t *bitmap, int num_words)
+{
+ unsigned int i;
+ for( i = 0; i < num_words; i++ )
+ {
+ if( bitmap[i] != 0xFFFFFFFF )
+ return (0);
+ }
+ return (1);
+}
+
+static inline int
+bit_is_set( uint32_t *bit_map, int bit_pos )
+{
+ return( ( bit_map[bit_pos >> 5] & (0x1 << (bit_pos & 0x1F) ) ) != 0 );
+}
+
+static inline int
+bit_is_clear( uint32_t *bit_map, int bit_pos )
+{
+ return( ( bit_map[bit_pos >> 5] & ( 0x1 << (bit_pos & 0x1F) ) ) == 0 );
+}
+
+static inline void
+bit_set( uint32_t *bit_map, int bit_pos )
+{
+ bit_map[bit_pos >> 5] |= 0x1 << (bit_pos & 0x1F);
+}
+
+static inline void
+bit_clear(uint32_t *bit_map, int bit_pos)
+{
+ bit_map[bit_pos >> 5] &= ~( 0x1 << ( bit_pos & 0x1F ) );
+}
+
+static inline void
+bit_nclear(uint32_t *bit_map, int start_pos, int stop_pos)
+{
+ int start_word = start_pos >> 5;
+ int stop_word = stop_pos >> 5;
+
+ if ( start_word == stop_word )
+ {
+
+ bit_map[start_word] &= ( ( 0x7FFFFFFF >> ( 31 - (start_pos & 0x1F ) ) )
+ | ( 0xFFFFFFFE << ( stop_pos & 0x1F ) ) );
+ }
+ else
+ {
+ bit_map[start_word] &= ( 0x7FFFFFFF >> ( 31 - ( start_pos & 0x1F ) ) );
+ while (++start_word < stop_word)
+ bit_map[start_word] = 0;
+ bit_map[stop_word] &= 0xFFFFFFFE << ( stop_pos & 0x1F );
+ }
+}
+
+static inline void
+bit_nset(uint32_t *bit_map, int start_pos, int stop_pos)
+{
+ int start_word = start_pos >> 5;
+ int stop_word = stop_pos >> 5;
+
+ if ( start_word == stop_word )
+ {
+ bit_map[start_word] |= ( ( 0xFFFFFFFF << ( start_pos & 0x1F ) )
+ & ( 0xFFFFFFFF >> ( 31 - ( stop_pos & 0x1F ) ) ) );
+ }
+ else
+ {
+ bit_map[start_word] |= 0xFFFFFFFF << ( start_pos & 0x1F );
+ while (++start_word < stop_word)
+ bit_map[start_word] = 0xFFFFFFFF;
+ bit_map[stop_word] |= 0xFFFFFFFF >> ( 31 - ( stop_pos & 0x1F ) );
+ }
+}
+
+#endif /* HB_BITS_H */
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 );
+}
diff --git a/libhb/taskset.h b/libhb/taskset.h
new file mode 100644
index 000000000..b482c0bef
--- /dev/null
+++ b/libhb/taskset.h
@@ -0,0 +1,52 @@
+/* $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. */
+
+#ifndef HB_TASKSET_H
+#define HB_TASKSET_H
+
+#define TASKSET_POSIX_COMPLIANT 1
+
+#include "bits.h"
+
+typedef struct hb_taskset_s {
+ int thread_count;
+ int arg_size;
+ int bitmap_elements;
+ hb_thread_t ** task_threads;
+ uint8_t * task_threads_args;
+ uint32_t * task_begin_bitmap; // Threads can begin
+ uint32_t * task_complete_bitmap; // Threads have completed
+ uint32_t * task_stop_bitmap; // Threads should exit
+ hb_lock_t * task_cond_lock; // Held during condition tests
+ hb_cond_t * task_begin; // Threads can begin work
+ hb_cond_t * task_complete; // Threads have finished work.
+} taskset_t;
+
+int taskset_init( taskset_t *, int /*thread_count*/, size_t /*user_arg_size*/ );
+void taskset_cycle( taskset_t * );
+void taskset_fini( taskset_t * );
+
+int taskset_thread_spawn( taskset_t *, int /*thr_idx*/, const char * /*descr*/,
+ thread_func_t *, int /*priority*/ );
+void taskset_thread_wait4start( taskset_t *, int );
+void taskset_thread_complete( taskset_t *, int );
+
+static inline void *taskset_thread_args( taskset_t *, int );
+static inline int taskset_thread_stop( taskset_t *, int );
+
+static inline void *
+taskset_thread_args( taskset_t *ts, int thr_idx )
+{
+ return( ts->task_threads_args + ( ts->arg_size * thr_idx ) );
+}
+
+static inline int
+taskset_thread_stop( taskset_t *ts, int thr_idx )
+{
+ return bit_is_set( ts->task_stop_bitmap, thr_idx );
+}
+
+#endif /* HB_TASKSET_H */