-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[libc] Implement barriers for pthreads #148948
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
2d5b880
cefd7de
d645f95
8cad8c0
7adf56a
a349e6f
d901a37
0512e7f
ecf9f6c
1a828f4
3122439
e20d450
4373ef7
7bbd476
1e80063
86b9074
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| //===-- Definition of pthread_barrier_t type ------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIBC_TYPES_PTHREAD_BARRIER_T_H | ||
| #define LLVM_LIBC_TYPES_PTHREAD_BARRIER_T_H | ||
|
|
||
| typedef struct { | ||
| char padding[88]; | ||
| } pthread_barrier_t; | ||
|
|
||
| #endif // LLVM_LIBC_TYPES_PTHREAD_BARRIER_T_H | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| //===-- Definition of pthread_barrierattr_t type --------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIBC_TYPES_PTHREAD_BARRIERATTR_T_H | ||
| #define LLVM_LIBC_TYPES_PTHREAD_BARRIERATTR_T_H | ||
|
|
||
| typedef struct { | ||
| bool pshared; | ||
| } pthread_barrierattr_t; | ||
|
|
||
| #endif // LLVM_LIBC_TYPES_PTHREAD_BARRIERATTR_T_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| //===-- 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/barrier.h" | ||
| #include "barrier.h" | ||
| #include "hdr/errno_macros.h" | ||
| #include "src/__support/threads/mutex.h" | ||
uzairnawaz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| const int BARRIER_FIRST_EXITED = -1; | ||
uzairnawaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| int Barrier::init(Barrier *b, | ||
| const pthread_barrierattr_t *attr __attribute__((unused)), | ||
uzairnawaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The answer might be "no", but: Isn't there a macro for this "check error and return it if it's nonzero" construct?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't believe there is something for this specific pattern, or at least I haven't encountered one yet (also skimmed through the __support/macros folder and I don't see anything like this unfortunately). |
||
|
|
||
| err = CndVar::init(&b->exiting); | ||
| if (err != 0) | ||
| return err; | ||
|
|
||
| Mutex::init(&b->m, false, false, false, false); | ||
uzairnawaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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) { | ||
uzairnawaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // this is the last thread to call wait(), so lets wake everyone up | ||
| blocking = false; | ||
| exiting.broadcast(); | ||
| } else { | ||
| // block threads until waiting = expected | ||
| while (blocking) { | ||
| exiting.wait(&m); | ||
| } | ||
| } | ||
| waiting--; | ||
|
|
||
| // all threads have exited the barrier, lets let the ones waiting to enter | ||
| // continue | ||
uzairnawaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (waiting == 0) { | ||
| blocking = true; | ||
| entering.broadcast(); | ||
| m.unlock(); | ||
| return BARRIER_FIRST_EXITED; | ||
| } | ||
| m.unlock(); | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| int Barrier::destroy(Barrier *b) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does this have a return value?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The idea was to have According to the standard (https://pubs.opengroup.org/onlinepubs/9799919799/): "The results are undefined if pthread_barrier_destroy() is called when any thread is blocked on the barrier, or if this function is called with an uninitialized barrier." However: If an implementation detects that the value specified by the attr argument to pthread_barrier_init() does not refer to an initialized barrier attributes object, it is recommended that the function should fail and report an [EINVAL] error." Since the standard doesn't actually require these error codes, I choose to just always return 0, but a future patch could include these error codes, so I think it makes sense to keep the return value. |
||
| CndVar::destroy(&b->entering); | ||
| CndVar::destroy(&b->exiting); | ||
| Mutex::destroy(&b->m); | ||
| return 0; | ||
| } | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| //===-- A platform independent abstraction layer for barriers --*- C++ -*-===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIBC___SUPPORT_SRC_THREADS_LINUX_BARRIER_H | ||
| #define LLVM_LIBC___SUPPORT_SRC_THREADS_LINUX_BARRIER_H | ||
|
|
||
| #include "include/llvm-libc-types/pthread_barrier_t.h" | ||
| #include "include/llvm-libc-types/pthread_barrierattr_t.h" | ||
| #include "src/__support/macros/config.h" | ||
| #include "src/__support/threads/CndVar.h" | ||
| #include "src/__support/threads/mutex.h" | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| // NOTE: if the size of this class changes, you must ensure that the size of | ||
| // pthread_barrier_t (found in include/llvm-libc/types/pthread_barrier_t.h) is | ||
| // the same size | ||
|
|
||
| extern const int BARRIER_FIRST_EXITED; | ||
|
|
||
| class Barrier { | ||
uzairnawaz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| private: | ||
| unsigned expected; | ||
| unsigned waiting; | ||
| bool blocking; | ||
| CndVar entering; | ||
| CndVar exiting; | ||
| Mutex m; | ||
|
|
||
| public: | ||
| static int init(Barrier *b, const pthread_barrierattr_t *attr, | ||
| unsigned count); | ||
| static int destroy(Barrier *b); | ||
| int wait(); | ||
| }; | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL | ||
|
|
||
| #endif // LLVM_LIBC___SUPPORT_SRC_THREADS_LINUX_BARRIER_H | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| //===-- Linux implementation of the pthread_barrier_init function ---------===// | ||
| // | ||
| // 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 "pthread_barrier_destroy.h" | ||
|
|
||
| #include "src/__support/common.h" | ||
| #include "src/__support/macros/config.h" | ||
| #include "src/__support/threads/barrier.h" | ||
|
|
||
| #include <pthread.h> | ||
uzairnawaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| LLVM_LIBC_FUNCTION(int, pthread_barrier_destroy, (pthread_barrier_t * b)) { | ||
| return Barrier::destroy(reinterpret_cast<Barrier *>(b)); | ||
| } | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| //===-- Implementation header for pthread_barrier_destroy --------*- C++-*-===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_BARRIER_DESTROY_H | ||
| #define LLVM_LIBC_SRC_PTHREAD_PTHREAD_BARRIER_DESTROY_H | ||
|
|
||
| #include "src/__support/macros/config.h" | ||
| #include <pthread.h> | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| int pthread_barrier_destroy(pthread_barrier_t *b); | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL | ||
|
|
||
| #endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_BARRIER_DESTROY_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| //===-- Linux implementation of the pthread_barrier_init function ---------===// | ||
| // | ||
| // 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 "pthread_barrier_init.h" | ||
|
|
||
| #include "src/__support/common.h" | ||
| #include "src/__support/macros/config.h" | ||
| #include "src/__support/threads/barrier.h" | ||
|
|
||
| #include <pthread.h> | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| static_assert( | ||
| sizeof(Barrier) <= sizeof(pthread_barrier_t), | ||
uzairnawaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| "The public pthread_barrier_t type cannot accommodate the internal " | ||
| "barrier type."); | ||
|
|
||
| LLVM_LIBC_FUNCTION(int, pthread_barrier_init, | ||
| (pthread_barrier_t * b, | ||
| const pthread_barrierattr_t *__restrict attr, | ||
| unsigned count)) { | ||
| return Barrier::init(reinterpret_cast<Barrier *>(b), attr, count); | ||
| } | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| //===-- Implementation header for pthread_barrier_init ----------*- C++ -*-===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_BARRIER_INIT_H | ||
| #define LLVM_LIBC_SRC_PTHREAD_PTHREAD_BARRIER_INIT_H | ||
|
|
||
| #include "src/__support/macros/config.h" | ||
| #include <pthread.h> | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| int pthread_barrier_init(pthread_barrier_t *b, | ||
| const pthread_barrierattr_t *__restrict attr, | ||
| unsigned count); | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL | ||
|
|
||
| #endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_BARRIER_INIT_H |
Uh oh!
There was an error while loading. Please reload this page.