1//===-- llvm/Support/Threading.cpp- Control multithreading mode --*- C++ -*-==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines helper functions for running LLVM in a multi-threaded
10// environment.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/Support/Threading.h"
15#include "llvm/ADT/Optional.h"
16#include "llvm/Config/config.h"
17#include "llvm/Support/Host.h"
18
19#include <cassert>
20#include <errno.h>
21#include <stdlib.h>
22#include <string.h>
23
24using namespace llvm;
25
26//===----------------------------------------------------------------------===//
27//=== WARNING: Implementation here must contain only TRULY operating system
28//===          independent code.
29//===----------------------------------------------------------------------===//
30
31bool llvm::llvm_is_multithreaded() {
32#if LLVM_ENABLE_THREADS != 0
33  return true;
34#else
35  return false;
36#endif
37}
38
39#if LLVM_ENABLE_THREADS == 0 ||                                                \
40    (!defined(_WIN32) && !defined(HAVE_PTHREAD_H))
41// Support for non-Win32, non-pthread implementation.
42void llvm::llvm_execute_on_thread(void (*Fn)(void *), void *UserData,
43                                  llvm::Optional<unsigned> StackSizeInBytes) {
44  (void)StackSizeInBytes;
45  Fn(UserData);
46}
47
48uint64_t llvm::get_threadid() { return 0; }
49
50uint32_t llvm::get_max_thread_name_length() { return 0; }
51
52void llvm::set_thread_name(const Twine &Name) {}
53
54void llvm::get_thread_name(SmallVectorImpl<char> &Name) { Name.clear(); }
55
56llvm::BitVector llvm::get_thread_affinity_mask() { return {}; }
57
58unsigned llvm::ThreadPoolStrategy::compute_thread_count() const {
59  // When threads are disabled, ensure clients will loop at least once.
60  return 1;
61}
62
63#if LLVM_ENABLE_THREADS == 0
64void llvm::llvm_execute_on_thread_async(
65    llvm::unique_function<void()> Func,
66    llvm::Optional<unsigned> StackSizeInBytes) {
67  (void)Func;
68  (void)StackSizeInBytes;
69  report_fatal_error("Spawning a detached thread doesn't make sense with no "
70                     "threading support");
71}
72#else
73// Support for non-Win32, non-pthread implementation.
74void llvm::llvm_execute_on_thread_async(
75    llvm::unique_function<void()> Func,
76    llvm::Optional<unsigned> StackSizeInBytes) {
77  (void)StackSizeInBytes;
78  std::thread(std::move(Func)).detach();
79}
80#endif
81
82#else
83
84int computeHostNumHardwareThreads();
85
86unsigned llvm::ThreadPoolStrategy::compute_thread_count() const {
87  int MaxThreadCount = UseHyperThreads ? computeHostNumHardwareThreads()
88                                       : sys::getHostNumPhysicalCores();
89  if (MaxThreadCount <= 0)
90    MaxThreadCount = 1;
91  if (ThreadsRequested == 0)
92    return MaxThreadCount;
93  if (!Limit)
94    return ThreadsRequested;
95  return std::min((unsigned)MaxThreadCount, ThreadsRequested);
96}
97
98namespace {
99struct SyncThreadInfo {
100  void (*UserFn)(void *);
101  void *UserData;
102};
103
104using AsyncThreadInfo = llvm::unique_function<void()>;
105
106enum class JoiningPolicy { Join, Detach };
107} // namespace
108
109// Include the platform-specific parts of this class.
110#ifdef LLVM_ON_UNIX
111#include "Unix/Threading.inc"
112#endif
113#ifdef _WIN32
114#include "Windows/Threading.inc"
115#endif
116
117void llvm::llvm_execute_on_thread(void (*Fn)(void *), void *UserData,
118                                  llvm::Optional<unsigned> StackSizeInBytes) {
119
120  SyncThreadInfo Info = {Fn, UserData};
121  llvm_execute_on_thread_impl(threadFuncSync, &Info, StackSizeInBytes,
122                              JoiningPolicy::Join);
123}
124
125void llvm::llvm_execute_on_thread_async(
126    llvm::unique_function<void()> Func,
127    llvm::Optional<unsigned> StackSizeInBytes) {
128  llvm_execute_on_thread_impl(&threadFuncAsync,
129                              new AsyncThreadInfo(std::move(Func)),
130                              StackSizeInBytes, JoiningPolicy::Detach);
131}
132
133#endif
134
135Optional<ThreadPoolStrategy>
136llvm::get_threadpool_strategy(StringRef Num, ThreadPoolStrategy Default) {
137  if (Num == "all")
138    return llvm::hardware_concurrency();
139  if (Num.empty())
140    return Default;
141  unsigned V;
142  if (Num.getAsInteger(10, V))
143    return None; // malformed 'Num' value
144  if (V == 0)
145    return Default;
146
147  // Do not take the Default into account. This effectively disables
148  // heavyweight_hardware_concurrency() if the user asks for any number of
149  // threads on the cmd-line.
150  ThreadPoolStrategy S = llvm::hardware_concurrency();
151  S.ThreadsRequested = V;
152  return S;
153}
154