| 95 | namespace { |
| 96 | |
| 97 | int32_t GetThreadPoolThreadLimit(Env* env) { |
| 98 | // Maximize this process' running thread limit first, if possible. |
| 99 | static std::once_flag once; |
| 100 | std::call_once(once, [&]() { |
| 101 | env->IncreaseResourceLimit(Env::ResourceLimitType::RUNNING_THREADS_PER_EUID); |
| 102 | }); |
| 103 | |
| 104 | uint64_t rlimit = env->GetResourceLimit(Env::ResourceLimitType::RUNNING_THREADS_PER_EUID); |
| 105 | // See server_thread_pool_max_thread_count. |
| 106 | if (FLAGS_server_thread_pool_max_thread_count == -1) { |
| 107 | // Use both pid_max and threads-max as possible upper bounds. |
| 108 | faststring buf; |
| 109 | uint64_t buf_val; |
| 110 | for (const auto& proc_file : { "/proc/sys/kernel/pid_max", |
| 111 | "/proc/sys/kernel/threads-max" }) { |
| 112 | if (ReadFileToString(env, proc_file, &buf).ok() && |
| 113 | safe_strtou64(buf.ToString(), &buf_val)) { |
| 114 | rlimit = std::min(rlimit, buf_val); |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | // Callers of this function expect a signed 32-bit integer, so we need to |
| 119 | // further cap the limit just in case it's too large. |
| 120 | rlimit = std::min<uint64_t>(rlimit, std::numeric_limits<int32_t>::max()); |
| 121 | |
| 122 | // Take only 10% of the calculated limit; we don't want to hog the system. |
| 123 | return static_cast<int32_t>(rlimit) / 10; |
| 124 | } |
| 125 | LOG_IF(FATAL, FLAGS_server_thread_pool_max_thread_count > rlimit) << |
| 126 | Substitute( |
| 127 | "Configured server-wide thread pool running thread limit " |
| 128 | "(server_thread_pool_max_thread_count) $0 exceeds euid running " |
| 129 | "thread limit (ulimit) $1", |
| 130 | FLAGS_server_thread_pool_max_thread_count, rlimit); |
| 131 | return FLAGS_server_thread_pool_max_thread_count; |
| 132 | } |
| 133 | |
| 134 | } // anonymous namespace |
| 135 |
no test coverage detected