首頁  >  文章  >  後端開發  >  為什麼在 Go 多線程環境中“setns”會失敗並顯示 EINVAL?

為什麼在 Go 多線程環境中“setns”會失敗並顯示 EINVAL?

Linda Hamilton
Linda Hamilton原創
2024-11-01 09:23:30646瀏覽

Why Does 'setns' Fail with EINVAL in a Go Multithreaded Environment?

從Go 呼叫'setns' 失敗,MNT 命名空間出現EINVAL

問題

嘗試從Go 呼叫'setns' 進入MNT 時命名空間,呼叫始終返回EINVAL。儘管相同功能的 C 實現正常工作,但仍觀察到此問題。

原因

這個問題源自於 Go 是一種多執行緒語言,而 'setns' 期望是從單執行緒上下文呼叫。當從多執行緒環境呼叫時,「setns」無法正確地將目前執行緒與目標命名空間關聯起來。

解決方案 - CGO 建構子

此問題的解決方案是利用「CGO 建構子技巧。」此技術可讓您在 Go 執行時間初始化先前指定要執行的 C 函數。透過使用這種方法,您的 C 函數可以在建立 Go 執行緒之前呼叫“setns”,確保呼叫是在單執行緒上下文中進行的。

  1. 建構一個呼叫「setns」的 C 函式' 與所需的參數。透過使用 __attribute__((constructor)) 巨集修飾函數來實現此目的。
  2. 透過使用 import "C" 導入 C 函數,將其包含在 Go 程式碼中。

工作範例

<code class="go">/*
#include <sched.h>
#include <stdio.h>
#include <fcntl.h>

__attribute__((constructor)) void enter_namespace(void) {
   setns(open("/proc/<PID>/ns/mnt", O_RDONLY, 0644), 0);
}
*/
import "C"

... rest of file is unchanged ...
</code>

請記得將佔位符 取代為與目標程式的實際 PID。

限制

這個方法有一些限制:

  • PID 必須在C 函數中硬編碼,就像Go 一樣程式碼在C 函數執行時可能不可用。
  • 不可能在 Go 程式碼中多次呼叫“setns”,因為 C 程式碼在 Go 運行時初始化之前運行。

附加說明

「setns(2)」的修補程式確認了多執行緒環境中單一執行緒執行的要求。具有功能的程序也必須在自己的使用者命名空間中擁有 CAP_SYS_CHROOT 和 CAP_SYS_ADMIN,並在目標掛載命名空間中擁有 CAP_SYS_ADMIN。

以上是為什麼在 Go 多線程環境中“setns”會失敗並顯示 EINVAL?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn