forked from OSchip/llvm-project
[libc] Add GNU extension functions pthread_setname_np and pthread_getname_np.
Reviewed By: michaelrj, lntue Differential Revision: https://reviews.llvm.org/D130872
This commit is contained in:
parent
1c52b4f798
commit
658c84e415
|
@ -251,8 +251,10 @@ if(LLVM_LIBC_FULL_BUILD)
|
|||
libc.src.pthread.pthread_create
|
||||
libc.src.pthread.pthread_detach
|
||||
libc.src.pthread.pthread_equal
|
||||
libc.src.pthread.pthread_getname_np
|
||||
libc.src.pthread.pthread_join
|
||||
libc.src.pthread.pthread_self
|
||||
libc.src.pthread.pthread_setname_np
|
||||
libc.src.pthread.pthread_mutex_destroy
|
||||
libc.src.pthread.pthread_mutex_init
|
||||
libc.src.pthread.pthread_mutex_lock
|
||||
|
|
|
@ -111,10 +111,30 @@ def GnuExtensions : StandardSpec<"GNUExtensions"> {
|
|||
]
|
||||
>;
|
||||
|
||||
HeaderSpec PThread = HeaderSpec<
|
||||
"pthread.h",
|
||||
[], // Macros
|
||||
[], // Types
|
||||
[], // Enumerations
|
||||
[
|
||||
FunctionSpec<
|
||||
"pthread_setname_np",
|
||||
RetValSpec<IntType>,
|
||||
[ArgSpec<PThreadTType>, ArgSpec<ConstCharPtr>]
|
||||
>,
|
||||
FunctionSpec<
|
||||
"pthread_getname_np",
|
||||
RetValSpec<IntType>,
|
||||
[ArgSpec<PThreadTType>, ArgSpec<CharPtr>, ArgSpec<SizeTType>]
|
||||
>,
|
||||
]
|
||||
>;
|
||||
|
||||
let Headers = [
|
||||
CType,
|
||||
FEnv,
|
||||
Math,
|
||||
PThread,
|
||||
StdIO,
|
||||
String,
|
||||
];
|
||||
|
|
|
@ -50,7 +50,6 @@ def POSIX : StandardSpec<"POSIX"> {
|
|||
ConstType ConstPThreadMutexTPtr = ConstType<PThreadMutexTPtr>;
|
||||
ConstType ConstRestrictedPThreadMutexTPtr = ConstType<RestrictedPThreadMutexTPtr>;
|
||||
|
||||
NamedType PThreadTType = NamedType<"pthread_t">;
|
||||
PtrType PThreadTPtr = PtrType<PThreadTType>;
|
||||
RestrictedPtrType RestrictedPThreadTPtr = RestrictedPtrType<PThreadTType>;
|
||||
|
||||
|
|
|
@ -107,6 +107,8 @@ def FILE : NamedType<"FILE">;
|
|||
def FILEPtr : PtrType<FILE>;
|
||||
def FILERestrictedPtr : RestrictedPtrType<FILE>;
|
||||
|
||||
def PThreadTType : NamedType<"pthread_t">;
|
||||
|
||||
//added because __assert_fail needs it.
|
||||
def UnsignedType : NamedType<"unsigned">;
|
||||
|
||||
|
|
|
@ -85,6 +85,8 @@ public:
|
|||
|
||||
// Return true if any write operation(s) failed due to insufficient size.
|
||||
bool overflow() const { return err; }
|
||||
|
||||
size_t bufsize() const { return data.size(); }
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
|
|
|
@ -25,6 +25,8 @@ add_header_library(
|
|||
DEPENDS
|
||||
libc.src.__support.common
|
||||
libc.src.__support.CPP.atomic
|
||||
libc.src.__support.CPP.string_view
|
||||
libc.src.__support.CPP.stringstream
|
||||
)
|
||||
|
||||
if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.thread)
|
||||
|
|
|
@ -30,6 +30,8 @@ add_object_library(
|
|||
libc.include.sys_syscall
|
||||
libc.src.__support.CPP.atomic
|
||||
libc.src.__support.CPP.error
|
||||
libc.src.__support.CPP.stringstream
|
||||
libc.src.__support.CPP.string_view
|
||||
libc.src.__support.threads.thread_common
|
||||
COMPILE_OPTIONS
|
||||
-O3
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
|
||||
#include "src/__support/threads/thread.h"
|
||||
#include "config/linux/app.h"
|
||||
#include "src/__support/CPP/StringView.h"
|
||||
#include "src/__support/CPP/atomic.h"
|
||||
#include "src/__support/CPP/error.h"
|
||||
#include "src/__support/CPP/stringstream.h"
|
||||
#include "src/__support/OSUtil/syscall.h" // For syscall functions.
|
||||
#include "src/__support/threads/linux/futex_word.h" // For FutexWordType
|
||||
|
||||
|
@ -17,7 +19,10 @@
|
|||
#include <arm_acle.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/futex.h>
|
||||
#include <linux/prctl.h> // For PR_SET_NAME
|
||||
#include <linux/sched.h> // For CLONE_* flags.
|
||||
#include <stdint.h>
|
||||
#include <sys/mman.h> // For PROT_* and MAP_* definitions.
|
||||
|
@ -33,6 +38,7 @@ static constexpr long MMAP_SYSCALL_NUMBER = SYS_mmap;
|
|||
#error "SYS_mmap or SYS_mmap2 not available on the target platform"
|
||||
#endif
|
||||
|
||||
static constexpr size_t NAME_SIZE_MAX = 16; // Includes the null terminator
|
||||
static constexpr size_t DEFAULT_STACK_SIZE = (1 << 16); // 64KB
|
||||
static constexpr uint32_t CLEAR_TID_VALUE = 0xABCD1234;
|
||||
static constexpr unsigned CLONE_SYSCALL_FLAGS =
|
||||
|
@ -278,4 +284,95 @@ bool Thread::operator==(const Thread &thread) const {
|
|||
return attrib->tid == thread.attrib->tid;
|
||||
}
|
||||
|
||||
static constexpr cpp::StringView THREAD_NAME_PATH_PREFIX("/proc/self/task/");
|
||||
static constexpr size_t THREAD_NAME_PATH_SIZE =
|
||||
THREAD_NAME_PATH_PREFIX.size() +
|
||||
IntegerToString<int>::BUFSIZE + // Size of tid
|
||||
1 + // For '/' character
|
||||
5; // For the file name "comm" and the nullterminator.
|
||||
|
||||
static void construct_thread_name_file_path(cpp::StringStream &stream,
|
||||
int tid) {
|
||||
stream << THREAD_NAME_PATH_PREFIX << tid << '/' << cpp::StringView("comm")
|
||||
<< cpp::StringStream::ENDS;
|
||||
}
|
||||
|
||||
int Thread::set_name(const cpp::StringView &name) {
|
||||
if (name.size() >= NAME_SIZE_MAX)
|
||||
return ERANGE;
|
||||
|
||||
if (*this == self) {
|
||||
// If we are setting the name of the current thread, then we can
|
||||
// use the syscall to set the name.
|
||||
int retval = __llvm_libc::syscall(SYS_prctl, PR_SET_NAME, name.data());
|
||||
if (retval < 0)
|
||||
return -retval;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
char path_name_buffer[THREAD_NAME_PATH_SIZE];
|
||||
cpp::StringStream path_stream(path_name_buffer);
|
||||
construct_thread_name_file_path(path_stream, attrib->tid);
|
||||
#ifdef SYS_open
|
||||
int fd = __llvm_libc::syscall(SYS_open, path_name_buffer, O_RDWR);
|
||||
#else
|
||||
int fd = __llvm_libc::syscall(SYS_openat, AT_FDCWD, path_name_buffer, O_RDWR);
|
||||
#endif
|
||||
if (fd < 0)
|
||||
return -fd;
|
||||
|
||||
int retval = __llvm_libc::syscall(SYS_write, fd, name.data(), name.size());
|
||||
__llvm_libc::syscall(SYS_close, fd);
|
||||
|
||||
if (retval < 0)
|
||||
return -retval;
|
||||
else if (retval != int(name.size()))
|
||||
return EIO;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Thread::get_name(cpp::StringStream &name) const {
|
||||
if (name.bufsize() < NAME_SIZE_MAX)
|
||||
return ERANGE;
|
||||
|
||||
char name_buffer[NAME_SIZE_MAX];
|
||||
|
||||
if (*this == self) {
|
||||
// If we are getting the name of the current thread, then we can
|
||||
// use the syscall to get the name.
|
||||
int retval = __llvm_libc::syscall(SYS_prctl, PR_GET_NAME, name_buffer);
|
||||
if (retval < 0)
|
||||
return -retval;
|
||||
name << name_buffer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char path_name_buffer[THREAD_NAME_PATH_SIZE];
|
||||
cpp::StringStream path_stream(path_name_buffer);
|
||||
construct_thread_name_file_path(path_stream, attrib->tid);
|
||||
#ifdef SYS_open
|
||||
int fd = __llvm_libc::syscall(SYS_open, path_name_buffer, O_RDONLY);
|
||||
#else
|
||||
int fd =
|
||||
__llvm_libc::syscall(SYS_openat, AT_FDCWD, path_name_buffer, O_RDONLY);
|
||||
#endif
|
||||
if (fd < 0)
|
||||
return -fd;
|
||||
|
||||
int retval = __llvm_libc::syscall(SYS_read, fd, name_buffer, NAME_SIZE_MAX);
|
||||
__llvm_libc::syscall(SYS_close, fd);
|
||||
if (retval < 0)
|
||||
return -retval;
|
||||
if (retval == NAME_SIZE_MAX)
|
||||
return ERANGE;
|
||||
if (name_buffer[retval - 1] == '\n')
|
||||
name_buffer[retval - 1] = '\0';
|
||||
else
|
||||
name_buffer[retval] = '\0';
|
||||
name << name_buffer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
#ifndef LLVM_LIBC_SRC_SUPPORT_THREADS_THREAD_H
|
||||
#define LLVM_LIBC_SRC_SUPPORT_THREADS_THREAD_H
|
||||
|
||||
#include "src/__support/CPP/StringView.h"
|
||||
#include "src/__support/CPP/atomic.h"
|
||||
#include "src/__support/CPP/stringstream.h"
|
||||
#include "src/__support/architectures.h"
|
||||
|
||||
#include <stddef.h> // For size_t
|
||||
|
@ -165,6 +167,12 @@ struct Thread {
|
|||
|
||||
// Return true if this thread is equal to the other thread.
|
||||
bool operator==(const Thread &other) const;
|
||||
|
||||
// Set the name of the thread. Return the error number on error.
|
||||
int set_name(const cpp::StringView &name);
|
||||
|
||||
// Return the name of the thread in |name|. Return the error number of error.
|
||||
int get_name(cpp::StringStream &name) const;
|
||||
};
|
||||
|
||||
extern thread_local Thread self;
|
||||
|
|
|
@ -301,3 +301,29 @@ add_entrypoint_object(
|
|||
libc.include.pthread
|
||||
libc.src.__support.threads.thread
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
pthread_setname_np
|
||||
SRCS
|
||||
pthread_setname_np.cpp
|
||||
HDRS
|
||||
pthread_setname_np.h
|
||||
DEPENDS
|
||||
libc.include.pthread
|
||||
libc.src.__support.CPP.array_ref
|
||||
libc.src.__support.CPP.string_view
|
||||
libc.src.__support.threads.thread
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
pthread_getname_np
|
||||
SRCS
|
||||
pthread_getname_np.cpp
|
||||
HDRS
|
||||
pthread_getname_np.h
|
||||
DEPENDS
|
||||
libc.include.pthread
|
||||
libc.src.__support.CPP.array_ref
|
||||
libc.src.__support.CPP.stringstream
|
||||
libc.src.__support.threads.thread
|
||||
)
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
//===-- Linux implementation of the pthread_setname_np 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_getname_np.h"
|
||||
|
||||
#include "src/__support/CPP/ArrayRef.h"
|
||||
#include "src/__support/CPP/StringView.h"
|
||||
#include "src/__support/common.h"
|
||||
#include "src/__support/threads/thread.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
static_assert(sizeof(pthread_t) == sizeof(__llvm_libc::Thread),
|
||||
"Mismatch between pthread_t and internal Thread.");
|
||||
|
||||
LLVM_LIBC_FUNCTION(int, pthread_getname_np,
|
||||
(pthread_t th, char *buf, size_t len)) {
|
||||
auto *thread = reinterpret_cast<__llvm_libc::Thread *>(&th);
|
||||
cpp::MutableArrayRef<char> name_buf(buf, len);
|
||||
cpp::StringStream name_stream(name_buf);
|
||||
return thread->get_name(name_stream);
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,21 @@
|
|||
//===-- Implementation header for pthread_getname_np 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_GETNAME_NP_H
|
||||
#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_GETNAME_NP_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
int pthread_getname_np(pthread_t, char *, size_t);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_GETNAME_NP_H
|
|
@ -0,0 +1,28 @@
|
|||
//===-- Linux implementation of the pthread_setname_np 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_setname_np.h"
|
||||
|
||||
#include "src/__support/CPP/StringView.h"
|
||||
#include "src/__support/CPP/error.h"
|
||||
#include "src/__support/common.h"
|
||||
#include "src/__support/threads/thread.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
static_assert(sizeof(pthread_t) == sizeof(__llvm_libc::Thread),
|
||||
"Mismatch between pthread_t and internal Thread.");
|
||||
|
||||
LLVM_LIBC_FUNCTION(int, pthread_setname_np, (pthread_t th, const char *name)) {
|
||||
auto *thread = reinterpret_cast<__llvm_libc::Thread *>(&th);
|
||||
return thread->set_name(cpp::StringView(name));
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,20 @@
|
|||
//===-- Implementation header for pthread_setname_np 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_SETNAME_NP_H
|
||||
#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_SETNAME_NP_H
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
int pthread_setname_np(pthread_t, const char *name);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_SETNAME_NP_H
|
|
@ -53,3 +53,26 @@ add_integration_test(
|
|||
libc.src.pthread.pthread_join
|
||||
libc.src.pthread.pthread_self
|
||||
)
|
||||
|
||||
add_integration_test(
|
||||
pthread_name_test
|
||||
SUITE
|
||||
libc-pthread-integration-tests
|
||||
SRCS
|
||||
pthread_name_test.cpp
|
||||
LOADER
|
||||
libc.loader.linux.crt1
|
||||
DEPENDS
|
||||
libc.include.errno
|
||||
libc.include.pthread
|
||||
libc.src.errno.errno
|
||||
libc.src.pthread.pthread_create
|
||||
libc.src.pthread.pthread_getname_np
|
||||
libc.src.pthread.pthread_join
|
||||
libc.src.pthread.pthread_mutex_destroy
|
||||
libc.src.pthread.pthread_mutex_init
|
||||
libc.src.pthread.pthread_mutex_lock
|
||||
libc.src.pthread.pthread_mutex_unlock
|
||||
libc.src.pthread.pthread_self
|
||||
libc.src.pthread.pthread_setname_np
|
||||
)
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
//===-- Tests for pthread_equal -------------------------------------------===//
|
||||
//
|
||||
// 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/CPP/StringView.h"
|
||||
#include "src/pthread/pthread_create.h"
|
||||
#include "src/pthread/pthread_getname_np.h"
|
||||
#include "src/pthread/pthread_join.h"
|
||||
#include "src/pthread/pthread_mutex_destroy.h"
|
||||
#include "src/pthread/pthread_mutex_init.h"
|
||||
#include "src/pthread/pthread_mutex_lock.h"
|
||||
#include "src/pthread/pthread_mutex_unlock.h"
|
||||
#include "src/pthread/pthread_self.h"
|
||||
#include "src/pthread/pthread_setname_np.h"
|
||||
|
||||
#include "utils/IntegrationTest/test.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
|
||||
using StringView = __llvm_libc::cpp::StringView;
|
||||
|
||||
char child_thread_name_buffer[16];
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
static void *child_func(void *) {
|
||||
__llvm_libc::pthread_mutex_lock(&mutex);
|
||||
auto self = __llvm_libc::pthread_self();
|
||||
__llvm_libc::pthread_getname_np(self, child_thread_name_buffer, 16);
|
||||
__llvm_libc::pthread_mutex_unlock(&mutex);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TEST_MAIN() {
|
||||
// We init and lock the mutex so that we guarantee that the child thread is
|
||||
// waiting after startup.
|
||||
ASSERT_EQ(__llvm_libc::pthread_mutex_init(&mutex, nullptr), 0);
|
||||
ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&mutex), 0);
|
||||
|
||||
auto main_thread = __llvm_libc::pthread_self();
|
||||
const char MAIN_THREAD_NAME[] = "main_thread";
|
||||
char thread_name_buffer[16];
|
||||
ASSERT_EQ(__llvm_libc::pthread_setname_np(main_thread, MAIN_THREAD_NAME), 0);
|
||||
ASSERT_EQ(
|
||||
__llvm_libc::pthread_getname_np(main_thread, thread_name_buffer, 16), 0);
|
||||
ASSERT_TRUE(StringView(MAIN_THREAD_NAME)
|
||||
.equals(StringView(
|
||||
reinterpret_cast<const char *>(thread_name_buffer))));
|
||||
|
||||
pthread_t th;
|
||||
ASSERT_EQ(__llvm_libc::pthread_create(&th, nullptr, child_func, nullptr), 0);
|
||||
// This new thread should of course not be equal to the main thread.
|
||||
const char CHILD_THREAD_NAME[] = "child_thread";
|
||||
ASSERT_EQ(__llvm_libc::pthread_setname_np(th, CHILD_THREAD_NAME), 0);
|
||||
ASSERT_EQ(__llvm_libc::pthread_getname_np(th, thread_name_buffer, 16), 0);
|
||||
ASSERT_TRUE(StringView(CHILD_THREAD_NAME)
|
||||
.equals(StringView(
|
||||
reinterpret_cast<const char *>(thread_name_buffer))));
|
||||
|
||||
ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&mutex), 0);
|
||||
|
||||
void *retval;
|
||||
ASSERT_EQ(__llvm_libc::pthread_join(th, &retval), 0);
|
||||
ASSERT_EQ(uintptr_t(retval), uintptr_t(nullptr));
|
||||
// Make sure that the child thread saw it name correctly.
|
||||
ASSERT_TRUE(StringView(CHILD_THREAD_NAME)
|
||||
.equals(StringView(reinterpret_cast<const char *>(
|
||||
child_thread_name_buffer))));
|
||||
|
||||
__llvm_libc::pthread_mutex_destroy(&mutex);
|
||||
|
||||
ASSERT_EQ(__llvm_libc::pthread_setname_np(main_thread,
|
||||
"a really long name for a thread"),
|
||||
ERANGE);
|
||||
char smallbuf[1];
|
||||
ASSERT_EQ(__llvm_libc::pthread_getname_np(main_thread, smallbuf, 1), ERANGE);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue