Skip to content

Commit 3c64a98

Browse files
authored
[libc] Partially implement 'errno' on the GPU (#97107)
Summary: The `errno` variable is expected to be `thread_local` by the standard. However, the GPU targets do not support `thread_local` and implementing that would be a large endeavor. Because of that, we previously didn't provide the `errno` symbol at all. However, to build some programs we at least need to be able to link against `errno`. Many things that would normally set `errno` completely ignore it currently (i.e. stdio) but some programs still need to be able to link against correct C programs. For this purpose this patch exports the `errno` symbol as a simple global. Internally, this will be updated atomically so it's at least not racy. Externally, this will be on the user. I've updated the documentation to state as such. This is required to get `libc++` to build.
1 parent ec0e6ef commit 3c64a98

File tree

3 files changed

+14
-8
lines changed

3 files changed

+14
-8
lines changed

libc/docs/gpu/motivation.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ Limitations
4444

4545
We only implement a subset of the standard C library. The GPU does not
4646
currently support thread local variables in all cases, so variables like
47-
``errno`` are not provided. Furthermore, the GPU under the OpenCL execution
47+
``errno`` are atomic and global. Furthermore, the GPU under the OpenCL execution
4848
model cannot safely provide a mutex interface. This means that features like
4949
file buffering are not implemented on the GPU. We can also not easily provide
5050
threading features on the GPU due to the execution model so these will be

libc/include/errno.h.def

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,18 @@
2525
#include "llvm-libc-macros/generic-error-number-macros.h"
2626
#endif
2727

28-
#if !defined(__AMDGPU__) && !defined(__NVPTX__)
29-
28+
#if defined(__AMDGPU__) || defined(__NVPTX__)
29+
extern int __llvmlibc_errno; // Not thread_local!
30+
#else
3031
#ifdef __cplusplus
3132
extern "C" {
3233
extern thread_local int __llvmlibc_errno;
3334
}
3435
#else
3536
extern _Thread_local int __llvmlibc_errno;
3637
#endif // __cplusplus
38+
#endif
3739

3840
#define errno __llvmlibc_errno
39-
#endif
4041

4142
#endif // LLVM_LIBC_ERRNO_H

libc/src/errno/libc_errno.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,21 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "libc_errno.h"
10+
#include "src/__support/CPP/atomic.h"
1011

1112
#ifdef LIBC_TARGET_ARCH_IS_GPU
12-
// LIBC_THREAD_LOCAL on GPU currently does nothing. So essentially this is just
13+
// LIBC_THREAD_LOCAL on GPU currently does nothing. So essentially this is just
1314
// a global errno for gpu to use for now.
1415
extern "C" {
15-
LIBC_THREAD_LOCAL int __llvmlibc_gpu_errno;
16+
LIBC_THREAD_LOCAL LIBC_NAMESPACE::cpp::Atomic<int> __llvmlibc_errno;
1617
}
1718

18-
void LIBC_NAMESPACE::Errno::operator=(int a) { __llvmlibc_gpu_errno = a; }
19-
LIBC_NAMESPACE::Errno::operator int() { return __llvmlibc_gpu_errno; }
19+
void LIBC_NAMESPACE::Errno::operator=(int a) {
20+
__llvmlibc_errno.store(a, cpp::MemoryOrder::RELAXED);
21+
}
22+
LIBC_NAMESPACE::Errno::operator int() {
23+
return __llvmlibc_errno.load(cpp::MemoryOrder::RELAXED);
24+
}
2025

2126
#elif !defined(LIBC_COPT_PUBLIC_PACKAGING)
2227
// This mode is for unit testing. We just use our internal errno.

0 commit comments

Comments
 (0)