| //===-- Implementation of Barrier class ------------- ---------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "src/__support/threads/linux/barrier.h" |
| #include "hdr/errno_macros.h" |
| #include "src/__support/threads/CndVar.h" |
| #include "src/__support/threads/mutex.h" |
| |
| namespace LIBC_NAMESPACE_DECL { |
| |
| int Barrier::init(Barrier *b, |
| [[maybe_unused]] const pthread_barrierattr_t *attr, |
| unsigned count) { |
| LIBC_ASSERT(attr == nullptr); // TODO implement barrierattr |
| if (count == 0) |
| return EINVAL; |
| |
| b->expected = count; |
| b->waiting = 0; |
| b->blocking = true; |
| |
| int err; |
| err = CndVar::init(&b->entering); |
| if (err != 0) |
| return err; |
| |
| err = CndVar::init(&b->exiting); |
| if (err != 0) |
| return err; |
| |
| auto mutex_err = Mutex::init(&b->m, false, false, false, false); |
| if (mutex_err != MutexError::NONE) |
| return EAGAIN; |
| |
| return 0; |
| } |
| |
| int Barrier::wait() { |
| m.lock(); |
| |
| // if the barrier is emptying out threads, wait until it finishes |
| while (!blocking) |
| entering.wait(&m); |
| waiting++; |
| |
| if (waiting < expected) { |
| // block threads until waiting = expected |
| while (blocking) |
| exiting.wait(&m); |
| } else { |
| // this is the last thread to call wait(), so lets wake everyone up |
| blocking = false; |
| exiting.broadcast(); |
| } |
| waiting--; |
| |
| if (waiting == 0) { |
| // all threads have exited the barrier, let's let the ones waiting to enter |
| // continue |
| blocking = true; |
| entering.broadcast(); |
| m.unlock(); |
| |
| // POSIX dictates that the barrier should return a special value to just one |
| // thread, so we can arbitrarily choose this thread |
| return PTHREAD_BARRIER_SERIAL_THREAD; |
| } |
| m.unlock(); |
| |
| return 0; |
| } |
| |
| int Barrier::destroy(Barrier *b) { |
| CndVar::destroy(&b->entering); |
| CndVar::destroy(&b->exiting); |
| Mutex::destroy(&b->m); |
| return 0; |
| } |
| |
| } // namespace LIBC_NAMESPACE_DECL |