|
| 1 | +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. |
| 2 | +# |
| 3 | +# SPDX-License-Identifier: Apache-2.0 |
| 4 | + |
| 5 | + |
| 6 | +# WSL-specific locale guard, used by cuda.core.system.get_process_name() to |
| 7 | +# work around a bug in NVML's WSL implementation where nvmlSystemGetProcessName |
| 8 | +# returns mojibake when the calling thread is in a non-"C" locale. See |
| 9 | +# get_process_name() for the full backstory. |
| 10 | +# |
| 11 | +# This module is only compiled on Linux (build_hooks.py excludes it on Windows) |
| 12 | +# because it uses the POSIX per-thread locale APIs (newlocale/uselocale/ |
| 13 | +# freelocale), which are not available on MSVC. Callers must guard imports of |
| 14 | +# this module with try/except ImportError. |
| 15 | + |
| 16 | + |
| 17 | +cdef extern from "locale.h" nogil: |
| 18 | + ctypedef void *locale_t |
| 19 | + int LC_ALL_MASK |
| 20 | + locale_t newlocale(int category_mask, const char *locale, locale_t base) |
| 21 | + locale_t uselocale(locale_t newloc) |
| 22 | + void freelocale(locale_t locobj) |
| 23 | + |
| 24 | + |
| 25 | +cdef class c_locale_guard: |
| 26 | + """Context manager that pins the calling thread to the "C" locale. |
| 27 | +
|
| 28 | + Uses POSIX newlocale/uselocale/freelocale so other threads' view of the |
| 29 | + locale is unaffected. Restores the previous thread locale on exit. |
| 30 | + """ |
| 31 | + cdef locale_t _c_locale |
| 32 | + cdef locale_t _prev_locale |
| 33 | + cdef bint _active |
| 34 | + |
| 35 | + def __cinit__(self): |
| 36 | + self._c_locale = <locale_t>0 |
| 37 | + self._prev_locale = <locale_t>0 |
| 38 | + self._active = False |
| 39 | + |
| 40 | + def __enter__(self): |
| 41 | + self._c_locale = newlocale(LC_ALL_MASK, b"C", <locale_t>0) |
| 42 | + if self._c_locale == <locale_t>0: |
| 43 | + raise RuntimeError("Failed to create C locale") |
| 44 | + self._prev_locale = uselocale(self._c_locale) |
| 45 | + self._active = True |
| 46 | + return self |
| 47 | + |
| 48 | + def __exit__(self, exc_type, exc_val, exc_tb): |
| 49 | + if self._active: |
| 50 | + uselocale(self._prev_locale) |
| 51 | + freelocale(self._c_locale) |
| 52 | + self._active = False |
| 53 | + return False |
0 commit comments