From: Nicolai Hähnle <nicolai.haeh...@amd.com> The #if guard is probably not 100% equivalent to the previous PIPE_OS check, but if anything it should be an over-approximation (are there pthread implementations without barriers?), so people will get either a good implementation or compile errors that are easy to fix. --- src/gallium/auxiliary/os/os_thread.h | 76 ----------------------------- src/gallium/drivers/llvmpipe/lp_rast.c | 9 ++-- src/gallium/drivers/llvmpipe/lp_rast_priv.h | 4 +- src/gallium/tests/unit/pipe_barrier_test.c | 12 ++--- src/util/u_thread.h | 74 ++++++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 88 deletions(-)
diff --git a/src/gallium/auxiliary/os/os_thread.h b/src/gallium/auxiliary/os/os_thread.h index 10d4695da68..d9c685922a5 100644 --- a/src/gallium/auxiliary/os/os_thread.h +++ b/src/gallium/auxiliary/os/os_thread.h @@ -54,96 +54,20 @@ __pipe_mutex_assert_locked(mtx_t *mutex) */ int ret = mtx_trylock(mutex); assert(ret == thrd_busy); if (ret == thrd_success) mtx_unlock(mutex); #endif } /* - * pipe_barrier - */ - -#if (defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_HURD)) && (!defined(PIPE_OS_ANDROID) || ANDROID_API_LEVEL >= 24) - -typedef pthread_barrier_t pipe_barrier; - -static inline void pipe_barrier_init(pipe_barrier *barrier, unsigned count) -{ - pthread_barrier_init(barrier, NULL, count); -} - -static inline void pipe_barrier_destroy(pipe_barrier *barrier) -{ - pthread_barrier_destroy(barrier); -} - -static inline void pipe_barrier_wait(pipe_barrier *barrier) -{ - pthread_barrier_wait(barrier); -} - - -#else /* If the OS doesn't have its own, implement barriers using a mutex and a condvar */ - -typedef struct { - unsigned count; - unsigned waiters; - uint64_t sequence; - mtx_t mutex; - cnd_t condvar; -} pipe_barrier; - -static inline void pipe_barrier_init(pipe_barrier *barrier, unsigned count) -{ - barrier->count = count; - barrier->waiters = 0; - barrier->sequence = 0; - (void) mtx_init(&barrier->mutex, mtx_plain); - cnd_init(&barrier->condvar); -} - -static inline void pipe_barrier_destroy(pipe_barrier *barrier) -{ - assert(barrier->waiters == 0); - mtx_destroy(&barrier->mutex); - cnd_destroy(&barrier->condvar); -} - -static inline void pipe_barrier_wait(pipe_barrier *barrier) -{ - mtx_lock(&barrier->mutex); - - assert(barrier->waiters < barrier->count); - barrier->waiters++; - - if (barrier->waiters < barrier->count) { - uint64_t sequence = barrier->sequence; - - do { - cnd_wait(&barrier->condvar, &barrier->mutex); - } while (sequence == barrier->sequence); - } else { - barrier->waiters = 0; - barrier->sequence++; - cnd_broadcast(&barrier->condvar); - } - - mtx_unlock(&barrier->mutex); -} - - -#endif - - -/* * Semaphores */ typedef struct { mtx_t mutex; cnd_t cond; int counter; } pipe_semaphore; diff --git a/src/gallium/drivers/llvmpipe/lp_rast.c b/src/gallium/drivers/llvmpipe/lp_rast.c index 0050655d9e3..9e2780ca1d7 100644 --- a/src/gallium/drivers/llvmpipe/lp_rast.c +++ b/src/gallium/drivers/llvmpipe/lp_rast.c @@ -25,20 +25,21 @@ * **************************************************************************/ #include <limits.h> #include "util/u_memory.h" #include "util/u_math.h" #include "util/u_rect.h" #include "util/u_surface.h" #include "util/u_pack_color.h" #include "util/u_string.h" +#include "util/u_thread.h" #include "os/os_time.h" #include "lp_scene_queue.h" #include "lp_context.h" #include "lp_debug.h" #include "lp_fence.h" #include "lp_perf.h" #include "lp_query.h" #include "lp_rast.h" @@ -815,31 +816,31 @@ thread_function(void *init_data) * - get next scene to rasterize * - map the framebuffer surfaces */ lp_rast_begin( rast, lp_scene_dequeue( rast->full_scenes, TRUE ) ); } /* Wait for all threads to get here so that threads[1+] don't * get a null rast->curr_scene pointer. */ - pipe_barrier_wait( &rast->barrier ); + util_barrier_wait( &rast->barrier ); /* do work */ if (debug) debug_printf("thread %d doing work\n", task->thread_index); rasterize_scene(task, rast->curr_scene); /* wait for all threads to finish with this scene */ - pipe_barrier_wait( &rast->barrier ); + util_barrier_wait( &rast->barrier ); /* XXX: shouldn't be necessary: */ if (task->thread_index == 0) { lp_rast_end( rast ); } /* signal done with work */ if (debug) debug_printf("thread %d done working\n", task->thread_index); @@ -907,21 +908,21 @@ lp_rast_create( unsigned num_threads ) } rast->num_threads = num_threads; rast->no_rast = debug_get_bool_option("LP_NO_RAST", FALSE); create_rast_threads(rast); /* for synchronizing rasterization threads */ if (rast->num_threads > 0) { - pipe_barrier_init( &rast->barrier, rast->num_threads ); + util_barrier_init( &rast->barrier, rast->num_threads ); } memset(lp_dummy_tile, 0, sizeof lp_dummy_tile); return rast; no_thread_data_cache: for (i = 0; i < MAX2(1, rast->num_threads); i++) { if (rast->tasks[i].thread_data.cache) { align_free(rast->tasks[i].thread_data.cache); @@ -966,19 +967,19 @@ void lp_rast_destroy( struct lp_rasterizer *rast ) for (i = 0; i < rast->num_threads; i++) { pipe_semaphore_destroy(&rast->tasks[i].work_ready); pipe_semaphore_destroy(&rast->tasks[i].work_done); } for (i = 0; i < MAX2(1, rast->num_threads); i++) { align_free(rast->tasks[i].thread_data.cache); } /* for synchronizing rasterization threads */ if (rast->num_threads > 0) { - pipe_barrier_destroy( &rast->barrier ); + util_barrier_destroy( &rast->barrier ); } lp_scene_queue_destroy(rast->full_scenes); FREE(rast); } diff --git a/src/gallium/drivers/llvmpipe/lp_rast_priv.h b/src/gallium/drivers/llvmpipe/lp_rast_priv.h index 3cc52b8d4fd..fe078d5b869 100644 --- a/src/gallium/drivers/llvmpipe/lp_rast_priv.h +++ b/src/gallium/drivers/llvmpipe/lp_rast_priv.h @@ -21,22 +21,22 @@ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * **************************************************************************/ #ifndef LP_RAST_PRIV_H #define LP_RAST_PRIV_H -#include "os/os_thread.h" #include "util/u_format.h" +#include "util/u_thread.h" #include "gallivm/lp_bld_debug.h" #include "lp_memory.h" #include "lp_rast.h" #include "lp_scene.h" #include "lp_state.h" #include "lp_texture.h" #include "lp_limits.h" #define TILE_VECTOR_HEIGHT 4 @@ -123,21 +123,21 @@ struct lp_rasterizer /** The scene currently being rasterized by the threads */ struct lp_scene *curr_scene; /** A task object for each rasterization thread */ struct lp_rasterizer_task tasks[LP_MAX_THREADS]; unsigned num_threads; thrd_t threads[LP_MAX_THREADS]; /** For synchronizing the rasterization threads */ - pipe_barrier barrier; + util_barrier barrier; }; void lp_rast_shade_quads_mask(struct lp_rasterizer_task *task, const struct lp_rast_shader_inputs *inputs, unsigned x, unsigned y, unsigned mask); diff --git a/src/gallium/tests/unit/pipe_barrier_test.c b/src/gallium/tests/unit/pipe_barrier_test.c index 58ad7e29630..6bd46b8d964 100644 --- a/src/gallium/tests/unit/pipe_barrier_test.c +++ b/src/gallium/tests/unit/pipe_barrier_test.c @@ -20,41 +20,41 @@ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * **************************************************************************/ /* - * Test case for pipe_barrier. + * Test case for util_barrier. * * The test succeeds if no thread exits before all the other threads reach * the barrier. */ #include <stdio.h> #include <stdlib.h> -#include "os/os_thread.h" #include "os/os_time.h" #include "util/u_atomic.h" +#include "util/u_thread.h" #define NUM_THREADS 10 static int verbosity = 0; static thrd_t threads[NUM_THREADS]; -static pipe_barrier barrier; +static util_barrier barrier; static int thread_ids[NUM_THREADS]; static volatile int waiting = 0; static volatile int proceeded = 0; #define LOG(fmt, ...) \ if (verbosity > 0) { \ fprintf(stdout, fmt, ##__VA_ARGS__); \ } @@ -71,21 +71,21 @@ thread_function(void *thread_data) { int thread_id = *((int *) thread_data); LOG("thread %d starting\n", thread_id); os_time_sleep(thread_id * 100 * 1000); LOG("thread %d before barrier\n", thread_id); CHECK(p_atomic_read(&proceeded) == 0); p_atomic_inc(&waiting); - pipe_barrier_wait(&barrier); + util_barrier_wait(&barrier); CHECK(p_atomic_read(&waiting) == NUM_THREADS); p_atomic_inc(&proceeded); LOG("thread %d exiting\n", thread_id); return 0; } @@ -102,29 +102,29 @@ int main(int argc, char *argv[]) fprintf(stderr, "error: unrecognized option `%s`\n", arg); exit(EXIT_FAILURE); } } // Disable buffering setbuf(stdout, NULL); LOG("pipe_barrier_test starting\n"); - pipe_barrier_init(&barrier, NUM_THREADS); + util_barrier_init(&barrier, NUM_THREADS); for (i = 0; i < NUM_THREADS; i++) { thread_ids[i] = i; threads[i] = u_thread_create(thread_function, (void *) &thread_ids[i]); } for (i = 0; i < NUM_THREADS; i++ ) { thrd_join(threads[i], NULL); } CHECK(p_atomic_read(&proceeded) == NUM_THREADS); - pipe_barrier_destroy(&barrier); + util_barrier_destroy(&barrier); LOG("pipe_barrier_test exiting\n"); return 0; } diff --git a/src/util/u_thread.h b/src/util/u_thread.h index 6b5458af86a..e484d8aa74f 100644 --- a/src/util/u_thread.h +++ b/src/util/u_thread.h @@ -93,11 +93,85 @@ static inline bool u_thread_is_self(thrd_t thread) { #if defined(HAVE_PTHREAD) # if defined(__GNU_LIBRARY__) && defined(__GLIBC__) && defined(__GLIBC_MINOR__) && \ (__GLIBC__ >= 3 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 12)) return pthread_equal(pthread_self(), thread); # endif #endif return false; } +/* + * util_barrier + */ + +#if defined(HAVE_PTHREAD) + +typedef pthread_barrier_t util_barrier; + +static inline void util_barrier_init(util_barrier *barrier, unsigned count) +{ + pthread_barrier_init(barrier, NULL, count); +} + +static inline void util_barrier_destroy(util_barrier *barrier) +{ + pthread_barrier_destroy(barrier); +} + +static inline void util_barrier_wait(util_barrier *barrier) +{ + pthread_barrier_wait(barrier); +} + + +#else /* If the OS doesn't have its own, implement barriers using a mutex and a condvar */ + +typedef struct { + unsigned count; + unsigned waiters; + uint64_t sequence; + mtx_t mutex; + cnd_t condvar; +} util_barrier; + +static inline void util_barrier_init(util_barrier *barrier, unsigned count) +{ + barrier->count = count; + barrier->waiters = 0; + barrier->sequence = 0; + (void) mtx_init(&barrier->mutex, mtx_plain); + cnd_init(&barrier->condvar); +} + +static inline void util_barrier_destroy(util_barrier *barrier) +{ + assert(barrier->waiters == 0); + mtx_destroy(&barrier->mutex); + cnd_destroy(&barrier->condvar); +} + +static inline void util_barrier_wait(util_barrier *barrier) +{ + mtx_lock(&barrier->mutex); + + assert(barrier->waiters < barrier->count); + barrier->waiters++; + + if (barrier->waiters < barrier->count) { + uint64_t sequence = barrier->sequence; + + do { + cnd_wait(&barrier->condvar, &barrier->mutex); + } while (sequence == barrier->sequence); + } else { + barrier->waiters = 0; + barrier->sequence++; + cnd_broadcast(&barrier->condvar); + } + + mtx_unlock(&barrier->mutex); +} + +#endif + #endif /* U_THREAD_H_ */ -- 2.11.0 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev