|
41 | 41 |
|
42 | 42 | #include <fcntl.h> |
43 | 43 | #include <unistd.h> |
| 44 | + #include <pthread.h> // for pthread_getname_np |
44 | 45 |
|
45 | 46 | #ifdef __linux__ |
46 | 47 | #include <sys/syscall.h> //Use gettid() syscall under linux to get thread id |
@@ -367,6 +368,127 @@ SPDLOG_INLINE size_t thread_id() SPDLOG_NOEXCEPT { |
367 | 368 | #endif |
368 | 369 | } |
369 | 370 |
|
| 371 | +// Helper function to check if current thread is the main thread |
| 372 | +SPDLOG_INLINE bool is_main_thread() SPDLOG_NOEXCEPT { |
| 373 | + // Cache the main thread ID for performance, but determine it more reliably |
| 374 | + static std::thread::id cached_main_thread_id; |
| 375 | + static bool main_thread_id_initialized = false; |
| 376 | + |
| 377 | + if (!main_thread_id_initialized) { |
| 378 | + // Determine main thread ID using platform-specific reliable methods |
| 379 | +#ifdef __APPLE__ |
| 380 | + // On macOS, check if current thread is main using pthread_main_np() |
| 381 | + if (pthread_main_np() != 0) { |
| 382 | + cached_main_thread_id = std::this_thread::get_id(); |
| 383 | + main_thread_id_initialized = true; |
| 384 | + } |
| 385 | +#elif defined(__linux__) |
| 386 | + // On Linux, check if current thread is main (PID == TID) |
| 387 | + if (getpid() == static_cast<pid_t>(syscall(SYS_gettid))) { |
| 388 | + cached_main_thread_id = std::this_thread::get_id(); |
| 389 | + main_thread_id_initialized = true; |
| 390 | + } |
| 391 | +#elif defined(_WIN32) |
| 392 | + // On Windows, we can check if current thread is main thread |
| 393 | + // Main thread ID is the same as process ID in Windows |
| 394 | + DWORD current_tid = GetCurrentThreadId(); |
| 395 | + DWORD process_id = GetCurrentProcessId(); |
| 396 | + |
| 397 | + // In Windows, the main thread ID is typically the same as the process ID |
| 398 | + // or we can check if this is the first thread created |
| 399 | + if (current_tid == process_id) { |
| 400 | + cached_main_thread_id = std::this_thread::get_id(); |
| 401 | + } else { |
| 402 | + // Alternative method: Check if we're in the main thread by examining |
| 403 | + // thread creation order or using GetMainThreadId (Windows 10+) |
| 404 | + // For compatibility, we'll use a heuristic approach |
| 405 | + static bool first_call = true; |
| 406 | + if (first_call) { |
| 407 | + cached_main_thread_id = std::this_thread::get_id(); |
| 408 | + first_call = false; |
| 409 | + } |
| 410 | + } |
| 411 | + main_thread_id_initialized = true; |
| 412 | +#else |
| 413 | + // For other platforms, use the original approach |
| 414 | + // Assume first caller is from main thread (works in most cases) |
| 415 | + cached_main_thread_id = std::this_thread::get_id(); |
| 416 | + main_thread_id_initialized = true; |
| 417 | +#endif |
| 418 | + } |
| 419 | + |
| 420 | + // Fast comparison using cached thread ID |
| 421 | + if (main_thread_id_initialized) { |
| 422 | + return std::this_thread::get_id() == cached_main_thread_id; |
| 423 | + } |
| 424 | + return false; |
| 425 | +} |
| 426 | + |
| 427 | +// Return current thread name as string |
| 428 | +SPDLOG_INLINE std::string thread_name() SPDLOG_NOEXCEPT { |
| 429 | +#ifdef _WIN32 |
| 430 | + // Windows implementation using GetThreadDescription (Windows 10 version 1607+) |
| 431 | + HANDLE hThread = GetCurrentThread(); |
| 432 | + PWSTR threadName = nullptr; |
| 433 | + |
| 434 | + // GetThreadDescription is available from Windows 10 version 1607 |
| 435 | + typedef HRESULT(WINAPI* GetThreadDescriptionFunc)(HANDLE, PWSTR*); |
| 436 | + static GetThreadDescriptionFunc getThreadDescFunc = nullptr; |
| 437 | + static bool initialized = false; |
| 438 | + |
| 439 | + if (!initialized) { |
| 440 | + HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll"); |
| 441 | + if (kernel32) { |
| 442 | + getThreadDescFunc = reinterpret_cast<GetThreadDescriptionFunc>( |
| 443 | + GetProcAddress(kernel32, "GetThreadDescription")); |
| 444 | + } |
| 445 | + initialized = true; |
| 446 | + } |
| 447 | + |
| 448 | + if (getThreadDescFunc && SUCCEEDED(getThreadDescFunc(hThread, &threadName)) && threadName) { |
| 449 | + // Convert wide string to narrow string |
| 450 | + int size = WideCharToMultiByte(CP_UTF8, 0, threadName, -1, nullptr, 0, nullptr, nullptr); |
| 451 | + if (size > 0) { |
| 452 | + std::string result(size - 1, '\0'); |
| 453 | + WideCharToMultiByte(CP_UTF8, 0, threadName, -1, &result[0], size, nullptr, nullptr); |
| 454 | + LocalFree(threadName); |
| 455 | + return result; |
| 456 | + } |
| 457 | + LocalFree(threadName); |
| 458 | + } |
| 459 | + |
| 460 | + // Fallback: return "main" for main thread, thread ID as string for others |
| 461 | + return is_main_thread() ? "main" : std::to_string(thread_id()); |
| 462 | + |
| 463 | +#elif defined(__linux__) || defined(__APPLE__) |
| 464 | + // Linux and macOS implementation using pthread_getname_np |
| 465 | + char thread_name_buf[16]; // Linux thread names are limited to 16 characters including null terminator |
| 466 | + |
| 467 | + #ifdef __APPLE__ |
| 468 | + // macOS version |
| 469 | + if (pthread_getname_np(pthread_self(), thread_name_buf, sizeof(thread_name_buf)) == 0) { |
| 470 | + if (thread_name_buf[0] != '\0') { |
| 471 | + return std::string(thread_name_buf); |
| 472 | + } |
| 473 | + } |
| 474 | + #else |
| 475 | + // Linux version |
| 476 | + if (pthread_getname_np(pthread_self(), thread_name_buf, sizeof(thread_name_buf)) == 0) { |
| 477 | + if (thread_name_buf[0] != '\0') { |
| 478 | + return std::string(thread_name_buf); |
| 479 | + } |
| 480 | + } |
| 481 | + #endif |
| 482 | + |
| 483 | + // Fallback: return "main" for main thread, thread ID as string for others |
| 484 | + return is_main_thread() ? "main" : std::to_string(thread_id()); |
| 485 | + |
| 486 | +#else |
| 487 | + // Other Unix systems: return "main" for main thread, thread ID for others |
| 488 | + return is_main_thread() ? "main" : std::to_string(thread_id()); |
| 489 | +#endif |
| 490 | +} |
| 491 | + |
370 | 492 | // This is avoid msvc issue in sleep_for that happens if the clock changes. |
371 | 493 | // See https://github.com/gabime/spdlog/issues/609 |
372 | 494 | SPDLOG_INLINE void sleep_for_millis(unsigned int milliseconds) SPDLOG_NOEXCEPT { |
|
0 commit comments