1. 程式人生 > >[Golang]OS系統呼叫淺析

[Golang]OS系統呼叫淺析

上回講Goroutine狀態變換的時候,遺留了一部分關於Syscall處理的內容,這次打算把Go語言對Syscall的處理機制系統的總結一下,放在今天這篇文章中。

Go 語言庫對Syscall的封裝

我們知道Go是一門面向系統級開發的Native程式語言,與C/C++ 類似,Go的編譯器會直接將程式編譯、連結成本地可執行檔案。理論上,它可以完成任何C/C++語言能完成的。作為支撐該特性的重要方面,Go以標準庫形式提供了syscall包,用來支援OS級系統呼叫。

首先,Go對各種系統呼叫介面進行了封裝,提供給使用者一組Go語言函式,方便在程式中直接呼叫,如:

func Read(fd int, p []byte
) (n int, err error)
func Write(fd int, p []byte) (n int, err error)

同時,Go還通過以下函式提供了對Syscall的直接呼叫支援:

func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr
, err Errno)
func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)

其中,帶有Raw字首的一組操作表示直接呼叫syscall (注:以Linux為例,在AMD64中是通過syscall指令實現,在X86中是int 0x80軟中斷,而ARM中則是採用SWI軟中斷實現系統呼叫),而不帶Raw字首的操作則在真正呼叫syscall前會先呼叫runtime·entersyscall,並在syscall返回後插入runtime·exitsyscall。這兩個輔助函式的功能我們在前面介紹排程器時已經說過了,後面還會再提。

這4個函式全都是用匯編語言實現的,並且和具體的硬體架構及OS相關,比如Linux下ARM架構的相應實現,在 src/pkg/syscall/asm_linux_arm.s中。至於其他的如Read/Write這類的函式,其內部基本上都呼叫上面的4個函式實現的。

執行時支援

我們之前講了很多次,Go語言runtime為了實現較高的併發度,對OS系統呼叫做了一些優化,主要就體現在runtime·entersyscall和入runtime·exitsyscall這兩個函式上,它們的實現程式碼在src/pkg/runtime/proc.c之中,之前我們已經多次討論過這個檔案了。

在分析實現代前,我們先來看看函式的宣告,位置在src/pkg/runtime/runtime.h中:

void runtime·entersyscall(void);
void runtime·entersyscallblock(void);
void runtime·exitsyscall(void);

這裡聲明瞭3個函式,多了一個void runtime·entersyscallblock(void),在後面會分析它的功能和使用情況。

好了,現在來看實現程式碼。首先,我們很容易找到了void runtime·exitsyscall(void) 的實現,而另外兩個卻找不到,只是找到了兩個與之向接近的函式定義,分別是:

void ·entersyscall(int dummy) { ... }
void ·entersyscallblock(int dummy) { ... }

通過反彙編分析,我發現程式碼中所有對runtime·entersyscallruntime·entersyscallblock的呼叫最後都分別對映到了·entersyscall 和·entersyscallblock,也就是說前面兩個函式分別是後面兩個函式的別名。至於為什麼這樣實現,我沒有找到相關的文件說明,但感覺應該主要是由於前後兩組函式引數不同的關係 —— 函式呼叫本身是不需要傳入引數的,而函式實現時,無中生有了一個dummy引數,其目的就是為了通過該引數指標(地址)方便定位呼叫者的PC和SP值。

runtime·entersyscall

好了,我們回到函式實現分析上來,看看進入系統呼叫前,runtime究竟都做了那些特別處理。下面將這個函式分成3段進行分析:

  • 首先,函式通過“pragma”將該函式宣告為“NOSPLIT”,令其中的函式呼叫不觸發棧擴充套件檢查。

    剛進入函式,先禁止搶佔,然後通過dummy引數獲得呼叫者的SP和PC值(通過save函式儲存到g->sched.spg->sched.pc),將其分別儲存到groutine的syscallspsyscallpc欄位,同時記錄的欄位還有syscallstacksyscallguard。這些欄位的功能主要是使得垃圾收集器明確棧分析的邊界 —— 對於正在進行系統呼叫的任務,只對其進入系統呼叫前的棧進行“標記-清除”。(實際上,Go語言的cgo機制也利用了entersyscall,因而cgo執行的程式碼不受垃圾收集機制管理。

    然後,Goroutine的狀態切換到Gsyscall狀態。

#pragma textflag NOSPLIT
void
·entersyscall(int32 dummy)
{
  // Disable preemption because during this function g is in Gsyscall status,
  // but can have inconsistent g->sched, do not let GC observe it.
  m->locks++;
  // Leave SP around for GC and traceback.
  save(runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy));
  g->syscallsp = g->sched.sp;
  g->syscallpc = g->sched.pc;
  g->syscallstack = g->stackbase;
  g->syscallguard = g->stackguard;
  g->status = Gsyscall;
  if(g->syscallsp < g->syscallguard-StackGuard || g->syscallstack < g->syscallsp) {
      // runtime·printf("entersyscall inconsistent %p [%p,%p]\n",
      // g->syscallsp, g->syscallguard-StackGuard, g->syscallstack);
      runtime·throw("entersyscall");
  }
  • 下面的程式碼是喚醒runtime的後臺監控執行緒sysmon,在之前講排程器的時候說過,sysmon會監控所有執行syscall的執行緒M,一旦超過某個時間閾值,就將該M與對應的P解耦。
if(runtime·atomicload(&runtime·sched.sysmonwait)) {  // TODO: fast atomic
  runtime
            
           

相關推薦

[Golang]OS系統呼叫淺析

上回講Goroutine狀態變換的時候,遺留了一部分關於Syscall處理的內容,這次打算把Go語言對Syscall的處理機制系統的總結一下,放在今天這篇文章中。Go 語言庫對Syscall的封裝我們知道Go是一門面向系統級開發的Native程式語言,與C/C++ 類似,Go

解決Android7.0系統 呼叫系統相機、系統播放器播放視訊、切圖相容問題,報異常android.os.FileUriExposedException

Android7.0以前獲取本地檔案uri用的Uri.fromFile(new File(filePath)); 後會得到一個file://,這種方式呢7.0及以後的系統版本就用不了,且會報一個異常:

Golang原始碼學習:排程邏輯(四)系統呼叫

## Linux系統呼叫 概念:系統呼叫為使用者態程序提供了硬體的抽象介面。並且是使用者空間訪問核心的唯一手段,除異常和陷入外,它們是核心唯一的合法入口。保證系統的安全和穩定。 呼叫號:在Linux中,每個系統呼叫被賦予一個獨一無二的系統呼叫號。當用戶空間的程序執行一個系統呼叫時,會使用呼叫號指明系統呼叫

鴻蒙OS系統呼叫是如何實現的? | 解讀鴻蒙原始碼

本文將首先帶您回顧“系統呼叫”的概念以及它的作用,然後從經典的Hello World開始,逐行程式碼層層分析——鴻蒙OS的系統呼叫是如何實現的。 # 寫在前面 9月10號 華為開發者大會(HDC)上,華為向廣大開發者宣佈了鴻蒙2.0系統開源,原始碼託管在國內原始碼託管平臺“碼雲”上:[https://ope

Mac OS系統下配置hosts的方法

mac os oca 攔截 min 麻煩 輸入 地址 也不會 last 首先,介紹下什麽是hosts Hosts是一個沒有擴展名的系統文件,可以用系統自帶的記事本等工具打開,作用就是將一些常用的網址域名與其對應的IP地址建立一個關聯,當用戶在瀏覽器輸入一個需要登錄的網址時,

關於mac os系統自帶mail郵件系統的郵件遷移操作

mac 郵件遷移 記錄一下mac os系統郵件的遷移操作: 1. mac 1--old 2. mac 2--new 2.1 如果導入所有的郵件內容:收件箱、發件箱郵件,則按照下面的選擇: 2.2 如果僅僅想導入發件箱,則下面的操作: 2.3 如果僅僅導入

ESXI6安裝蘋果MAC OS系統

MAC OS安裝1、ESXi修改器 unlocker208,用於開啟ESXi中的Mac OS X支持1)、先啟動vSphere Client連接到ESXi主機(vSphere Client不要連接到vCenter,如果連接到vCenter,是無法啟動Mac OS X的,不過ESXi可以屬於vCenter管理,

第一次作業:基於Orange's OS系統的進程模型分析與心得體會

直接 lld turn AR 信息保存 一次 tin 怎麽 ret 1一. 操作系統進程概念模型與進程控制塊概念淺析 1. 什麽是進程?          圖 1 - 1 (WIN10系統任務管理器對進程管理的圖形化界面) 計算機中的程序關於某數據集合上的一次運

arm linux 系統呼叫過程

在Linux下系統呼叫是用軟中斷實現的,下面以一個簡單的open例子簡要分析一下應用層的open是如何呼叫到核心中的sys_open的。 t8.c 1: #include <stdio.h> 2: #include <sys/types.h> 3:

Linux核心編譯以及新增系統呼叫函式

實驗內容 (作者:Baron_w,禁止轉載) ⚫ 編譯 Linux 核心 ⚫ Linux 啟動過程 ⚫ Linux 系統呼叫實現分析 ⚫ 增加一個系統呼叫** 相關知識 dmesg 的用法 ⚫ 列出載入到核心中的所有驅動 我們可以使用如‘more’。 ‘tail’ ,

一次性講明白Linux系統呼叫(1)

什麼是系統呼叫 Linux核心中設定了很多可以實現各種系統功能的子程式,這些子程式就叫系統呼叫。而系統呼叫和普通函式呼叫的區別主要是在系統呼叫是系統提供的,函式一般是函式庫或者自己提供的。 為什麼要用系統呼叫 其實很多我們平時用的C語言標準函式,在Linux

Mac OS 系統佔用儲存空間太大怎麼辦?

  儲存空間 121 GB,系統就佔用 106G,然後就是不斷的彈窗提醒你! 解決方法: 終端先執行一下 du -sh * 檢視具體是哪裡使用了儲存空間,一般都是 library 佔用比較多的空間, 把可以刪除的都刪了,然後繼續清查系統,安裝一個免費軟體 OmniD

read 系統呼叫剖析

Read 系統呼叫在使用者空間中的處理過程 Linux 系統呼叫(SCI,system call interface)的實現機制實際上是一個多路匯聚以及分解的過程,該匯聚點就是 0x80 中斷這個入口點(X86 系統結構)。也就是說,所有系統呼叫都從使用者空間中匯聚到 0x80 中斷點,同時儲存

linux 系統呼叫 inotify & epoll

一、inotify 作用: 監控一個目錄下檔案的增加、刪除事件 1.重要的資料結構 // 發生的event結構 struct inotify_event {     __s32       wd;       &nb

Linux 檔案系統呼叫open七日遊(三)

接著上回,當對“.”和“..”處理完成後就直接返回進入下一個子路徑迴圈了,但如果當前子路徑不是“.”或“..”呢? 【fs/namei.c】 sys_open > do_sys_open > do_filp_open >&

linux 系統呼叫open 七日遊(二)

接著昨日的旅程,我們應該開始處理具體的子路徑了: 【fs/namei.c】 sys_open->do_sys_open->do_filp_open->path_openat->link_path_walk 點選(此處)摺疊或開啟 &n

linux系統呼叫open七日遊(一)

友情提示:您需要一個 kernel 3.15.6,下載地址: https://www.kernel.org/pub/linux/kernel/v3.0/linux-3.15.6.tar.xz     我們將以 Linux 系統呼叫 open 為主線,參

Linux 系統呼叫 open 七日遊(七)

【場景三】open(pathname, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)     在這個場景中我們希望建立一個新檔案(O_CREAT),並賦予該檔案使用者可讀(S_IRUSR)和使用者可寫(S_IW

Linux檔案系統呼叫open 七日遊 (六)

還記得在上一個場景中,build_open_flags裡面有一個對標誌位O_PATH的判斷麼?現在我們就來看看這個標誌位是幹啥的: 【場景二】open(pathname,O_PATH)     這個O_PATH似乎是不常用的,咱們先看看它的使用

linux檔案系統呼叫 open 七日遊(四)

現在,我們的“路徑行走”只剩下最後一個小問題需要處理了——符號連結。 【fs/namei.c】 sys_open > do_sys_open > do_filp_open > path_openat &g