在「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 這邊是怎麼弄,好像沒提到...