diff options
author | jstebbins <[email protected]> | 2012-05-17 19:51:35 +0000 |
---|---|---|
committer | jstebbins <[email protected]> | 2012-05-17 19:51:35 +0000 |
commit | 5a0673d1572fdfcd00063cfa9dffba907c808056 (patch) | |
tree | b55af15b31edc30a69bf2c17818f6ea3565f9a9a | |
parent | d005ce0b526630bd428c1e5a466b0a96f0b8ecba (diff) |
libhb: tasksets API provided by scsiguy
This is an easier to use API for launching multithreaded tasks. And it is more
portable since it does not rely on undefined/implementation specific behavior
of POSIX mutexes. That is, the ability for one thread to unlock a mutex owned
by another thread.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@4685 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r-- | libhb/decomb.c | 389 | ||||
-rw-r--r-- | libhb/deinterlace.c | 111 | ||||
-rw-r--r-- | libhb/ports.c | 27 | ||||
-rw-r--r-- | libhb/ports.h | 3 | ||||
-rw-r--r-- | libhb/rotate.c | 106 |
5 files changed, 188 insertions, 448 deletions
diff --git a/libhb/decomb.c b/libhb/decomb.c index 50773b772..20041459d 100644 --- a/libhb/decomb.c +++ b/libhb/decomb.c @@ -80,6 +80,7 @@ which will feed EEDI2 interpolations to yadif. #include "mpeg2dec/mpeg2.h" #include "eedi2.h" #include "mcdeint.h" +#include "taskset.h" #define PARITY_DEFAULT -1 @@ -107,21 +108,10 @@ struct yadif_arguments_s { 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; @@ -203,20 +193,12 @@ struct hb_filter_private_s 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 + taskset_t yadif_taskset; // Threads for Yadif - one per CPU + 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 decomb_taskset; // Threads for comb detection - 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 + taskset_t eedi2_taskset; // Threads for eedi2 - one per plane }; static int hb_decomb_init( hb_filter_object_t * filter, @@ -1314,7 +1296,6 @@ void eedi2_interpolate_plane( hb_filter_private_t * pv, int k ) */ void eedi2_filter_thread( void *thread_args_v ) { - eedi2_arguments_t *eedi2_work = NULL; hb_filter_private_t * pv; int run = 1; int plane; @@ -1328,31 +1309,29 @@ void eedi2_filter_thread( void *thread_args_v ) 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; } - - /* - * Process plane - */ + else + { + /* + * 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 ); } @@ -1370,30 +1349,11 @@ void eedi2_planer( hb_filter_private_t * pv ) 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 ); } @@ -1402,7 +1362,6 @@ void eedi2_planer( hb_filter_private_t * pv ) */ 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; @@ -1416,21 +1375,18 @@ void decomb_filter_thread( void *thread_args_v ) 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; + } /* * Process segment (for now just from luma) @@ -1459,42 +1415,23 @@ void decomb_filter_thread( void *thread_args_v ) 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 ); + if( pv->mode & MODE_FILTER ) { filter_combing_mask( pv ); @@ -1689,27 +1626,26 @@ void yadif_decomb_filter_thread( void *thread_args_v ) 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; @@ -1822,12 +1758,13 @@ void yadif_decomb_filter_thread( void *thread_args_v ) } } } + +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, @@ -1923,28 +1860,12 @@ static void yadif_filter( uint8_t ** dst, 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. @@ -2120,99 +2041,71 @@ static int hb_decomb_init( hb_filter_object_t * filter, } } } + + /* + * 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" ); + } - /* - * 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 ); - - 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; + for( i = 0; i < pv->cpu_count; i++ ) + { + yadif_thread_arg_t *thread_args; - 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->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 ); - } - else + + 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 ) { - hb_error( "decomb could not create threads" ); + hb_error( "decomb could not spawn thread" ); } } 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 ) { @@ -2230,32 +2123,17 @@ static int hb_decomb_init( hb_filter_object_t * filter, { eedi2_thread_arg_t *eedi2_thread_args; - eedi2_thread_args = malloc( sizeof( eedi2_thread_arg_t ) ); - - if( eedi2_thread_args ) - { - 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] ); + eedi2_thread_args = taskset_thread_args( &pv->eedi2_taskset, i ); - pv->eedi2_arguments[i].stop = 0; + eedi2_thread_args->pv = pv; + eedi2_thread_args->plane = i; - 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" ); } } } @@ -2366,71 +2244,18 @@ static void hb_decomb_close( hb_filter_object_t * filter ) if (pv->cxy) eedi2_aligned_free(pv->cxy); 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 */ diff --git a/libhb/deinterlace.c b/libhb/deinterlace.c index 49681512c..e654817c3 100644 --- a/libhb/deinterlace.c +++ b/libhb/deinterlace.c @@ -20,6 +20,7 @@ #include "hbffmpeg.h" #include "mpeg2dec/mpeg2.h" #include "mcdeint.h" +#include "taskset.h" // yadif_mode is a bit vector with the following flags // Note that 2PASS should be enabled when using MCDEINT @@ -42,7 +43,6 @@ typedef struct yadif_arguments_s { uint8_t **dst; int parity; int tff; - int stop; } yadif_arguments_t; struct hb_filter_private_s @@ -59,9 +59,8 @@ struct hb_filter_private_s 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; @@ -220,27 +219,27 @@ void yadif_filter_thread( void *thread_args_v ) 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; } /* @@ -332,12 +331,13 @@ void yadif_filter_thread( void *thread_args_v ) } } } + +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 ); } @@ -364,28 +364,10 @@ static void yadif_filter( uint8_t ** dst, 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. @@ -444,41 +426,32 @@ static int hb_deinterlace_init( hb_filter_object_t * filter, } /* - * 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 ) ); - - if( thread_args ) { - thread_args->pv = pv; - thread_args->segment = i; + thread_args = taskset_thread_args( &pv->yadif_taskset, i ); - pv->yadif_begin_lock[i] = hb_lock_init(); - pv->yadif_complete_lock[i] = hb_lock_init(); + thread_args->pv = pv; + thread_args->segment = i; + pv->yadif_arguments[i].dst = NULL; - /* - * 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" ); } } } @@ -526,25 +499,7 @@ static void hb_deinterlace_close( hb_filter_object_t * filter ) } } - 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 ); } diff --git a/libhb/ports.c b/libhb/ports.c index cec4efd96..6f3a48240 100644 --- a/libhb/ports.c +++ b/libhb/ports.c @@ -294,20 +294,20 @@ void hb_mkdir( char * name ) ***********************************************************************/ 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 }; @@ -346,7 +346,7 @@ static void attribute_align_thread hb_thread_func( void * _t ) { 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 ) ); @@ -376,7 +376,7 @@ static void attribute_align_thread hb_thread_func( void * _t ) * 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 ); @@ -489,7 +489,7 @@ hb_lock_t * hb_lock_init() pthread_mutexattr_init(&mta); -#if defined( SYS_CYGWIN ) +#if defined( SYS_CYGWIN ) || defined( SYS_FREEBSD ) pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_NORMAL); #endif @@ -566,6 +566,9 @@ hb_cond_t * hb_cond_init() { 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 diff --git a/libhb/ports.h b/libhb/ports.h index 7b743c437..c1cadf785 100644 --- a/libhb/ports.h +++ b/libhb/ports.h @@ -62,7 +62,8 @@ typedef struct hb_thread_s hb_thread_t; # 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 * ); diff --git a/libhb/rotate.c b/libhb/rotate.c index 5f9558764..a60f92ce5 100644 --- a/libhb/rotate.c +++ b/libhb/rotate.c @@ -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) @@ -11,7 +12,6 @@ typedef struct rotate_arguments_s { hb_buffer_t *dst; hb_buffer_t *src; - int stop; } rotate_arguments_t; struct hb_filter_private_s @@ -24,9 +24,7 @@ struct hb_filter_private_s 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 }; @@ -85,27 +83,25 @@ void rotate_filter_thread( void *thread_args_v ) 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; } /* @@ -168,12 +164,13 @@ void rotate_filter_thread( void *thread_args_v ) } } } + +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 ); } @@ -199,28 +196,12 @@ static void rotate_filter( */ pv->rotate_arguments[segment].dst = out; pv->rotate_arguments[segment].src = in; - - /* - * 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. @@ -244,44 +225,34 @@ static int hb_rotate_init( hb_filter_object_t * filter, 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 ) ); - - if( thread_args ) { - thread_args->pv = pv; - thread_args->segment = i; - - pv->rotate_begin_lock[i] = hb_lock_init(); - pv->rotate_complete_lock[i] = hb_lock_init(); + thread_args = taskset_thread_args( &pv->rotate_taskset, i ); - /* - * Important to start off with the threads locked waiting - * on input. - */ - hb_lock( pv->rotate_begin_lock[i] ); + thread_args->pv = pv; + thread_args->segment = i; + pv->rotate_arguments[i].dst = NULL; - 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" ); } } // Set init width/height so the next stage in the pipline @@ -344,26 +315,11 @@ static void hb_rotate_close( hb_filter_object_t * filter ) return; } - 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] ); - - hb_thread_close( &pv->rotate_threads[i] ); - hb_lock_close( &pv->rotate_begin_lock[i] ); - hb_lock_close( &pv->rotate_complete_lock[i] ); - } + taskset_fini( &pv->rotate_taskset ); /* * 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 ); |