Coverage Report

Created: 2026-02-14 09:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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