[libc] Enable threads.h functions on aarch64.
authorSiva Chandra <sivachandra@google.com>
Thu, 31 Mar 2022 06:44:57 +0000 (23:44 -0700)
committerSiva Chandra <sivachandra@google.com>
Thu, 31 Mar 2022 15:42:07 +0000 (08:42 -0700)
Reviewed By: lntue

Differential Revision: https://reviews.llvm.org/D122788

libc/config/linux/aarch64/entrypoints.txt
libc/src/threads/linux/CMakeLists.txt
libc/src/threads/linux/Thread.h
libc/src/threads/linux/thrd_create.cpp
libc/src/threads/linux/x86_64/thread_start_args.h.in [deleted file]

index cd2b52f..72919c1 100644 (file)
@@ -213,6 +213,24 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.sys.mman.munmap
 )
 
+if(LLVM_LIBC_FULL_BUILD)
+  list(APPEND TARGET_LIBC_ENTRYPOINTS
+    # threads.h entrypoints
+    libc.src.threads.call_once
+    libc.src.threads.cnd_broadcast
+    libc.src.threads.cnd_destroy
+    libc.src.threads.cnd_init
+    libc.src.threads.cnd_signal
+    libc.src.threads.cnd_wait
+    libc.src.threads.mtx_destroy
+    libc.src.threads.mtx_init
+    libc.src.threads.mtx_lock
+    libc.src.threads.mtx_unlock
+    libc.src.threads.thrd_create
+    libc.src.threads.thrd_join
+  )
+endif()
+
 set(TARGET_LLVMLIBC_ENTRYPOINTS
   ${TARGET_LIBC_ENTRYPOINTS}
   ${TARGET_LIBM_ENTRYPOINTS}
index 6706c42..0941711 100644 (file)
@@ -1,13 +1,3 @@
-add_gen_header(
-  thread_start_args_h
-  DEF_FILE thread_start_args.h.def
-  GEN_HDR thread_start_args.h
-  PARAMS
-    thread_start_args=${LIBC_TARGET_ARCHITECTURE}/thread_start_args.h.in
-  DATA_FILES
-    ${LIBC_TARGET_ARCHITECTURE}/thread_start_args.h.in
-)
-
 add_entrypoint_object(
   call_once
   SRCS
@@ -29,7 +19,6 @@ add_header_library(
     Futex.h
     Thread.h
   DEPENDS
-    .thread_start_args_h
     libc.include.sys_syscall
     libc.include.threads
     libc.src.__support.CPP.atomic
index a14ed49..de58ae4 100644 (file)
@@ -9,8 +9,6 @@
 #ifndef LLVM_LIBC_SRC_THREADS_LINUX_THREAD_UTILS_H
 #define LLVM_LIBC_SRC_THREADS_LINUX_THREAD_UTILS_H
 
-#include "thread_start_args.h"
-
 #include <stdint.h>
 
 namespace __llvm_libc {
index 34b5039..e893374 100644 (file)
@@ -13,6 +13,7 @@
 #include "include/sys/syscall.h"          // For syscall numbers.
 #include "include/threads.h"              // For thrd_* type definitions.
 #include "src/__support/OSUtil/syscall.h" // For syscall function.
+#include "src/__support/architectures.h"
 #include "src/__support/common.h"
 #include "src/errno/llvmlibc_errno.h"
 #include "src/sys/mman/mmap.h"
 
 namespace __llvm_libc {
 
-struct StartArgs {
+// We align the start args to 16-byte boundary as we adjust the allocated
+// stack memory with its size. We want the adjusted address to be at a
+// 16-byte boundary to satisfy the x86_64 and aarch64 ABI requirements.
+// If different architecture in future requires higher alignment, then we
+// can add a platform specific alignment spec.
+struct alignas(16) StartArgs {
   thrd_t *thread;
   thrd_start_t func;
   void *arg;
 };
 
+__attribute__((always_inline)) inline uintptr_t get_start_args_addr() {
+  // NOTE: For __builtin_frame_address to work reliably across compilers,
+  // architectures and various optimization levels, the TU including this file
+  // should be compiled with -fno-omit-frame-pointer.
+  return reinterpret_cast<uintptr_t>(__builtin_frame_address(0))
+         // The x86_64 call instruction pushes resume address on to the stack.
+         // Next, The x86_64 SysV ABI requires that the frame pointer be pushed
+         // on to the stack. Similarly on aarch64, previous frame pointer and
+         // the value of the link register are pushed on to the stack. So, in
+         // both these cases, we have to step past two 64-bit values to get
+         // to the start args.
+         + sizeof(uintptr_t) * 2;
+}
+
 static __attribute__((noinline)) void start_thread() {
   StartArgs *start_args = reinterpret_cast<StartArgs *>(get_start_args_addr());
   __llvm_libc::syscall(SYS_exit, start_args->thread->__retval =
@@ -79,13 +99,29 @@ LLVM_LIBC_FUNCTION(int, thrd_create,
   start_args->func = func;
   start_args->arg = arg;
 
-  // TODO: The arguments to the clone syscall below is correct for x86_64
-  // but it might differ for other architectures. So, make this call
-  // architecture independent. May be implement a glibc like wrapper for clone
-  // and use it here.
+  // The clone syscall takes arguments in an architecture specific order.
+  // Also, we want the result of the syscall to be in a register as the child
+  // thread gets a completely different stack after it is created. The stack
+  // variables from this function will not be availalbe to the child thread.
+#ifdef LLVM_LIBC_ARCH_X86_64
   long register clone_result asm("rax");
-  clone_result = __llvm_libc::syscall(SYS_clone, clone_flags, adjusted_stack,
-                                      &thread->__tid, clear_tid_address, 0);
+  clone_result = __llvm_libc::syscall(
+      SYS_clone, clone_flags, adjusted_stack,
+      &thread->__tid,    // The address where the child tid is written
+      clear_tid_address, // The futex where the child thread status is signalled
+      0                  // Set TLS to null for now.
+  );
+#elif defined(LLVM_LIBC_ARCH_AARCH64)
+  long register clone_result asm("x0");
+  clone_result = __llvm_libc::syscall(
+      SYS_clone, clone_flags, adjusted_stack,
+      &thread->__tid,   // The address where the child tid is written
+      0,                // Set TLS to null for now.
+      clear_tid_address // The futex where the child thread status is signalled
+  );
+#else
+#error "Unsupported architecture for the clone syscall."
+#endif
 
   if (clone_result == 0) {
     start_thread();
diff --git a/libc/src/threads/linux/x86_64/thread_start_args.h.in b/libc/src/threads/linux/x86_64/thread_start_args.h.in
deleted file mode 100644 (file)
index 36365b9..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-//===- x86_64 implementation of the get_start_args_addr function -*- 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
-//
-//===----------------------------------------------------------------------===//
-
-%%begin()
-
-namespace __llvm_libc {
-
-__attribute__((always_inline)) inline uintptr_t get_start_args_addr() {
-  // NOTE: For __builtin_frame_address to work reliably across compilers,
-  // architectures and various optimization levels, the TU including this file
-  // should be compiled with -fno-omit-frame-pointer.
-  return reinterpret_cast<uintptr_t>(__builtin_frame_address(0)) +
-         // The x86_64 call instruction pushes resume address on to the stack.
-         // Next, The x86_64 SysV ABI also pushes the frame pointer on the
-         // stack. Hence, we look past these items to get to the start args.
-         sizeof(uintptr_t) * 2;
-}
-
-} // namespace __llvm_libc