getenv() + putenv() + setenv() 的 thread-safe 問題

在「Improving Steam Client Stability on Linux (ttimo.typepad.com)」這邊看到的,原文在「Improving Steam Client stability on Linux: setenv and multithreaded environments」這邊。

裡面提到了 getenv() + putenv() + setenv() 的設計問題使得他很難 thread-safe 而造成 Linux 版的 Steam client 容易 crash,從功能上大概猜得到原因,畢竟是對一塊 global variable 操作 + 提供 pointer 讓後續的程式操作。

比較特別的是作者提到了 Mac 上面是透過 memory leak 解決 thread-safe 的問題:

There is no silver bullet to address this. These APIs are thread safe on Windows and Mac, so developers use them. Mac opted to leak the strings rather than crash (see BUGS in the Mac OS X manual page for getenv).

在蘋果網站上的 getenv 說明看起來像是直接 malloc() 後複製一塊出去讓你用,用 memory leak 確保 thread-safe 特性?

Successive calls to setenv() or putenv() assigning a differently sized value to the same name will result in a memory leak. The FreeBSD seman-tics semanticstics for these functions (namely, that the contents of value are copied and that old values remain accessible indefinitely) make this bug unavoidable. Future versions may eliminate one or both of these semantic guarantees in order to fix the bug.

這包似乎是從 FreeBSD 這邊帶過來的:「Bug 5604 - setenv(3) function has memory leak, other bugs」。

後面提到 Steam client 的解法,看起來主要就是儘量降低 *env() 的使用以緩解問題,但對於其他 library 去讀的部分就比較沒辦法了,他們的作法是在還沒進入 thread 區塊前,把已知的變數名稱弄大空間,讓後續操作儘量不會觸發到改變位置的行為:

For the few remaining setenv use cases that could not be easily refactored, we introduced an 'environment manager' that pre-allocates large enough value buffers at startup for fixed environment variable names, before any threading has started.

另外原文 comment 的地方有提到 glibc 有一些 *env() 的 thread-safe 特性改善計畫,裡面也可以看看還蠻有趣的,是今年七月的事情:「getenv/environ thread safety」。

話說 Windows 這邊是怎麼弄,好像沒提到...

X Window 下多個 Selection 的問題

整理資料的時候發現繞了一大圈,在英文版的維基百科上面有蠻完整的歷史說明:「X Window selection」。

這邊就是自己遇到問題後整理起來的。我遇到的問題是在 QEMU 裡面的 Windows 10 複製的東西,在 WezTerm 無法用 Shift-Insert 貼上,但在瀏覽器上卻可以用 Ctrl-V 貼上。

這是因為 X Window 有好幾個 selection (或是當作不同的「剪貼簿」),這點在最開頭提到的維基百科文件裡面有歷史故事可以看。

其中 cutbuffer 已經過時,先不管他,目前主要有 PRIMARY 與 CLIPBOARD 兩個 selection 可以用,在 command line 下可以讀出來,這樣就能觀察到不同程式是怎麼塞進這兩個 selection 了:

xclip -out -selection clipboard
xclip -out -selection primary

其中 PRIMARY 主要是用在框選後就會更新的 buffer,而 CLIPBOARD 則是用在使用者有明確表示要「剪貼」的 buffer。

釐清後,後續就是個人選擇問題了,因為 WezTerm 算是很有彈性的 terminal 軟體,可以直接在設定檔裡面修改 key mapping。

預設的 Shift-Insert 會讀 PRIMARY,而 Ctrl-Shift-V 才是讀 CLIPBOARD,我希望把 Shift-Insert 也改成讀 CLIPBOARD,對我來說用起來會更順手。

這邊會修改 ~/.wezterm.lua 用 WezTerm 提供的 PasteFrom 指定 selection,像是這樣:

local act = wezterm.action
config.keys = {
    {
        key = 'Insert',
        mods = 'SHIFT',
        action = act.PasteFrom 'Clipboard',
    },
}

而有些人會希望一勞永逸,把 PRIMARY 與 CLIPBOARD 合併,在「Merge primary and clipboard X selections」這邊有提到好幾套解法,我測過 autocutsel 是可以做到的,但缺點就是滑鼠選一個範圍時就會自動覆蓋剪貼簿,算是個人取捨問題。

也是個困擾頗久,得花了時間查資料 + 測試解掉的問題...

Ubuntu 上 Gradle 版本太舊的問題

從「Ubuntu – Package Search Results -- gradle」或是「gradle package : Ubuntu」這邊可以看到 Ubuntu 上的 Gradle 舊到不行,從 focal (20.04) 後都是 4.4.1,看起來是因為上游 Debian 一直沒更新?在「Debian -- Package Search Results -- gradle」這邊也看得到是 4.4.1。

而從 GitHub 上翻,可以發現 4.4.1 是 2017 年出的版本了。

短時間看起來沒解,所以就得找方法繞開... 官網上的「Installation」有提到可以透過 SDKMAN!,但我就馬上想到 mise 說不定可以?

在 mise 的 registry.toml 裡面可以看到目前支援的項目,包括了 asdf 社群的資源,可以看到有 gradle 的設定,看起來是有支援的:

gradle = ["asdf:rfrancis/asdf-gradle", "vfox:version-fox/vfox-gradle"]

直接裝起來就收工了:

mise use -g gradle@8

話說看到不少有趣的東西,像是三個雲的 cli 指令:

awscli = ["asdf:MetricMike/asdf-awscli"]
azure-cli = ["asdf:EcoMind/asdf-azure-cli"]
gcloud = ["asdf:jthegedus/asdf-gcloud"]

算是個選擇...?

wc -l 在 Linux 與 macOS 上輸出的格式不同

Linux 上跑起來沒問題的 shell script 到 macOS 上發現有狀況,追了問題後發現是 wc -l 輸出的格式不同導致的。

Linux 上面是直接輸出數字:

$ echo abc | wc -l
1

macOS 上面則會在開頭看到 trailing space:

$ echo abc | wc -l
       1

可以搜到蠻多地方都有在討論這個問題,像是這篇:「WC on OSX - Return includes spaces」。

不過看起來 POSIX 標準沒有直接規定輸出的格式,只好照著語意再處理了,像是 | awk '{print $1}' 之類的方法。

Linux 的 RT (Real-Time) 版本 PREEMPT_RT

Hacker News Daily 上看到的,Linux kernelPREEMPT_RT 這個 RT patch 併入 official repository 了:「Real-time Linux is officially part of the kernel after decades of debate」。

這類需求可以在 RTOS 裡面看到完整的說明,大家常用的特性是確保反應時間這點,像是對汽車自動駕駛的操作。

從 Linux 開始流行後就有人會想要這個需求了,而 open-source software 當然就會有人實作,不過一直是以 out-of-tree patch 的形式在維護。

其他在市場上常見的選擇有 VxWorks 以及 QNX,以前就蠻常聽到這些 OS 的應用。

另外翻資料時發現 Windows CE 也有做到即時性,不過微軟已經淡出這塊市場,Windows CE 2013 的支援到去年的 2023/10/10,但比較特別的是居然還有在賣,預定賣到 2028 年:(下面這段出自 CE migration - Frequently Asked Questions)

While Windows CE 2013 will reach end of extended support in late 2023, Microsoft will allow license sales to continue for Windows Embedded Compact 2013 until 2028. And of course, Windows CE devices can continue to be used indefinitely.

然後已經掛掉的 Symbian 也有做到即時性。

回到 Linux 這邊的情況,其實讓我比較驚訝 (但想了一下覺得好像也合理) 的是 printk 原來是個阻礙:

Torvalds wrote the original code for printk, a debugging tool that can pinpoint exact moments where a process crashes, but also introduces latency that runs counter to real-time computing.

在「[PATCH printk v5 0/8] provide nbcon base」有提到是 atomic 需求,為了解決這個問題設計了 NBCON (non-blocking console):

This is v5 of a series to introduce the new non-BKL (nbcon) consoles. v4 is here [0]. For information about the motivation of the atomic consoles, please read the cover letter of v1 [1].

「用正確的方法解決」的堅持,看起來陸陸續續在收尾階段了。

Podman 下的 inotify 問題

手上有個前端專案的開發環境是在 Linux container 上跑起來,有支援修改時 auto reload,我在 Linux Desktop 上面跑起來沒有問題,但在 MacBook (M 系列) 上開發就發現不會 auto reload,這樣改起來頗麻煩...

馬上有在猜是不是 inotify 的問題,先翻了一下資料,發現 inotify 在 Podman 上沒有被完整支援:「file changes not registered by inotifywait inside podman on Mac #19430」、「cannot receive inotify on shared directories when using AppleHV #22343」。

接下來把 Podman 換成 Docker,就發現解決了,看起來我遇到的應該就是 Podman 對 inotify 的支援度問題。

這樣開發上沒辦法用 Podman,只能先繼續把票追起來。

陽交大資工 (原交大資工) 要退役 FreeBSD 伺服器了

結果是在 Plurk 上面看到 https://www.plurk.com/p/3g8a60cuxm 這則消息,原公告在「[重要事項]工作站系統升級維護及 FreeBSD EOL 規劃」這邊。

與 Linux 相關的是 alumni 工作站從 FreeBSD 換 Debian

alumni 工作站將由 Debian 系統取代。
現有的 alumni 工作站將於維護當天改名為 alumni1。
我們將提供三個月的遷移時間,alumni1 工作站將於三個月後停止服務。

而與 FreeBSD 有關的則是先縮減,然後三個月後停止服務:

將縮減至兩台工作站 bsd[1-2].cs.nycu.edu.tw
BSD 工作站將於三個月後停止服務。

雖然 alumni 主機只有偶而會連回去跑個 MTR 看各種 routing,但撤掉 FreeBSD 還是有點感傷啊。

不曉得現在 SA/NA 課程還有沒有在教 FreeBSD...

Android 的 Linux Kernel 將會有四年的維護期

去年 Linux Kernel 決定將 LTS 從六年縮短為兩年 (參考先前寫到的「Linux Kernel 後續的 LTS 版本將縮短成兩年」),而 Android 這邊決定後來的 LTS 版本將額外提供兩年支援,變成四年:「Google extends Linux kernel support to keep Android devices secure for longer」,引用的報導在「Google extends Linux kernel support to keep Android devices secure for longer」。

Android 的說明文件「Android common kernels」這邊有提到這個時間:

Beginning with kernel 6.6, the support lifetime for the stable kernels is 4 years.

應該是 Android 本身的 support policy 需要這個長度...

NVIDIA 正式推出開源版本的 Linux driver 了

五月的時候有提過 NVIDIA 有計畫要使用 open-source license 的 Linux driver:「Nvidia 在 Linux 上安裝核心驅動程式時將建議使用開源版本」,現在則是正式公告了:「NVIDIA Transitions Fully Towards Open-Source GPU Kernel Modules」。

支援的 GPU 分成三塊,第一塊是只有 open-source 版本有支援,目前已經推出的產品應該是只有 GH200 是這個架構:

For cutting-edge platforms such as NVIDIA Grace Hopper or NVIDIA Blackwell, you must use the open-source GPU kernel modules. The proprietary drivers are unsupported on these platforms.

然後是 Turing 後的架構,以桌機顯卡來說的話是 2016 年出的 20 系列架構 (值得提一下的是,16 系列雖然看起來數字比較小,但是是 2019 年出的 Turing 架構,所以也支援):

For newer GPUs from the Turing, Ampere, Ada Lovelace, or Hopper architectures, NVIDIA recommends switching to the open-source GPU kernel modules.

舊的系列則是不支援,以桌機來說就是 10 系列以及更舊的卡:

For older GPUs from the Maxwell, Pascal, or Volta architectures, the open-source GPU kernel modules are not compatible with your platform. Continue to use the NVIDIA proprietary driver.

再等一兩個版本再來換過去...

話說找資料發現維基百科上面用 Nvidia,但我找資料發現官方名稱是用 NVIDIA,翻了討論頁發現 2010 年就有人幹剿過了 (在 Naming Conventions 這段),看起來是不會改?

最近 Linux Kernel 對 Raspberry Pi 效率的提升

在「NUMA Emulation speeds up Pi 5 (and other improvements)」這邊看到的,最近 Linux kernel 有些新的 patch 對 Raspberry Pi 的效率有不少提升。

其中 NUMA Emulation 這包對於 Raspberry Pi 5 的效能提升頗多:

[I]t can bring a significant performance uplift on Raspberry Pi 5.

照他的說法,Geekbench 6 的提升部分,單核 6% 多核 18%:

In more conrete numbers, testing with Geekbench 6 shows that splitting into four emulated NUMA nodes can uplift the single core score of the benchmark by around 6%, and the multi-core by around 18%.

Jeff Geerling 測試的結果則是 6% & 12%,沒有宣稱那麼多,但仍然是不小的提升。

話說我還在想要不要弄一台 Raspberry Pi 5,目前手上有幾台 1B、一台 3B+ 以及一台 4,除了跑 SmokePing 以外還有什麼值得跑的...