/src/gdal/port/cplgetcurrentthreadcount.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: GDAL |
4 | | * Purpose: Return number of current threads in current process |
5 | | * Author: Even Rouault <even dot rouault at spatialys.com> |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2025, Even Rouault <even dot rouault at spatialys.com> |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "cpl_multiproc.h" |
14 | | |
15 | | /************************************************************************/ |
16 | | /* CPLGetCurrentThreadCount() */ |
17 | | /************************************************************************/ |
18 | | |
19 | | /** |
20 | | * \fn CPLGetCurrentThreadCount() |
21 | | * |
22 | | * Return the current number of threads of the current process. |
23 | | * |
24 | | * Implemented for Linux, Windows, FreeBSD, netBSD and MACOSX. |
25 | | * |
26 | | * Return 0 on other platforms or in case of error. |
27 | | * |
28 | | * @since 3.12 |
29 | | */ |
30 | | |
31 | | #ifdef __linux |
32 | | |
33 | | #include "cpl_string.h" |
34 | | |
35 | | #include <cstdio> |
36 | | #include <string> |
37 | | |
38 | | int CPLGetCurrentThreadCount() |
39 | 0 | { |
40 | 0 | int nRet = 0; |
41 | 0 | FILE *fp = fopen("/proc/self/stat", "rb"); |
42 | 0 | if (fp) |
43 | 0 | { |
44 | 0 | std::string osBuffer; |
45 | 0 | osBuffer.resize(4096); |
46 | 0 | const size_t nRead = fread(osBuffer.data(), 1, osBuffer.size(), fp); |
47 | 0 | if (nRead > 0 && nRead < osBuffer.size()) |
48 | 0 | { |
49 | 0 | osBuffer.resize(nRead); |
50 | 0 | const auto nPos = osBuffer.find(')'); |
51 | 0 | if (nPos != std::string::npos) |
52 | 0 | { |
53 | 0 | const CPLStringList aosTokens( |
54 | 0 | CSLTokenizeString2(osBuffer.c_str() + nPos + 1, " ", 0)); |
55 | 0 | if (aosTokens.size() >= 18) |
56 | 0 | { |
57 | 0 | nRet = atoi(aosTokens[17]); |
58 | 0 | } |
59 | 0 | } |
60 | 0 | } |
61 | 0 | fclose(fp); |
62 | 0 | } |
63 | 0 | return nRet; |
64 | 0 | } |
65 | | |
66 | | #elif defined(_WIN32) |
67 | | |
68 | | #include <windows.h> |
69 | | #include <tlhelp32.h> |
70 | | |
71 | | int CPLGetCurrentThreadCount() |
72 | | { |
73 | | int nRet = 0; |
74 | | |
75 | | const DWORD pid = GetCurrentProcessId(); |
76 | | HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); |
77 | | if (hThreadSnap != INVALID_HANDLE_VALUE) |
78 | | { |
79 | | THREADENTRY32 te32; |
80 | | te32.dwSize = static_cast<int>(sizeof(THREADENTRY32)); |
81 | | |
82 | | if (Thread32First(hThreadSnap, &te32)) |
83 | | { |
84 | | do |
85 | | { |
86 | | if (te32.th32OwnerProcessID == pid) |
87 | | { |
88 | | nRet++; |
89 | | } |
90 | | } while (Thread32Next(hThreadSnap, &te32)); |
91 | | } |
92 | | |
93 | | CloseHandle(hThreadSnap); |
94 | | } |
95 | | return nRet; |
96 | | } |
97 | | |
98 | | #elif defined(__FreeBSD__) |
99 | | |
100 | | #include <sys/types.h> |
101 | | #include <sys/user.h> // must be after sys/types.h |
102 | | #include <sys/sysctl.h> |
103 | | #include <unistd.h> |
104 | | |
105 | | int CPLGetCurrentThreadCount() |
106 | | { |
107 | | const pid_t pid = getpid(); |
108 | | int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, static_cast<int>(pid)}; |
109 | | |
110 | | struct kinfo_proc kp; |
111 | | size_t len = sizeof(kp); |
112 | | |
113 | | if (sysctl(mib, 4, &kp, &len, nullptr, 0) == -1) |
114 | | { |
115 | | return 0; |
116 | | } |
117 | | |
118 | | return kp.ki_numthreads; |
119 | | } |
120 | | |
121 | | #elif defined(__NetBSD__) |
122 | | |
123 | | #include <sys/types.h> |
124 | | #include <sys/sysctl.h> |
125 | | #include <sys/lwp.h> |
126 | | #include <unistd.h> |
127 | | |
128 | | int CPLGetCurrentThreadCount() |
129 | | { |
130 | | const pid_t pid = getpid(); |
131 | | int mib[5] = {CTL_KERN, KERN_PROC, static_cast<int>(pid), |
132 | | static_cast<int>(sizeof(struct kinfo_lwp)), 0}; |
133 | | |
134 | | size_t len = 0; |
135 | | if (sysctl(mib, 5, nullptr, &len, nullptr, 0) == -1) |
136 | | { |
137 | | return 0; |
138 | | } |
139 | | |
140 | | return static_cast<int>(len / sizeof(struct kinfo_lwp)); |
141 | | } |
142 | | |
143 | | #elif defined(__APPLE__) && defined(__MACH__) |
144 | | |
145 | | #include <mach/mach.h> |
146 | | |
147 | | int CPLGetCurrentThreadCount() |
148 | | { |
149 | | const mach_port_t task = mach_task_self(); |
150 | | |
151 | | thread_act_array_t thread_list; |
152 | | mach_msg_type_number_t thread_count = 0; |
153 | | |
154 | | kern_return_t kr = task_threads(task, &thread_list, &thread_count); |
155 | | if (kr == KERN_SUCCESS) |
156 | | { |
157 | | for (mach_msg_type_number_t i = 0; i < thread_count; i++) |
158 | | { |
159 | | mach_port_deallocate(task, thread_list[i]); |
160 | | } |
161 | | |
162 | | vm_deallocate(task, reinterpret_cast<vm_address_t>(thread_list), |
163 | | thread_count * sizeof(thread_t)); |
164 | | } |
165 | | |
166 | | return static_cast<int>(thread_count); |
167 | | } |
168 | | |
169 | | #else |
170 | | |
171 | | #include "cpl_error.h" |
172 | | |
173 | | int CPLGetCurrentThreadCount() |
174 | | { |
175 | | CPLDebugOnce( |
176 | | "CPL", |
177 | | "CPLGetCurrentThreadCount() unimplemented on this operating system"); |
178 | | return 0; |
179 | | } |
180 | | |
181 | | #endif |