Line data Source code
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 6 : int CPLGetCurrentThreadCount()
39 : {
40 6 : int nRet = 0;
41 6 : FILE *fp = fopen("/proc/self/stat", "rb");
42 6 : if (fp)
43 : {
44 12 : std::string osBuffer;
45 6 : osBuffer.resize(4096);
46 6 : const size_t nRead = fread(osBuffer.data(), 1, osBuffer.size(), fp);
47 6 : if (nRead > 0 && nRead < osBuffer.size())
48 : {
49 6 : osBuffer.resize(nRead);
50 6 : const auto nPos = osBuffer.find(')');
51 6 : if (nPos != std::string::npos)
52 : {
53 : const CPLStringList aosTokens(
54 12 : CSLTokenizeString2(osBuffer.c_str() + nPos + 1, " ", 0));
55 6 : if (aosTokens.size() >= 18)
56 : {
57 6 : nRet = atoi(aosTokens[17]);
58 : }
59 : }
60 : }
61 6 : fclose(fp);
62 : }
63 6 : return nRet;
64 : }
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
|