| //===-- 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/CPP/new.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; | |
| new (&b->entering) CndVar(attr ? attr->pshared : false); | |
| new (&b->exiting) CndVar(attr ? attr->pshared : false); | |
| new (&b->m) Mutex(/*is_priority_inherit=*/false, /*is_recursive=*/false, | |
| /*is_robust=*/false, | |
| /*is_pshared=*/attr ? attr->pshared : false); | |
| 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) { | |
| b->entering.reset(); | |
| b->exiting.reset(); | |
| Mutex::destroy(&b->m); | |
| return 0; | |
| } | |
| } // namespace LIBC_NAMESPACE_DECL |