VLink 2.0.0
A high-performance communication middleware
载入中...
搜索中...
未找到
utils.h
浏览该文件的文档.
1/*
2 * Copyright (C) 2026 by Thun Lu. All rights reserved.
3 * Author: Thun Lu <thun.lu@zohomail.cn>
4 * Repo: https://github.com/thun-res/vlink
5 * _ __ __ _ __
6 * | | / / / / (_) ____ / /__
7 * | | / / / / / / / __ \ / //_/
8 * | |/ / / /___ / / / / / / / ,<
9 * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10 *
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
14 *
15 * http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
22 */
23
24/**
25 * @file utils.h
26 * @brief Platform-agnostic system utilities for process, thread, network and signal management.
27 *
28 * @details
29 * The @c Utils namespace provides a set of free functions that wrap platform-specific
30 * system calls into a portable API. Supported targets include Linux, macOS, Windows,
31 * QNX, and Android.
32 *
33 * @note
34 * - All functions are @c noexcept -- errors are indicated by empty strings, @c false
35 * return values or sentinel values (e.g., @c pid == -1).
36 * - @c yield_cpu() is inlined and emits the most efficient CPU-pause instruction for
37 * the target architecture (PAUSE on x86, YIELD on ARM, .word 0x0100000f on RISC-V).
38 *
39 * @par Example
40 * @code
41 * // Set thread name and pin to cores 0 and 1:
42 * vlink::Utils::set_thread_name("worker");
43 * vlink::Utils::set_thread_stick(0b11);
44 *
45 * // Register SIGTERM / SIGINT handler:
46 * vlink::Utils::register_terminate_signal([](int sig) {
47 * // shutdown logic
48 * });
49 * @endcode
50 */
51
52#pragma once
53
54#include <functional>
55#include <string>
56#include <thread>
57#include <utility>
58#include <vector>
59
60#include "./macros.h"
61
62#ifdef _MSC_VER
63extern "C" void _mm_pause(void);
64#endif
65
66namespace vlink {
67
68/**
69 * @namespace vlink::Utils
70 * @brief Platform-agnostic system utility functions.
71 */
72namespace Utils { // NOLINT(readability-identifier-naming)
73
74/**
75 * @brief Returns the absolute path of the running executable.
76 *
77 * @return Full file-system path, or empty string on failure.
78 */
79[[nodiscard]] VLINK_EXPORT std::string get_app_path() noexcept;
80
81/**
82 * @brief Returns the directory containing the running executable.
83 *
84 * @return Directory path (without trailing slash), or empty string on failure.
85 */
86[[nodiscard]] VLINK_EXPORT std::string get_app_dir() noexcept;
87
88/**
89 * @brief Returns the file name of the running executable (without directory prefix).
90 *
91 * @return Executable name, or empty string on failure.
92 */
93[[nodiscard]] VLINK_EXPORT std::string get_app_name() noexcept;
94
95/**
96 * @brief Returns the host name of the current machine.
97 *
98 * @return Host name as reported by @c gethostname(), or empty string on failure.
99 */
100[[nodiscard]] VLINK_EXPORT std::string get_host_name() noexcept;
101
102/**
103 * @brief Returns the process ID of the current process.
104 *
105 * @return Process ID (PID), or -1 on failure.
106 */
107[[nodiscard]] VLINK_EXPORT int32_t get_pid() noexcept;
108
109/**
110 * @brief Returns the process ID of the current process as a decimal string.
111 *
112 * @return PID string, or empty string on failure.
113 */
114[[nodiscard]] VLINK_EXPORT std::string get_pid_str() noexcept;
115
116/**
117 * @brief Returns the platform-specific temporary directory path.
118 *
119 * @details
120 * Returns @c /tmp on Linux/macOS, @c %TEMP% on Windows, or the equivalent on other platforms.
121 *
122 * @return Temporary directory path, or empty string on failure.
123 */
124[[nodiscard]] VLINK_EXPORT std::string get_tmp_dir() noexcept;
125
126/**
127 * @brief Reads the value of an environment variable.
128 *
129 * @param key Name of the environment variable.
130 * @param default_value Value returned if the variable is not set. Default: empty string.
131 * @return Environment variable value, or @p default_value if not found.
132 */
133[[nodiscard]] VLINK_EXPORT std::string get_env(const std::string& key, const std::string& default_value = "") noexcept;
134
135/**
136 * @brief Sets or updates an environment variable.
137 *
138 * @param key Name of the environment variable.
139 * @param value New value.
140 * @param force If @c true, overwrite an existing variable. Default: @c true.
141 * @return @c true on success.
142 */
143VLINK_EXPORT bool set_env(const std::string& key, const std::string& value, bool force = true) noexcept;
144
145/**
146 * @brief Removes an environment variable.
147 *
148 * @param key Name of the variable to unset.
149 * @return @c true on success.
150 */
151VLINK_EXPORT bool unset_env(const std::string& key) noexcept;
152
153/**
154 * @brief Returns all IPv4 addresses assigned to local network interfaces.
155 *
156 * @param filter_available If @c true, only return addresses on interfaces that are UP.
157 * Default: @c false.
158 * @return Vector of dotted-decimal IPv4 address strings.
159 */
160[[nodiscard]] VLINK_EXPORT std::vector<std::string> get_all_ipv4_address(bool filter_available = false) noexcept;
161
162/**
163 * @brief Returns all IPv6 addresses assigned to local network interfaces.
164 *
165 * @param filter_available If @c true, only return addresses on interfaces that are UP.
166 * Default: @c false.
167 * @return Vector of IPv6 address strings.
168 */
169[[nodiscard]] VLINK_EXPORT std::vector<std::string> get_all_ipv6_address(bool filter_available = false) noexcept;
170
171/**
172 * @brief Returns the network interface name that owns a given IPv4 address.
173 *
174 * @param ipv4 Dotted-decimal IPv4 address to look up.
175 * @return Interface name (e.g., @c "eth0"), or empty string if not found.
176 */
177[[nodiscard]] VLINK_EXPORT std::string get_interface_name_by_ipv4(const std::string& ipv4) noexcept;
178
179/**
180 * @brief Returns the network interface name that owns a given IPv6 address.
181 *
182 * @param ipv6 IPv6 address string to look up.
183 * @return Interface name, or empty string if not found.
184 */
185[[nodiscard]] VLINK_EXPORT std::string get_interface_name_by_ipv6(const std::string& ipv6) noexcept;
186
187/**
188 * @brief Returns suitable IPv4 addresses for use as DDS participant unicast locators.
189 *
190 * @details
191 * Filters out loopback and link-local addresses, preferring routable unicast addresses.
192 *
193 * @param filter_available If @c true, only return addresses on UP interfaces. Default: @c false.
194 * @param max_count Maximum number of addresses to return. Default: 5.
195 * @return Vector of selected IPv4 address strings.
196 */
197[[nodiscard]] VLINK_EXPORT std::vector<std::string> get_dds_default_address(bool filter_available = false,
198 int max_count = 5) noexcept;
199
200/**
201 * @brief Checks that only one instance of the process is running (singleton guard).
202 *
203 * @details
204 * Uses a lock file or named semaphore to ensure mutual exclusion.
205 * Returns @c false if another instance is already running.
206 *
207 * @param program_name Program name used for the lock. Defaults to the executable name.
208 * @return @c true if this is the only running instance.
209 */
210[[nodiscard]] VLINK_EXPORT bool check_singleton(const std::string& program_name = "") noexcept;
211
212/**
213 * @brief Blocks until a file-system path appears or the timeout elapses.
214 *
215 * @details
216 * Polls the path every @p poll_ms milliseconds. Useful for waiting for a device
217 * node (e.g., @c /dev/video0) to become available at startup.
218 *
219 * @param path File-system path to poll.
220 * @param timeout_ms Maximum wait time in milliseconds.
221 * @param poll_ms Polling interval in milliseconds. Default: 50.
222 * @return @c true if the path appeared within the timeout; @c false on timeout.
223 */
224VLINK_EXPORT bool wait_for_device(const std::string& path, int timeout_ms, int poll_ms = 50) noexcept;
225
226/**
227 * @brief Emits a CPU pause/yield hint to reduce bus contention in busy-wait loops.
228 *
229 * @details
230 * Issues the most efficient idle instruction for the target:
231 * - x86/x86-64: @c PAUSE
232 * - ARMv7/AArch64: @c YIELD
233 * - RISC-V: fence hint (@c .word 0x0100000f)
234 * - Fallback: @c std::this_thread::yield()
235 *
236 * This function is always inlined and has zero call overhead.
237 */
238VLINK_EXPORT void yield_cpu() noexcept;
239
240/**
241 * @brief Configures the Windows console for UTF-8 output.
242 *
243 * @details
244 * Calls @c SetConsoleOutputCP(CP_UTF8) on Windows. No-op on other platforms.
245 */
247
248/**
249 * @brief Sets the OS-level name of a thread for debugging tools (e.g., gdb, perf).
250 *
251 * @param name Thread name string (max 15 characters on Linux due to @c pthread_setname_np).
252 * @param thread Thread to rename, or @c nullptr for the calling thread. Default: @c nullptr.
253 * @return @c true on success.
254 */
255VLINK_EXPORT bool set_thread_name(const std::string& name, std::thread* thread = nullptr) noexcept;
256
257/**
258 * @brief Sets the scheduling policy and priority of a thread.
259 *
260 * @details
261 * On Linux, wraps @c pthread_setschedparam. Requires appropriate @c CAP_SYS_NICE or
262 * @c RLIMIT_RTPRIO permissions for real-time policies.
263 *
264 * @param priority_level Scheduling priority (policy-dependent range).
265 * @param policy Scheduling policy (e.g., @c SCHED_FIFO, @c SCHED_RR, @c SCHED_OTHER).
266 * Pass -1 to keep the current policy. Default: -1.
267 * @param thread Thread to configure, or @c nullptr for the calling thread. Default: @c nullptr.
268 * @return @c true on success.
269 */
270VLINK_EXPORT bool set_thread_priority(int priority_level, int policy = -1, std::thread* thread = nullptr) noexcept;
271
272/**
273 * @brief Pins a thread to a set of CPU cores specified by a bitmask.
274 *
275 * @details
276 * Wraps @c pthread_setaffinity_np on Linux. Bit @c i of @p core_mask corresponds to core @c i.
277 * For example, @c core_mask == 0b0101 pins to cores 0 and 2.
278 *
279 * @param core_mask Bitmask of CPU cores (bit 0 = core 0).
280 * @param thread Thread to pin, or @c nullptr for the calling thread. Default: @c nullptr.
281 * @return @c true on success.
282 */
283VLINK_EXPORT bool set_thread_stick(uint32_t core_mask, std::thread* thread = nullptr) noexcept;
284
285/**
286 * @brief Returns the native OS thread identifier of the calling thread.
287 *
288 * @details
289 * Returns @c pthread_self() on POSIX or @c GetCurrentThreadId() on Windows.
290 * The value can be used with profiling tools or for thread identification in logs.
291 *
292 * @return Native thread ID.
293 */
294[[nodiscard]] VLINK_EXPORT uint64_t get_native_thread_id() noexcept;
295
296/**
297 * @brief Registers a callback for graceful termination signals (SIGTERM, SIGINT, etc.).
298 *
299 * @details
300 * On POSIX, installs a @c sigaction handler for @c SIGTERM and @c SIGINT.
301 * The callback receives the signal number as its argument.
302 *
303 * @param callback Callback invoked when a termination signal arrives.
304 * @param is_async If @c true, the callback runs asynchronously in a dedicated thread.
305 * Default: @c false (synchronous in the signal context).
306 * @param pass_through If @c true, re-raise the signal after the callback returns so that
307 * the default OS behaviour (core dump, etc.) also occurs. Default: @c false.
308 */
309VLINK_EXPORT void register_terminate_signal(std::function<void(int)>&& callback, bool is_async = false,
310 bool pass_through = false) noexcept;
311
312/**
313 * @brief Registers a callback for crash signals (SIGSEGV, SIGABRT, SIGFPE, SIGBUS, etc.).
314 *
315 * @details
316 * Useful for dumping logs or state before an unrecoverable crash.
317 * The callback should be async-signal-safe or very short.
318 *
319 * @param callback Callback invoked with the signal number when a crash signal fires.
320 */
321VLINK_EXPORT void register_crash_signal(std::function<void(int)>&& callback) noexcept;
322
323/**
324 * @brief Starts a background thread that detects keyboard input.
325 *
326 * @details
327 * Polls stdin every @p poll_ms milliseconds for a key press. When a key is detected,
328 * @p callback is invoked with the key name as a string (e.g., @c "enter", @c "q").
329 * Stop the detector with @c stop_detect_keyboard().
330 *
331 * @param callback Callback invoked with the key name, or @c nullptr to ignore. Default: @c nullptr.
332 * @param poll_ms Polling interval in milliseconds. Default: 20.
333 */
334VLINK_EXPORT void start_detect_keyboard(std::function<void(const std::string& key)>&& callback = nullptr,
335 int poll_ms = 20) noexcept;
336
337/**
338 * @brief Stops the keyboard detection thread started by @c start_detect_keyboard().
339 */
341
342/**
343 * @brief Returns the current terminal window dimensions.
344 *
345 * @return A pair @c {columns, rows}. Returns @c {0, 0} on failure or if not a tty.
346 */
347[[nodiscard]] VLINK_EXPORT std::pair<int, int> get_terminal_size() noexcept;
348
349/**
350 * @brief Returns the current CPU usage of the process as a percentage.
351 *
352 * @details
353 * Computes @c (user_time + kernel_time) / elapsed_time * 100. The value is a snapshot
354 * since the last call and may return 0 on the first invocation.
355 *
356 * @return CPU usage in the range [0.0, 100.0 * num_cpus].
357 */
358[[nodiscard]] VLINK_EXPORT double get_cpu_usage() noexcept;
359
360/**
361 * @brief Returns the resident set size (RSS) of the process as a percentage of total RAM.
362 *
363 * @return Memory usage percentage in the range [0.0, 100.0].
364 */
365[[nodiscard]] VLINK_EXPORT double get_memory_usage() noexcept;
366
367/**
368 * @brief Checks whether a process with the given name is currently running.
369 *
370 * @param process_name Executable name to search for (without path).
371 * @return @c true if at least one process with that name is running.
372 */
373[[nodiscard]] VLINK_EXPORT bool is_process_running(const std::string& process_name) noexcept;
374
375/**
376 * @brief Returns the local timezone offset from UTC in seconds.
377 *
378 * @details
379 * For example, UTC+8 returns @c 28800, UTC-5 returns @c -18000.
380 *
381 * @return Timezone offset in seconds.
382 */
383[[nodiscard]] VLINK_EXPORT int32_t get_timezone_diff() noexcept;
384
385/**
386 * @brief Returns a unique identifier for the current machine.
387 *
388 * @details
389 * On Linux, reads @c /etc/machine-id. On other platforms a platform-specific
390 * identifier is used.
391 *
392 * @return Machine ID string, or empty string on failure.
393 */
394[[nodiscard]] VLINK_EXPORT std::string get_machine_id() noexcept;
395
396/**
397 * @brief Hints to the OS that any unreferenced cached memory pages can be released.
398 *
399 * @details
400 * On Linux calls @c malloc_trim(0) to return freed memory from the glibc heap to the OS.
401 * On other platforms this is a no-op.
402 */
404
405////////////////////////////////////////////////////////////////
406/// Details
407////////////////////////////////////////////////////////////////
408
409#if defined(__GNUC__) && !defined(_WIN32) && !defined(__CYGWIN__)
410inline __attribute__((artificial)) void yield_cpu() noexcept {
411#else
412inline void yield_cpu() noexcept {
413#endif
414#if __has_builtin(__yield)
415 __yield();
416#elif defined(_MSC_VER) && defined(_YIELD_PROCESSOR)
417 _YIELD_PROCESSOR();
418#elif __has_builtin(__builtin_ia32_pause)
419__builtin_ia32_pause();
420#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)
421#if defined(_MSC_VER)
422_mm_pause();
423#elif defined(__GNUC__)
424__builtin_ia32_pause();
425#else
426__asm__("pause");
427#endif
428#elif __has_builtin(__builtin_arm_yield)
429__builtin_arm_yield();
430#elif defined(__arm__) || defined(__aarch64__)
431#if defined(__GNUC__)
432__asm__("yield");
433#else
434std::this_thread::yield();
435#endif
436#elif defined(__riscv)
437__asm__(".word 0x0100000f");
438#elif defined(_MSC_VER) && defined(_YIELD_PROCESSOR)
439_YIELD_PROCESSOR();
440#else
441std::this_thread::yield();
442#endif
443}
444
445} // namespace Utils
446
447} // namespace vlink
Platform-independent macro definitions for the VLink library.
#define VLINK_EXPORT
定义 macros.h:85
STL namespace