rendered paste bodyIndex: libhb/bits.h
===================================================================
--- libhb/bits.h (revision 0)
+++ libhb/bits.h (revision 0)
@@ -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 ) ) )
+ | ( 0xFFFFFFFF << ( ( stop_pos & 0x1F ) + 1 ) ) );
+ }
+ else
+ {
+ bit_map[start_word] &= ( 0x7FFFFFFF >> ( 31 - ( start_pos & 0x1F ) ) );
+ while (++start_word < stop_word)
+ bit_map[start_word] = 0;
+ bit_map[stop_word] &= 0xFFFFFFFF << ( ( stop_pos & 0x1F ) + 1 );
+ }
+}
+
+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 */
Index: libhb/rotate.c
===================================================================
--- libhb/rotate.c (revision 3169)
+++ libhb/rotate.c (working copy)
@@ -2,6 +2,7 @@
#include "hb.h"
#include "hbffmpeg.h"
//#include "mpeg2dec/mpeg2.h"
+#include "taskset.h"
#define MODE_DEFAULT 3
// Mode 1: Flip vertically (y0 becomes yN and yN becomes y0)
@@ -10,7 +11,6 @@
typedef struct rotate_arguments_s {
uint8_t **dst;
- int stop;
} rotate_arguments_t;
struct hb_filter_private_s
@@ -25,9 +25,7 @@
int cpu_count;
- hb_thread_t ** rotate_threads; // Threads for Rotate - one per CPU
- hb_lock_t ** rotate_begin_lock; // Thread has work
- hb_lock_t ** rotate_complete_lock; // Thread has completed work
+ taskset_t rotate_taskset; // Threads for Rotate - one per CPU
rotate_arguments_t *rotate_arguments; // Arguments to thread for work
AVPicture pic_in;
@@ -111,27 +109,25 @@
while( run )
{
/*
- * Wait here until there is work to do. hb_lock() blocks until
- * render releases it to say that there is more work to do.
+ * Wait here until there is work to do.
*/
- hb_lock( pv->rotate_begin_lock[segment] );
+ taskset_thread_wait4start( &pv->rotate_taskset, segment );
- rotate_work = &pv->rotate_arguments[segment];
-
- if( rotate_work->stop )
+ if( taskset_thread_stop( &pv->rotate_taskset, segment ) )
{
/*
* No more work to do, exit this thread.
*/
run = 0;
- continue;
+ goto report_completion;
}
+ rotate_work = &pv->rotate_arguments[segment];
if( rotate_work->dst == NULL )
{
hb_error( "Thread started when no work available" );
hb_snooze(500);
- continue;
+ goto report_completion;
}
/*
@@ -175,12 +171,13 @@
pv );
}
}
+
+report_completion:
/*
* Finished this segment, let everyone know.
*/
- hb_unlock( pv->rotate_complete_lock[segment] );
+ taskset_thread_complete( &pv->rotate_taskset, segment );
}
- free( thread_args_v );
}
@@ -203,28 +200,12 @@
* Setup the work for this plane.
*/
pv->rotate_arguments[segment].dst = dst;
-
- /*
- * Let the thread for this plane know that we've setup work
- * for it by releasing the begin lock (ensuring that the
- * complete lock is already locked so that we block when
- * we try to lock it again below).
- */
- hb_lock( pv->rotate_complete_lock[segment] );
- hb_unlock( pv->rotate_begin_lock[segment] );
}
/*
- * Wait until all three threads have completed by trying to get
- * the complete lock that we locked earlier for each thread, which
- * will block until that thread has completed the work on that
- * plane.
+ * Allow the taskset threads to make one pass over the data.
*/
- for( segment = 0; segment < pv->cpu_count; segment++ )
- {
- hb_lock( pv->rotate_complete_lock[segment] );
- hb_unlock( pv->rotate_complete_lock[segment] );
- }
+ taskset_cycle( &pv->rotate_taskset );
/*
* Entire frame is now rotated.
@@ -268,44 +249,34 @@
pv->cpu_count = hb_get_cpu_count();
-
/*
- * Create threads and locks.
+ * Create rotate taskset.
*/
- pv->rotate_threads = malloc( sizeof( hb_thread_t* ) * pv->cpu_count );
- pv->rotate_begin_lock = malloc( sizeof( hb_lock_t * ) * pv->cpu_count );
- pv->rotate_complete_lock = malloc( sizeof( hb_lock_t * ) * pv->cpu_count );
pv->rotate_arguments = malloc( sizeof( rotate_arguments_t ) * pv->cpu_count );
+ if( pv->rotate_arguments == NULL ||
+ taskset_init( &pv->rotate_taskset, /*thread_count*/pv->cpu_count,
+ sizeof( rotate_thread_arg_t ) ) == 0 )
+ {
+ hb_error( "rotate could not initialize taskset" );
+ }
int i;
for( i = 0; i < pv->cpu_count; i++ )
{
rotate_thread_arg_t *thread_args;
- thread_args = malloc( sizeof( rotate_thread_arg_t ) );
+ thread_args = taskset_thread_args( &pv->rotate_taskset, i );
- if( thread_args ) {
- thread_args->pv = pv;
- thread_args->segment = i;
+ thread_args->pv = pv;
+ thread_args->segment = i;
+ pv->rotate_arguments[i].dst = NULL;
- pv->rotate_begin_lock[i] = hb_lock_init();
- pv->rotate_complete_lock[i] = hb_lock_init();
-
- /*
- * Important to start off with the threads locked waiting
- * on input.
- */
- hb_lock( pv->rotate_begin_lock[i] );
-
- pv->rotate_arguments[i].stop = 0;
- pv->rotate_arguments[i].dst = NULL;
-
- pv->rotate_threads[i] = hb_thread_init( "rotate_filter_segment",
- rotate_filter_thread,
- thread_args,
- HB_NORMAL_PRIORITY );
- } else {
- hb_error( "rotate could not create threads" );
+ if( taskset_thread_spawn( &pv->rotate_taskset, i,
+ "rotate_filter_segment",
+ rotate_filter_thread,
+ HB_NORMAL_PRIORITY ) == 0 )
+ {
+ hb_error( "rotate could not spawn thread" );
}
}
@@ -329,26 +300,11 @@
hb_buffer_close( &pv->buf_settings );
}
- int i;
- for( i = 0; i < pv->cpu_count; i++)
- {
- /*
- * Tell each rotate thread to stop, and then cleanup.
- */
- pv->rotate_arguments[i].stop = 1;
- hb_unlock( pv->rotate_begin_lock[i] );
+ taskset_fini( &pv->rotate_taskset );
- hb_thread_close( &pv->rotate_threads[i] );
- hb_lock_close( &pv->rotate_begin_lock[i] );
- hb_lock_close( &pv->rotate_complete_lock[i] );
- }
-
/*
* free memory for rotate structs
*/
- free( pv->rotate_threads );
- free( pv->rotate_begin_lock );
- free( pv->rotate_complete_lock );
free( pv->rotate_arguments );
free( pv );
Index: libhb/ports.c
===================================================================
--- libhb/ports.c (revision 3169)
+++ libhb/ports.c (working copy)
@@ -290,20 +290,20 @@
***********************************************************************/
struct hb_thread_s
{
- char * name;
- int priority;
- void (* function) ( void * );
- void * arg;
+ char * name;
+ int priority;
+ thread_func_t * function;
+ void * arg;
- hb_lock_t * lock;
- int exited;
+ hb_lock_t * lock;
+ int exited;
#if defined( SYS_BEOS )
- thread_id thread;
+ thread_id thread;
#elif USE_PTHREAD
- pthread_t thread;
+ pthread_t thread;
//#elif defined( SYS_CYGWIN )
-// HANDLE thread;
+// HANDLE thread;
#endif
};
@@ -342,7 +342,7 @@
{
hb_thread_t * t = (hb_thread_t *) _t;
-#if defined( SYS_DARWIN )
+#if defined( SYS_DARWIN ) || defined( SYS_FREEBSD )
/* Set the thread priority */
struct sched_param param;
memset( ¶m, 0, sizeof( struct sched_param ) );
@@ -372,7 +372,7 @@
* arg: argument of the routine
* priority: HB_LOW_PRIORITY or HB_NORMAL_PRIORITY
***********************************************************************/
-hb_thread_t * hb_thread_init( char * name, void (* function)(void *),
+hb_thread_t * hb_thread_init( const char * name, void (* function)(void *),
void * arg, int priority )
{
hb_thread_t * t = calloc( sizeof( hb_thread_t ), 1 );
@@ -485,7 +485,7 @@
pthread_mutexattr_init(&mta);
-#if defined( SYS_CYGWIN )
+#if defined( SYS_CYGWIN ) || defined( SYS_FREEBSD )
pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_NORMAL);
#endif
@@ -562,6 +562,9 @@
{
hb_cond_t * c = calloc( sizeof( hb_cond_t ), 1 );
+ if( c == NULL )
+ return NULL;
+
#if defined( SYS_BEOS )
c->thread = -1;
#elif USE_PTHREAD
Index: libhb/ports.h
===================================================================
--- libhb/ports.h (revision 3169)
+++ libhb/ports.h (working copy)
@@ -59,7 +59,8 @@
# define HB_NORMAL_PRIORITY 0
#endif
-hb_thread_t * hb_thread_init( char * name, void (* function)(void *),
+typedef void (thread_func_t)(void *);
+hb_thread_t * hb_thread_init( const char * name, thread_func_t *function,
void * arg, int priority );
void hb_thread_close( hb_thread_t ** );
int hb_thread_has_exited( hb_thread_t * );
Index: libhb/taskset.c
===================================================================
--- libhb/taskset.c (revision 0)
+++ libhb/taskset.c (revision 0)
@@ -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 );
+}
Index: libhb/deinterlace.c
===================================================================
--- libhb/deinterlace.c (revision 3169)
+++ libhb/deinterlace.c (working copy)
@@ -19,6 +19,7 @@
#include "hb.h"
#include "hbffmpeg.h"
#include "mpeg2dec/mpeg2.h"
+#include "taskset.h"
#define SUPPRESS_AV_LOG
@@ -36,7 +37,6 @@
uint8_t **dst;
int parity;
int tff;
- int stop;
} yadif_arguments_t;
struct hb_filter_private_s
@@ -54,9 +54,8 @@
int cpu_count;
- hb_thread_t ** yadif_threads; // Threads for Yadif - one per CPU
- hb_lock_t ** yadif_begin_lock; // Thread has work
- hb_lock_t ** yadif_complete_lock; // Thread has completed work
+ taskset_t yadif_taskset; // Threads for Yadif - one per CPU
+
yadif_arguments_t *yadif_arguments; // Arguments to thread for work
int mcdeint_mode;
@@ -227,27 +226,27 @@
while( run )
{
/*
- * Wait here until there is work to do. hb_lock() blocks until
- * render releases it to say that there is more work to do.
+ * Wait here until there is work to do.
*/
- hb_lock( pv->yadif_begin_lock[segment] );
+ taskset_thread_wait4start( &pv->yadif_taskset, segment );
- yadif_work = &pv->yadif_arguments[segment];
- if( yadif_work->stop )
+ if( taskset_thread_stop( &pv->yadif_taskset, segment ) )
{
/*
* No more work to do, exit this thread.
*/
run = 0;
- continue;
+ goto report_completion;
}
+ yadif_work = &pv->yadif_arguments[segment];
+
if( yadif_work->dst == NULL )
{
hb_error( "Thread started when no work available" );
hb_snooze(500);
- continue;
+ goto report_completion;
}
/*
@@ -339,12 +338,13 @@
}
}
}
+
+report_completion:
/*
* Finished this segment, let everyone know.
*/
- hb_unlock( pv->yadif_complete_lock[segment] );
+ taskset_thread_complete( &pv->yadif_taskset, segment );
}
- free( thread_args_v );
}
@@ -371,28 +371,10 @@
pv->yadif_arguments[segment].parity = parity;
pv->yadif_arguments[segment].tff = tff;
pv->yadif_arguments[segment].dst = dst;
-
- /*
- * Let the thread for this plane know that we've setup work
- * for it by releasing the begin lock (ensuring that the
- * complete lock is already locked so that we block when
- * we try to lock it again below).
- */
- hb_lock( pv->yadif_complete_lock[segment] );
- hb_unlock( pv->yadif_begin_lock[segment] );
}
- /*
- * Wait until all three threads have completed by trying to get
- * the complete lock that we locked earlier for each thread, which
- * will block until that thread has completed the work on that
- * plane.
- */
- for( segment = 0; segment < pv->cpu_count; segment++ )
- {
- hb_lock( pv->yadif_complete_lock[segment] );
- hb_unlock( pv->yadif_complete_lock[segment] );
- }
+ /* Allow the taskset threads to make one pass over the data. */
+ taskset_cycle( &pv->yadif_taskset );
/*
* Entire frame is now deinterlaced.
@@ -572,41 +554,32 @@
}
/*
- * Create yadif threads and locks.
+ * Setup yadif taskset.
*/
- pv->yadif_threads = malloc( sizeof( hb_thread_t* ) * pv->cpu_count );
- pv->yadif_begin_lock = malloc( sizeof( hb_lock_t * ) * pv->cpu_count );
- pv->yadif_complete_lock = malloc( sizeof( hb_lock_t * ) * pv->cpu_count );
pv->yadif_arguments = malloc( sizeof( yadif_arguments_t ) * pv->cpu_count );
+ if( pv->yadif_arguments == NULL ||
+ taskset_init( &pv->yadif_taskset, /*thread_count*/pv->cpu_count,
+ sizeof( yadif_arguments_t ) ) == 0 )
+ {
+ hb_error( "yadif could not initialize taskset" );
+ }
for( i = 0; i < pv->cpu_count; i++ )
{
yadif_thread_arg_t *thread_args;
- thread_args = malloc( sizeof( yadif_thread_arg_t ) );
+ thread_args = taskset_thread_args( &pv->yadif_taskset, i );
- if( thread_args ) {
- thread_args->pv = pv;
- thread_args->segment = i;
+ thread_args->pv = pv;
+ thread_args->segment = i;
+ pv->yadif_arguments[i].dst = NULL;
- pv->yadif_begin_lock[i] = hb_lock_init();
- pv->yadif_complete_lock[i] = hb_lock_init();
-
- /*
- * Important to start off with the threads locked waiting
- * on input.
- */
- hb_lock( pv->yadif_begin_lock[i] );
-
- pv->yadif_arguments[i].stop = 0;
- pv->yadif_arguments[i].dst = NULL;
-
- pv->yadif_threads[i] = hb_thread_init( "yadif_filter_segment",
- yadif_filter_thread,
- thread_args,
- HB_NORMAL_PRIORITY );
- } else {
- hb_error( "Yadif could not create threads" );
+ if( taskset_thread_spawn( &pv->yadif_taskset, i,
+ "yadif_filter_segment",
+ yadif_filter_thread,
+ HB_NORMAL_PRIORITY ) == 0 )
+ {
+ hb_error( "yadif could not spawn thread" );
}
}
}
@@ -699,25 +672,7 @@
}
}
- for( i = 0; i < pv->cpu_count; i++)
- {
- /*
- * Tell each yadif thread to stop, and then cleanup.
- */
- pv->yadif_arguments[i].stop = 1;
- hb_unlock( pv->yadif_begin_lock[i] );
-
- hb_thread_close( &pv->yadif_threads[i] );
- hb_lock_close( &pv->yadif_begin_lock[i] );
- hb_lock_close( &pv->yadif_complete_lock[i] );
- }
-
- /*
- * free memory for yadif structs
- */
- free( pv->yadif_threads );
- free( pv->yadif_begin_lock );
- free( pv->yadif_complete_lock );
+ taskset_fini( &pv->yadif_taskset );
free( pv->yadif_arguments );
}
Index: libhb/taskset.h
===================================================================
--- libhb/taskset.h (revision 0)
+++ libhb/taskset.h (revision 0)
@@ -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 */
Index: libhb/decomb.c
===================================================================
--- libhb/decomb.c (revision 3169)
+++ libhb/decomb.c (working copy)
@@ -69,6 +69,7 @@
#include "hbffmpeg.h"
#include "mpeg2dec/mpeg2.h"
#include "eedi2.h"
+#include "taskset.h"
#define SUPPRESS_AV_LOG
@@ -97,21 +98,10 @@
uint8_t **dst;
int parity;
int tff;
- int stop;
int is_combed;
};
-struct decomb_arguments_s {
- int stop;
-};
-
-struct eedi2_arguments_s {
- int stop;
-};
-
typedef struct yadif_arguments_s yadif_arguments_t;
-typedef struct decomb_arguments_s decomb_arguments_t;
-typedef struct eedi2_arguments_s eedi2_arguments_t;
typedef struct eedi2_thread_arg_s {
hb_filter_private_t *pv;
@@ -191,21 +181,13 @@
int cpu_count;
- hb_thread_t ** yadif_threads; // Threads for Yadif - one per CPU
- hb_lock_t ** yadif_begin_lock; // Thread has work
- hb_lock_t ** yadif_complete_lock; // Thread has completed work
- yadif_arguments_t *yadif_arguments; // Arguments to thread for work
-
- hb_thread_t ** decomb_threads; // Threads for comb detection - one per CPU
- hb_lock_t ** decomb_begin_lock; // Thread has work
- hb_lock_t ** decomb_complete_lock; // Thread has completed work
- decomb_arguments_t *decomb_arguments; // Arguments to thread for work
+ taskset_t yadif_taskset; // Threads for Yadif - one per CPU
- hb_thread_t ** eedi2_threads; // Threads for eedi2 - one per plane
- hb_lock_t ** eedi2_begin_lock; // Thread has work
- hb_lock_t ** eedi2_complete_lock; // Thread has completed work
- eedi2_arguments_t *eedi2_arguments; // Arguments to thread for work
+ yadif_arguments_t *yadif_arguments; // Arguments to thread for work
+ taskset_t decomb_taskset; // Threads for comb detection - one per CPU
+
+ taskset_t eedi2_taskset; // Threads for eedi2 - one per plane
// int alternator; // for bobbing parity when framedoubling
};
@@ -814,7 +796,6 @@
*/
void eedi2_filter_thread( void *thread_args_v )
{
- eedi2_arguments_t *eedi2_work = NULL;
hb_filter_private_t * pv;
int run = 1;
int plane;
@@ -828,31 +809,30 @@
while( run )
{
/*
- * Wait here until there is work to do. hb_lock() blocks until
- * render releases it to say that there is more work to do.
+ * Wait here until there is work to do.
*/
- hb_lock( pv->eedi2_begin_lock[plane] );
+ taskset_thread_wait4start( &pv->eedi2_taskset, plane );
- eedi2_work = &pv->eedi2_arguments[plane];
-
- if( eedi2_work->stop )
+ if( taskset_thread_stop( &pv->eedi2_taskset, plane ) )
{
/*
* No more work to do, exit this thread.
*/
run = 0;
- continue;
- }
+ }
+ else
+ {
- /*
- * Process plane
- */
+ /*
+ * Process plane
+ */
eedi2_interpolate_plane( pv, plane );
+ }
/*
* Finished this segment, let everyone know.
*/
- hb_unlock( pv->eedi2_complete_lock[plane] );
+ taskset_thread_complete( &pv->eedi2_taskset, plane );
}
free( thread_args_v );
}
@@ -870,30 +850,11 @@
eedi2_fill_half_height_buffer_plane( &pv->ref[1][i][pitch*start_line], pv->eedi_half[SRCPF][i], pitch, pv->height[i] );
}
- int plane;
- for( plane = 0; plane < 3; plane++ )
- {
- /*
- * Let the thread for this plane know that we've setup work
- * for it by releasing the begin lock (ensuring that the
- * complete lock is already locked so that we block when
- * we try to lock it again below).
- */
- hb_lock( pv->eedi2_complete_lock[plane] );
- hb_unlock( pv->eedi2_begin_lock[plane] );
- }
-
/*
- * Wait until all three threads have completed by trying to get
- * the complete lock that we locked earlier for each thread, which
- * will block until that thread has completed the work on that
- * plane.
+ * Now that all data is ready for our threads, fire them off
+ * and wait for their completion.
*/
- for( plane = 0; plane < 3; plane++ )
- {
- hb_lock( pv->eedi2_complete_lock[plane] );
- hb_unlock( pv->eedi2_complete_lock[plane] );
- }
+ taskset_cycle( &pv->eedi2_taskset );
}
@@ -902,7 +863,6 @@
*/
void decomb_filter_thread( void *thread_args_v )
{
- decomb_arguments_t *decomb_work = NULL;
hb_filter_private_t * pv;
int run = 1;
int segment, segment_start, segment_stop, plane;
@@ -916,20 +876,17 @@
while( run )
{
/*
- * Wait here until there is work to do. hb_lock() blocks until
- * render releases it to say that there is more work to do.
+ * Wait here until there is work to do.
*/
- hb_lock( pv->decomb_begin_lock[segment] );
+ taskset_thread_wait4start( &pv->decomb_taskset, segment );
- decomb_work = &pv->decomb_arguments[segment];
-
- if( decomb_work->stop )
+ if( taskset_thread_stop( &pv->decomb_taskset, segment ) )
{
/*
* No more work to do, exit this thread.
*/
run = 0;
- continue;
+ goto report_completion;
}
/*
@@ -952,41 +909,22 @@
detect_combed_segment( pv, segment_start, segment_stop );
}
+
+report_completion:
/*
* Finished this segment, let everyone know.
*/
- hb_unlock( pv->decomb_complete_lock[segment] );
+ taskset_thread_complete( &pv->decomb_taskset, segment );
}
- free( thread_args_v );
}
int comb_segmenter( hb_filter_private_t * pv )
{
- int segment;
-
- for( segment = 0; segment < pv->cpu_count; segment++ )
- {
- /*
- * Let the thread for this plane know that we've setup work
- * for it by releasing the begin lock (ensuring that the
- * complete lock is already locked so that we block when
- * we try to lock it again below).
- */
- hb_lock( pv->decomb_complete_lock[segment] );
- hb_unlock( pv->decomb_begin_lock[segment] );
- }
-
/*
- * Wait until all three threads have completed by trying to get
- * the complete lock that we locked earlier for each thread, which
- * will block until that thread has completed the work on that
- * plane.
+ * Now that all data for decomb detection is ready for
+ * our threads, fire them off and wait for their completion.
*/
- for( segment = 0; segment < pv->cpu_count; segment++ )
- {
- hb_lock( pv->decomb_complete_lock[segment] );
- hb_unlock( pv->decomb_complete_lock[segment] );
- }
+ taskset_cycle( &pv->decomb_taskset );
return check_combing_mask( pv );
}
@@ -1168,27 +1106,26 @@
while( run )
{
/*
- * Wait here until there is work to do. hb_lock() blocks until
- * render releases it to say that there is more work to do.
+ * Wait here until there is work to do.
*/
- hb_lock( pv->yadif_begin_lock[segment] );
-
- yadif_work = &pv->yadif_arguments[segment];
-
- if( yadif_work->stop )
+ taskset_thread_wait4start( &pv->yadif_taskset, segment );
+
+ if( taskset_thread_stop( &pv->yadif_taskset, segment ) )
{
/*
* No more work to do, exit this thread.
*/
run = 0;
- continue;
+ goto report_completion;
}
+ yadif_work = &pv->yadif_arguments[segment];
+
if( yadif_work->dst == NULL )
{
hb_error( "thread started when no work available" );
hb_snooze(500);
- continue;
+ goto report_completion;
}
is_combed = pv->yadif_arguments[segment].is_combed;
@@ -1301,12 +1238,13 @@
}
}
}
+
+report_completion:
/*
* Finished this segment, let everyone know.
*/
- hb_unlock( pv->yadif_complete_lock[segment] );
+ taskset_thread_complete( &pv->yadif_taskset, segment );
}
- free( thread_args_v );
}
static void yadif_filter( uint8_t ** dst,
@@ -1402,28 +1340,12 @@
pv->yadif_arguments[segment].tff = tff;
pv->yadif_arguments[segment].dst = dst;
pv->yadif_arguments[segment].is_combed = is_combed;
-
- /*
- * Let the thread for this plane know that we've setup work
- * for it by releasing the begin lock (ensuring that the
- * complete lock is already locked so that we block when
- * we try to lock it again below).
- */
- hb_lock( pv->yadif_complete_lock[segment] );
- hb_unlock( pv->yadif_begin_lock[segment] );
}
/*
- * Wait until all three threads have completed by trying to get
- * the complete lock that we locked earlier for each thread, which
- * will block until that thread has completed the work on that
- * plane.
+ * Allow the taskset threads to make one pass over the data.
*/
- for( segment = 0; segment < pv->cpu_count; segment++ )
- {
- hb_lock( pv->yadif_complete_lock[segment] );
- hb_unlock( pv->yadif_complete_lock[segment] );
- }
+ taskset_cycle( &pv->yadif_taskset );
/*
* Entire frame is now deinterlaced.
@@ -1724,98 +1646,70 @@
}
}
- /*
- * Create yadif threads and locks.
- */
- pv->yadif_threads = malloc( sizeof( hb_thread_t* ) * pv->cpu_count );
- pv->yadif_begin_lock = malloc( sizeof( hb_lock_t * ) * pv->cpu_count );
- pv->yadif_complete_lock = malloc( sizeof( hb_lock_t * ) * pv->cpu_count );
- pv->yadif_arguments = malloc( sizeof( yadif_arguments_t ) * pv->cpu_count );
+ /*
+ * Setup yadif taskset.
+ */
+ pv->yadif_arguments = malloc( sizeof( yadif_arguments_t ) * pv->cpu_count );
+ if( pv->yadif_arguments == NULL ||
+ taskset_init( &pv->yadif_taskset, /*thread_count*/pv->cpu_count,
+ sizeof( yadif_thread_arg_t ) ) == 0 )
+ {
+ hb_error( "yadif could not initialize taskset" );
+ }
- for( i = 0; i < pv->cpu_count; i++ )
- {
- yadif_thread_arg_t *thread_args;
+ for( i = 0; i < pv->cpu_count; i++ )
+ {
+ yadif_thread_arg_t *thread_args;
- thread_args = malloc( sizeof( yadif_thread_arg_t ) );
-
- if( thread_args )
- {
- thread_args->pv = pv;
- thread_args->segment = i;
-
- pv->yadif_begin_lock[i] = hb_lock_init();
- pv->yadif_complete_lock[i] = hb_lock_init();
-
- /*
- * Important to start off with the threads locked waiting
- * on input.
- */
- hb_lock( pv->yadif_begin_lock[i] );
-
- pv->yadif_arguments[i].stop = 0;
- pv->yadif_arguments[i].dst = NULL;
-
- pv->yadif_threads[i] = hb_thread_init( "yadif_filter_segment",
- yadif_decomb_filter_thread,
- thread_args,
- HB_NORMAL_PRIORITY );
- }
- else
- {
- hb_error( "yadif could not create threads" );
- }
+ thread_args = taskset_thread_args( &pv->yadif_taskset, i );
+ thread_args->pv = pv;
+ thread_args->segment = i;
+ pv->yadif_arguments[i].dst = NULL;
+ if( taskset_thread_spawn( &pv->yadif_taskset, i,
+ "yadif_filter_segment",
+ yadif_decomb_filter_thread,
+ HB_NORMAL_PRIORITY ) == 0 )
+ {
+ hb_error( "yadif could not spawn thread" );
+ }
}
/*
- * Create decomb threads and locks.
+ * Create decomb taskset.
*/
- pv->decomb_threads = malloc( sizeof( hb_thread_t* ) * pv->cpu_count );
- pv->decomb_begin_lock = malloc( sizeof( hb_lock_t * ) * pv->cpu_count );
- pv->decomb_complete_lock = malloc( sizeof( hb_lock_t * ) * pv->cpu_count );
- pv->decomb_arguments = malloc( sizeof( decomb_arguments_t ) * pv->cpu_count );
-
+ if( taskset_init( &pv->decomb_taskset, /*thread_count*/pv->cpu_count,
+ sizeof( decomb_thread_arg_t ) ) == 0 )
+ {
+ hb_error( "decomb could not initialize taskset" );
+ }
for( i = 0; i < pv->cpu_count; i++ )
{
decomb_thread_arg_t *decomb_thread_args;
- decomb_thread_args = malloc( sizeof( decomb_thread_arg_t ) );
-
- if( decomb_thread_args )
+ decomb_thread_args = taskset_thread_args( &pv->decomb_taskset, i );
+ decomb_thread_args->pv = pv;
+ decomb_thread_args->segment = i;
+
+ if( taskset_thread_spawn( &pv->decomb_taskset, i,
+ "decomb_filter_segment",
+ decomb_filter_thread,
+ HB_NORMAL_PRIORITY ) == 0 )
{
- decomb_thread_args->pv = pv;
- decomb_thread_args->segment = i;
-
- pv->decomb_begin_lock[i] = hb_lock_init();
- pv->decomb_complete_lock[i] = hb_lock_init();
-
- /*
- * Important to start off with the threads locked waiting
- * on input.
- */
- hb_lock( pv->decomb_begin_lock[i] );
-
- pv->decomb_arguments[i].stop = 0;
-
- pv->decomb_threads[i] = hb_thread_init( "decomb_filter_segment",
- decomb_filter_thread,
- decomb_thread_args,
- HB_NORMAL_PRIORITY );
+ hb_error( "decomb could not spawn thread" );
}
- else
- {
- hb_error( "decomb could not create threads" );
- }
}
if( pv->mode & MODE_EEDI2 )
{
+
/*
- * Create eedi2 threads and locks.
+ * Create eedi2 taskset.
*/
- pv->eedi2_threads = malloc( sizeof( hb_thread_t* ) * 3 );
- pv->eedi2_begin_lock = malloc( sizeof( hb_lock_t * ) * 3 );
- pv->eedi2_complete_lock = malloc( sizeof( hb_lock_t * ) * 3 );
- pv->eedi2_arguments = malloc( sizeof( eedi2_arguments_t ) * 3 );
+ if( taskset_init( &pv->eedi2_taskset, /*thread_count*/3,
+ sizeof( eedi2_thread_arg_t ) ) == 0 )
+ {
+ hb_error( "eedi2 could not initialize taskset" );
+ }
if( pv->post_processing > 1 )
{
@@ -1833,37 +1727,21 @@
{
eedi2_thread_arg_t *eedi2_thread_args;
- eedi2_thread_args = malloc( sizeof( eedi2_thread_arg_t ) );
+ eedi2_thread_args = taskset_thread_args( &pv->eedi2_taskset, i );
- if( eedi2_thread_args )
- {
- eedi2_thread_args->pv = pv;
- eedi2_thread_args->plane = i;
+ eedi2_thread_args->pv = pv;
+ eedi2_thread_args->plane = i;
- pv->eedi2_begin_lock[i] = hb_lock_init();
- pv->eedi2_complete_lock[i] = hb_lock_init();
-
- /*
- * Important to start off with the threads locked waiting
- * on input.
- */
- hb_lock( pv->eedi2_begin_lock[i] );
-
- pv->eedi2_arguments[i].stop = 0;
-
- pv->eedi2_threads[i] = hb_thread_init( "eedi2_filter_segment",
- eedi2_filter_thread,
- eedi2_thread_args,
- HB_NORMAL_PRIORITY );
- }
- else
+ if( taskset_thread_spawn( &pv->eedi2_taskset, i,
+ "eedi2_filter_segment",
+ eedi2_filter_thread,
+ HB_NORMAL_PRIORITY ) == 0 )
{
- hb_error( "eedi2 could not create threads" );
+ hb_error( "eedi2 could not spawn thread" );
}
}
}
-
/* Allocate mcdeint specific buffers */
if( pv->mcdeint_mode >= 0 )
{
@@ -2001,70 +1879,17 @@
if (pv->tmpc) eedi2_aligned_free(pv->tmpc);
}
- for( i = 0; i < pv->cpu_count; i++)
- {
- /*
- * Tell each yadif thread to stop, and then cleanup.
- */
- pv->yadif_arguments[i].stop = 1;
- hb_unlock( pv->yadif_begin_lock[i] );
-
- hb_thread_close( &pv->yadif_threads[i] );
- hb_lock_close( &pv->yadif_begin_lock[i] );
- hb_lock_close( &pv->yadif_complete_lock[i] );
- }
+ taskset_fini( &pv->yadif_taskset );
+ taskset_fini( &pv->decomb_taskset );
/*
* free memory for yadif structs
*/
- free( pv->yadif_threads );
- free( pv->yadif_begin_lock );
- free( pv->yadif_complete_lock );
free( pv->yadif_arguments );
- for( i = 0; i < pv->cpu_count; i++)
- {
- /*
- * Tell each decomb thread to stop, and then cleanup.
- */
- pv->decomb_arguments[i].stop = 1;
- hb_unlock( pv->decomb_begin_lock[i] );
-
- hb_thread_close( &pv->decomb_threads[i] );
- hb_lock_close( &pv->decomb_begin_lock[i] );
- hb_lock_close( &pv->decomb_complete_lock[i] );
- }
-
- /*
- * free memory for decomb structs
- */
- free( pv->decomb_threads );
- free( pv->decomb_begin_lock );
- free( pv->decomb_complete_lock );
- free( pv->decomb_arguments );
-
if( pv->mode & MODE_EEDI2 )
{
- for( i = 0; i < 3; i++)
- {
- /*
- * Tell each eedi2 thread to stop, and then cleanup.
- */
- pv->eedi2_arguments[i].stop = 1;
- hb_unlock( pv->eedi2_begin_lock[i] );
-
- hb_thread_close( &pv->eedi2_threads[i] );
- hb_lock_close( &pv->eedi2_begin_lock[i] );
- hb_lock_close( &pv->eedi2_complete_lock[i] );
- }
-
- /*
- * free memory for eedi2 structs
- */
- free( pv->eedi2_threads );
- free( pv->eedi2_begin_lock );
- free( pv->eedi2_complete_lock );
- free( pv->eedi2_arguments );
+ taskset_fini( &pv->eedi2_taskset );
}
/* Cleanup mcdeint specific buffers */