aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/lib/Support/Unix
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/Support/Unix')
-rw-r--r--contrib/llvm/lib/Support/Unix/Path.inc273
-rw-r--r--contrib/llvm/lib/Support/Unix/Signals.inc18
-rw-r--r--contrib/llvm/lib/Support/Unix/Threading.inc215
3 files changed, 476 insertions, 30 deletions
diff --git a/contrib/llvm/lib/Support/Unix/Path.inc b/contrib/llvm/lib/Support/Unix/Path.inc
index e0b11aaff007..93f8982196b3 100644
--- a/contrib/llvm/lib/Support/Unix/Path.inc
+++ b/contrib/llvm/lib/Support/Unix/Path.inc
@@ -48,6 +48,8 @@
# endif
#endif
+#include <pwd.h>
+
#ifdef __APPLE__
#include <mach-o/dyld.h>
#include <sys/attr.h>
@@ -65,23 +67,41 @@
#endif
#include <sys/types.h>
-#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__)
+#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && \
+ !defined(__linux__)
#include <sys/statvfs.h>
#define STATVFS statvfs
+#define FSTATVFS fstatvfs
#define STATVFS_F_FRSIZE(vfs) vfs.f_frsize
#else
-#ifdef __OpenBSD__
+#if defined(__OpenBSD__) || defined(__FreeBSD__)
#include <sys/param.h>
#include <sys/mount.h>
-#elif defined(__ANDROID__)
+#elif defined(__linux__)
+#if defined(HAVE_LINUX_MAGIC_H)
+#include <linux/magic.h>
+#else
+#if defined(HAVE_LINUX_NFS_FS_H)
+#include <linux/nfs_fs.h>
+#endif
+#if defined(HAVE_LINUX_SMB_H)
+#include <linux/smb.h>
+#endif
+#endif
#include <sys/vfs.h>
#else
#include <sys/mount.h>
#endif
#define STATVFS statfs
+#define FSTATVFS fstatfs
#define STATVFS_F_FRSIZE(vfs) static_cast<uint64_t>(vfs.f_bsize)
#endif
+#if defined(__NetBSD__)
+#define STATVFS_F_FLAG(vfs) (vfs).f_flag
+#else
+#define STATVFS_F_FLAG(vfs) (vfs).f_flags
+#endif
using namespace llvm;
@@ -180,7 +200,7 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
if (getprogpath(exe_path, argv0))
return exe_path;
}
-#elif defined(HAVE_DLFCN_H)
+#elif defined(HAVE_DLFCN_H) && defined(HAVE_DLADDR)
// Use dladdr to get executable path if available.
Dl_info DLInfo;
int err = dladdr(MainAddr, &DLInfo);
@@ -210,6 +230,10 @@ UniqueID file_status::getUniqueID() const {
return UniqueID(fs_st_dev, fs_st_ino);
}
+uint32_t file_status::getLinkCount() const {
+ return fs_st_nlinks;
+}
+
ErrorOr<space_info> disk_space(const Twine &Path) {
struct STATVFS Vfs;
if (::STATVFS(Path.str().c_str(), &Vfs))
@@ -257,6 +281,16 @@ std::error_code current_path(SmallVectorImpl<char> &result) {
return std::error_code();
}
+std::error_code set_current_path(const Twine &path) {
+ SmallString<128> path_storage;
+ StringRef p = path.toNullTerminatedStringRef(path_storage);
+
+ if (::chdir(p.begin()) == -1)
+ return std::error_code(errno, std::generic_category());
+
+ return std::error_code();
+}
+
std::error_code create_directory(const Twine &path, bool IgnoreExisting,
perms Perms) {
SmallString<128> path_storage;
@@ -325,6 +359,51 @@ std::error_code remove(const Twine &path, bool IgnoreNonExisting) {
return std::error_code();
}
+static bool is_local_impl(struct STATVFS &Vfs) {
+#if defined(__linux__)
+#ifndef NFS_SUPER_MAGIC
+#define NFS_SUPER_MAGIC 0x6969
+#endif
+#ifndef SMB_SUPER_MAGIC
+#define SMB_SUPER_MAGIC 0x517B
+#endif
+#ifndef CIFS_MAGIC_NUMBER
+#define CIFS_MAGIC_NUMBER 0xFF534D42
+#endif
+ switch ((uint32_t)Vfs.f_type) {
+ case NFS_SUPER_MAGIC:
+ case SMB_SUPER_MAGIC:
+ case CIFS_MAGIC_NUMBER:
+ return false;
+ default:
+ return true;
+ }
+#elif defined(__CYGWIN__)
+ // Cygwin doesn't expose this information; would need to use Win32 API.
+ return false;
+#else
+ return !!(STATVFS_F_FLAG(Vfs) & MNT_LOCAL);
+#endif
+}
+
+std::error_code is_local(const Twine &Path, bool &Result) {
+ struct STATVFS Vfs;
+ if (::STATVFS(Path.str().c_str(), &Vfs))
+ return std::error_code(errno, std::generic_category());
+
+ Result = is_local_impl(Vfs);
+ return std::error_code();
+}
+
+std::error_code is_local(int FD, bool &Result) {
+ struct STATVFS Vfs;
+ if (::FSTATVFS(FD, &Vfs))
+ return std::error_code(errno, std::generic_category());
+
+ Result = is_local_impl(Vfs);
+ return std::error_code();
+}
+
std::error_code rename(const Twine &from, const Twine &to) {
// Get arguments.
SmallString<128> from_storage;
@@ -405,6 +484,46 @@ std::error_code equivalent(const Twine &A, const Twine &B, bool &result) {
return std::error_code();
}
+static void expandTildeExpr(SmallVectorImpl<char> &Path) {
+ StringRef PathStr(Path.begin(), Path.size());
+ if (PathStr.empty() || !PathStr.startswith("~"))
+ return;
+
+ PathStr = PathStr.drop_front();
+ StringRef Expr =
+ PathStr.take_until([](char c) { return path::is_separator(c); });
+ StringRef Remainder = PathStr.substr(Expr.size() + 1);
+ SmallString<128> Storage;
+ if (Expr.empty()) {
+ // This is just ~/..., resolve it to the current user's home dir.
+ if (!path::home_directory(Storage)) {
+ // For some reason we couldn't get the home directory. Just exit.
+ return;
+ }
+
+ // Overwrite the first character and insert the rest.
+ Path[0] = Storage[0];
+ Path.insert(Path.begin() + 1, Storage.begin() + 1, Storage.end());
+ return;
+ }
+
+ // This is a string of the form ~username/, look up this user's entry in the
+ // password database.
+ struct passwd *Entry = nullptr;
+ std::string User = Expr.str();
+ Entry = ::getpwnam(User.c_str());
+
+ if (!Entry) {
+ // Unable to look up the entry, just return back the original path.
+ return;
+ }
+
+ Storage = Remainder;
+ Path.clear();
+ Path.append(Entry->pw_dir, Entry->pw_dir + strlen(Entry->pw_dir));
+ llvm::sys::path::append(Path, Storage);
+}
+
static std::error_code fillStatus(int StatRet, const struct stat &Status,
file_status &Result) {
if (StatRet != 0) {
@@ -430,22 +549,23 @@ static std::error_code fillStatus(int StatRet, const struct stat &Status,
Type = file_type::fifo_file;
else if (S_ISSOCK(Status.st_mode))
Type = file_type::socket_file;
+ else if (S_ISLNK(Status.st_mode))
+ Type = file_type::symlink_file;
- perms Perms = static_cast<perms>(Status.st_mode);
- Result =
- file_status(Type, Perms, Status.st_dev, Status.st_ino, Status.st_atime,
- Status.st_mtime, Status.st_uid, Status.st_gid,
- Status.st_size);
+ perms Perms = static_cast<perms>(Status.st_mode) & all_perms;
+ Result = file_status(Type, Perms, Status.st_dev, Status.st_nlink,
+ Status.st_ino, Status.st_atime, Status.st_mtime,
+ Status.st_uid, Status.st_gid, Status.st_size);
return std::error_code();
}
-std::error_code status(const Twine &Path, file_status &Result) {
+std::error_code status(const Twine &Path, file_status &Result, bool Follow) {
SmallString<128> PathStorage;
StringRef P = Path.toNullTerminatedStringRef(PathStorage);
struct stat Status;
- int StatRet = ::stat(P.begin(), &Status);
+ int StatRet = (Follow ? ::stat : ::lstat)(P.begin(), &Status);
return fillStatus(StatRet, Status, Result);
}
@@ -455,6 +575,15 @@ std::error_code status(int FD, file_status &Result) {
return fillStatus(StatRet, Status, Result);
}
+std::error_code setPermissions(const Twine &Path, perms Permissions) {
+ SmallString<128> PathStorage;
+ StringRef P = Path.toNullTerminatedStringRef(PathStorage);
+
+ if (::chmod(P.begin(), Permissions))
+ return std::error_code(errno, std::generic_category());
+ return std::error_code();
+}
+
std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) {
#if defined(HAVE_FUTIMENS)
timespec Times[2];
@@ -481,6 +610,26 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset,
int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE;
int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE);
+#if defined(__APPLE__)
+ //----------------------------------------------------------------------
+ // Newer versions of MacOSX have a flag that will allow us to read from
+ // binaries whose code signature is invalid without crashing by using
+ // the MAP_RESILIENT_CODESIGN flag. Also if a file from removable media
+ // is mapped we can avoid crashing and return zeroes to any pages we try
+ // to read if the media becomes unavailable by using the
+ // MAP_RESILIENT_MEDIA flag. These flags are only usable when mapping
+ // with PROT_READ, so take care not to specify them otherwise.
+ //----------------------------------------------------------------------
+ if (Mode == readonly) {
+#if defined(MAP_RESILIENT_CODESIGN)
+ flags |= MAP_RESILIENT_CODESIGN;
+#endif
+#if defined(MAP_RESILIENT_MEDIA)
+ flags |= MAP_RESILIENT_MEDIA;
+#endif
+ }
+#endif // #if defined (__APPLE__)
+
Mapping = ::mmap(nullptr, Size, prot, flags, FD, Offset);
if (Mapping == MAP_FAILED)
return std::error_code(errno, std::generic_category());
@@ -526,7 +675,8 @@ int mapped_file_region::alignment() {
}
std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
- StringRef path){
+ StringRef path,
+ bool follow_symlinks) {
SmallString<128> path_null(path);
DIR *directory = ::opendir(path_null.c_str());
if (!directory)
@@ -535,7 +685,7 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
it.IterationHandle = reinterpret_cast<intptr_t>(directory);
// Add something for replace_filename to replace.
path::append(path_null, ".");
- it.CurrentEntry = directory_entry(path_null.str());
+ it.CurrentEntry = directory_entry(path_null.str(), follow_symlinks);
return directory_iterator_increment(it);
}
@@ -577,10 +727,19 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,
SmallVectorImpl<char> *RealPath) {
SmallString<128> Storage;
StringRef P = Name.toNullTerminatedStringRef(Storage);
- while ((ResultFD = open(P.begin(), O_RDONLY)) < 0) {
+ int OpenFlags = O_RDONLY;
+#ifdef O_CLOEXEC
+ OpenFlags |= O_CLOEXEC;
+#endif
+ while ((ResultFD = open(P.begin(), OpenFlags)) < 0) {
if (errno != EINTR)
return std::error_code(errno, std::generic_category());
}
+#ifndef O_CLOEXEC
+ int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC);
+ (void)r;
+ assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed");
+#endif
// Attempt to get the real name of the file, if the user asked
if(!RealPath)
return std::error_code();
@@ -616,6 +775,10 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
int OpenFlags = O_CREAT;
+#ifdef O_CLOEXEC
+ OpenFlags |= O_CLOEXEC;
+#endif
+
if (Flags & F_RW)
OpenFlags |= O_RDWR;
else
@@ -635,6 +798,11 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
if (errno != EINTR)
return std::error_code(errno, std::generic_category());
}
+#ifndef O_CLOEXEC
+ int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC);
+ (void)r;
+ assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed");
+#endif
return std::error_code();
}
@@ -685,18 +853,85 @@ std::error_code getPathFromOpenFD(int FD, SmallVectorImpl<char> &ResultPath) {
return std::error_code();
}
+template <typename T>
+static std::error_code remove_directories_impl(const T &Entry,
+ bool IgnoreErrors) {
+ std::error_code EC;
+ directory_iterator Begin(Entry, EC, false);
+ directory_iterator End;
+ while (Begin != End) {
+ auto &Item = *Begin;
+ file_status st;
+ EC = Item.status(st);
+ if (EC && !IgnoreErrors)
+ return EC;
+
+ if (is_directory(st)) {
+ EC = remove_directories_impl(Item, IgnoreErrors);
+ if (EC && !IgnoreErrors)
+ return EC;
+ }
+
+ EC = fs::remove(Item.path(), true);
+ if (EC && !IgnoreErrors)
+ return EC;
+
+ Begin.increment(EC);
+ if (EC && !IgnoreErrors)
+ return EC;
+ }
+ return std::error_code();
+}
+
+std::error_code remove_directories(const Twine &path, bool IgnoreErrors) {
+ auto EC = remove_directories_impl(path, IgnoreErrors);
+ if (EC && !IgnoreErrors)
+ return EC;
+ EC = fs::remove(path, true);
+ if (EC && !IgnoreErrors)
+ return EC;
+ return std::error_code();
+}
+
+std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest,
+ bool expand_tilde) {
+ dest.clear();
+ if (path.isTriviallyEmpty())
+ return std::error_code();
+
+ if (expand_tilde) {
+ SmallString<128> Storage;
+ path.toVector(Storage);
+ expandTildeExpr(Storage);
+ return real_path(Storage, dest, false);
+ }
+
+ int fd;
+ std::error_code EC = openFileForRead(path, fd, &dest);
+
+ if (EC)
+ return EC;
+ ::close(fd);
+ return std::error_code();
+}
+
} // end namespace fs
namespace path {
bool home_directory(SmallVectorImpl<char> &result) {
- if (char *RequestedDir = getenv("HOME")) {
- result.clear();
- result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
- return true;
+ char *RequestedDir = getenv("HOME");
+ if (!RequestedDir) {
+ struct passwd *pw = getpwuid(getuid());
+ if (pw && pw->pw_dir)
+ RequestedDir = pw->pw_dir;
}
+ if (!RequestedDir)
+ return false;
- return false;
+ result.clear();
+ result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
+ return true;
}
static bool getDarwinConfDir(bool TempDir, SmallVectorImpl<char> &Result) {
diff --git a/contrib/llvm/lib/Support/Unix/Signals.inc b/contrib/llvm/lib/Support/Unix/Signals.inc
index 9752b70644c6..88ad21e9806e 100644
--- a/contrib/llvm/lib/Support/Unix/Signals.inc
+++ b/contrib/llvm/lib/Support/Unix/Signals.inc
@@ -25,8 +25,8 @@
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <string>
-#if HAVE_EXECINFO_H
-# include <execinfo.h> // For backtrace().
+#ifdef HAVE_BACKTRACE
+# include BACKTRACE_HEADER // For backtrace().
#endif
#if HAVE_SIGNAL_H
#include <signal.h>
@@ -59,7 +59,7 @@ using namespace llvm;
static RETSIGTYPE SignalHandler(int Sig); // defined below.
-static ManagedStatic<SmartMutex<true> > SignalsMutex;
+static ManagedStatic<sys::SmartMutex<true> > SignalsMutex;
/// InterruptFunction - The function to call if ctrl-c is pressed.
static void (*InterruptFunction)() = nullptr;
@@ -149,11 +149,7 @@ static void CreateSigAltStack() {}
#endif
static void RegisterHandlers() {
- // We need to dereference the signals mutex during handler registration so
- // that we force its construction. This is to prevent the first use being
- // during handling an actual signal because you can't safely call new in a
- // signal handler.
- *SignalsMutex;
+ sys::SmartScopedLock<true> Guard(*SignalsMutex);
// If the handlers are already registered, we're done.
if (NumRegisteredSignals != 0) return;
@@ -223,7 +219,7 @@ static RETSIGTYPE SignalHandler(int Sig) {
sigprocmask(SIG_UNBLOCK, &SigMask, nullptr);
{
- unique_lock<SmartMutex<true>> Guard(*SignalsMutex);
+ unique_lock<sys::SmartMutex<true>> Guard(*SignalsMutex);
RemoveFilesToRemove();
if (std::find(std::begin(IntSigs), std::end(IntSigs), Sig)
@@ -412,7 +408,7 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS) {
if (printSymbolizedStackTrace(Argv0, StackTrace, depth, OS))
return;
-#if HAVE_DLFCN_H && __GNUG__ && !defined(__CYGWIN__)
+#if HAVE_DLFCN_H && HAVE_DLADDR
int width = 0;
for (int i = 0; i < depth; ++i) {
Dl_info dlinfo;
@@ -462,7 +458,7 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS) {
}
static void PrintStackTraceSignalHandler(void *) {
- PrintStackTrace(llvm::errs());
+ sys::PrintStackTrace(llvm::errs());
}
void llvm::sys::DisableSystemDialogsOnCrash() {}
diff --git a/contrib/llvm/lib/Support/Unix/Threading.inc b/contrib/llvm/lib/Support/Unix/Threading.inc
new file mode 100644
index 000000000000..407b194e1b6a
--- /dev/null
+++ b/contrib/llvm/lib/Support/Unix/Threading.inc
@@ -0,0 +1,215 @@
+//===- Unix/Threading.inc - Unix Threading Implementation ----- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides the Unix specific implementation of Threading functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h"
+
+#if defined(__APPLE__)
+#include <mach/mach_init.h>
+#include <mach/mach_port.h>
+#endif
+
+#include <pthread.h>
+
+#if defined(__FreeBSD__)
+#include <pthread_np.h> // For pthread_getthreadid_np()
+#endif
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <errno.h>
+#include <unistd.h>
+#endif
+
+#if defined(__NetBSD__)
+#include <lwp.h> // For _lwp_self()
+#endif
+
+#if defined(__linux__)
+#include <unistd.h> // For syscall()
+#include <sys/syscall.h> // For syscall codes
+#endif
+
+namespace {
+ struct ThreadInfo {
+ void(*UserFn)(void *);
+ void *UserData;
+ };
+}
+
+static void *ExecuteOnThread_Dispatch(void *Arg) {
+ ThreadInfo *TI = reinterpret_cast<ThreadInfo*>(Arg);
+ TI->UserFn(TI->UserData);
+ return nullptr;
+}
+
+void llvm::llvm_execute_on_thread(void(*Fn)(void*), void *UserData,
+ unsigned RequestedStackSize) {
+ ThreadInfo Info = { Fn, UserData };
+ pthread_attr_t Attr;
+ pthread_t Thread;
+
+ // Construct the attributes object.
+ if (::pthread_attr_init(&Attr) != 0)
+ return;
+
+ // Set the requested stack size, if given.
+ if (RequestedStackSize != 0) {
+ if (::pthread_attr_setstacksize(&Attr, RequestedStackSize) != 0)
+ goto error;
+ }
+
+ // Construct and execute the thread.
+ if (::pthread_create(&Thread, &Attr, ExecuteOnThread_Dispatch, &Info) != 0)
+ goto error;
+
+ // Wait for the thread and clean up.
+ ::pthread_join(Thread, nullptr);
+
+error:
+ ::pthread_attr_destroy(&Attr);
+}
+
+
+uint64_t llvm::get_threadid() {
+#if defined(__APPLE__)
+ // Calling "mach_thread_self()" bumps the reference count on the thread
+ // port, so we need to deallocate it. mach_task_self() doesn't bump the ref
+ // count.
+ thread_port_t Self = mach_thread_self();
+ mach_port_deallocate(mach_task_self(), Self);
+ return Self;
+#elif defined(__FreeBSD__)
+ return uint64_t(pthread_getthreadid_np());
+#elif defined(__NetBSD__)
+ return uint64_t(_lwp_self());
+#elif defined(__ANDROID__)
+ return uint64_t(gettid());
+#elif defined(__linux__)
+ return uint64_t(syscall(SYS_gettid));
+#elif defined(LLVM_ON_WIN32)
+ return uint64_t(::GetCurrentThreadId());
+#else
+ return uint64_t(pthread_self());
+#endif
+}
+
+
+static constexpr uint32_t get_max_thread_name_length_impl() {
+#if defined(__NetBSD__)
+ return PTHREAD_MAX_NAMELEN_NP;
+#elif defined(__APPLE__)
+ return 64;
+#elif defined(__linux__)
+#if HAVE_PTHREAD_SETNAME_NP
+ return 16;
+#else
+ return 0;
+#endif
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+ return 16;
+#else
+ return 0;
+#endif
+}
+
+uint32_t llvm::get_max_thread_name_length() {
+ return get_max_thread_name_length_impl();
+}
+
+void llvm::set_thread_name(const Twine &Name) {
+ // Make sure the input is null terminated.
+ SmallString<64> Storage;
+ StringRef NameStr = Name.toNullTerminatedStringRef(Storage);
+
+ // Truncate from the beginning, not the end, if the specified name is too
+ // long. For one, this ensures that the resulting string is still null
+ // terminated, but additionally the end of a long thread name will usually
+ // be more unique than the beginning, since a common pattern is for similar
+ // threads to share a common prefix.
+ if (get_max_thread_name_length() > 0)
+ NameStr = NameStr.take_back(get_max_thread_name_length());
+ (void)NameStr;
+#if defined(__linux__)
+#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__)
+#if HAVE_PTHREAD_SETNAME_NP
+ ::pthread_setname_np(::pthread_self(), NameStr.data());
+#endif
+#endif
+#elif defined(__FreeBSD__)
+ ::pthread_set_name_np(::pthread_self(), NameStr.data());
+#elif defined(__NetBSD__)
+ ::pthread_setname_np(::pthread_self(), "%s",
+ const_cast<char *>(NameStr.data()));
+#elif defined(__APPLE__)
+ ::pthread_setname_np(NameStr.data());
+#endif
+}
+
+void llvm::get_thread_name(SmallVectorImpl<char> &Name) {
+ Name.clear();
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+ int pid = ::getpid();
+ uint64_t tid = get_threadid();
+
+ struct kinfo_proc *kp = nullptr, *nkp;
+ size_t len = 0;
+ int error;
+ int ctl[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD,
+ (int)pid };
+
+ while (1) {
+ error = sysctl(ctl, 4, kp, &len, nullptr, 0);
+ if (kp == nullptr || (error != 0 && errno == ENOMEM)) {
+ // Add extra space in case threads are added before next call.
+ len += sizeof(*kp) + len / 10;
+ nkp = (struct kinfo_proc *)realloc(kp, len);
+ if (nkp == nullptr) {
+ free(kp);
+ return;
+ }
+ kp = nkp;
+ continue;
+ }
+ if (error != 0)
+ len = 0;
+ break;
+ }
+
+ for (size_t i = 0; i < len / sizeof(*kp); i++) {
+ if (kp[i].ki_tid == (lwpid_t)tid) {
+ Name.append(kp[i].ki_tdname, kp[i].ki_tdname + strlen(kp[i].ki_tdname));
+ break;
+ }
+ }
+ free(kp);
+ return;
+#elif defined(__NetBSD__)
+ constexpr uint32_t len = get_max_thread_name_length_impl();
+ char buf[len];
+ ::pthread_getname_np(::pthread_self(), buf, len);
+
+ Name.append(buf, buf + strlen(buf));
+#elif defined(__linux__)
+#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__)
+#if HAVE_PTHREAD_GETNAME_NP
+ constexpr uint32_t len = get_max_thread_name_length_impl();
+ char Buffer[len];
+ if (0 == ::pthread_getname_np(::pthread_self(), Buffer, len))
+ Name.append(Buffer, Buffer + strlen(Buffer));
+#endif
+#endif
+#endif
+}