From b130d96445bf1551ae88bde9a9dda18a47c41049 Mon Sep 17 00:00:00 2001 From: tatehaga Date: Tue, 23 Oct 2018 15:19:27 -0400 Subject: [PATCH] barrier implementation using semaphores (#186) --- nx/include/switch.h | 1 + nx/include/switch/kernel/barrier.h | 30 ++++++++++++++++++++++++++++++ nx/source/kernel/barrier.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 nx/include/switch/kernel/barrier.h create mode 100644 nx/source/kernel/barrier.c diff --git a/nx/include/switch.h b/nx/include/switch.h index dd22df23..6c5d8423 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -34,6 +34,7 @@ extern "C" { #include "switch/kernel/random.h" #include "switch/kernel/jit.h" #include "switch/kernel/ipc.h" +#include "switch/kernel/barrier.h" #include "switch/services/sm.h" #include "switch/services/smm.h" diff --git a/nx/include/switch/kernel/barrier.h b/nx/include/switch/kernel/barrier.h new file mode 100644 index 00000000..befa6e93 --- /dev/null +++ b/nx/include/switch/kernel/barrier.h @@ -0,0 +1,30 @@ +/** + * @file barrier.h + * @brief Multi-threading Barrier + * @author tatehaga + * @copyright libnx Authors + */ +#pragma once +#include "semaphore.h" + +/// Barrier structure. +typedef struct Barrier { + u64 count; ///< Number of threads to reach the barrier. + u64 thread_total; ///< Number of threads to wait on. + Semaphore throttle; ///< Semaphore to make sure threads release to scheduler one at a time. + Semaphore lock; ///< Semaphore to lock barrier to prevent multiple operations by threads at once. + Semaphore thread_wait; ///< Semaphore to force a thread to wait if count < thread_total. +} Barrier; + +/** + * @brief Initializes a barrier and the number of threads to wait on. + * @param b Barrier object. + * @param thread_count Initial value for the number of threads the barrier must wait for. + */ +void barrierInit(Barrier *b, u64 thread_count); + +/** + * @brief Forces threads to wait until all threads have called barrierWait. + * @param b Barrier object. + */ +void barrierWait(Barrier *b); diff --git a/nx/source/kernel/barrier.c b/nx/source/kernel/barrier.c new file mode 100644 index 00000000..d0c9af1b --- /dev/null +++ b/nx/source/kernel/barrier.c @@ -0,0 +1,29 @@ +#include "kernel/barrier.h" + +void barrierInit(Barrier *b, u64 thread_count) { + b->count = 0; + b->thread_total = thread_count; + semaphoreInit(&b->throttle, 0); + semaphoreInit(&b->lock, 1); + semaphoreInit(&b->thread_wait, 0); +} + +void barrierWait(Barrier *b) { + semaphoreWait(&b->lock); + if(b->count < b->thread_total) { + b->count++; + } + if(b->count < b->thread_total) { + semaphoreSignal(&b->lock); + semaphoreWait(&b->thread_wait); + semaphoreSignal(&b->throttle); + } + else if(b->count == b->thread_total) { + for(int i = 0; i < b->thread_total-1; i++) { + semaphoreSignal(&b->thread_wait); + semaphoreWait(&b->throttle); + } + b->count = 0; + semaphoreSignal(&b->lock); + } +}