Golang 系統(tǒng)調(diào)用 syscall

對于寫后端語言來說的人假夺,文件操作是很常見的。go對文件操作的支持非常的好茵汰。今天通過go中文件操作記錄下syscall相關(guān)內(nèi)容赂弓。

先看下文件定義:

type File struct {
    *file
}
// file is the real representation of *File.
// The extra level of indirection ensures that no clients of os
// can overwrite this data, which could cause the finalizer
// to close the wrong file descriptor.
type file struct {
    fd      int
    name    string
    dirinfo *dirInfo // nil unless directory being read
}

// Auxiliary information if the File describes a directory
type dirInfo struct {
    buf  []byte // buffer for directory I/O
    nbuf int    // length of buf; return value from Getdirentries
    bufp int    // location of next record in buf.
}

是不是夠簡潔的绑榴,而且注釋寫的很清楚。嘿嘿

我們從文件創(chuàng)建開始

// Create creates the named file with mode 0666 (before umask), truncating
// it if it already exists. If successful, methods on the returned
// File can be used for I/O; the associated file descriptor has mode
// O_RDWR.
// If there is an error, it will be of type *PathError.
func Create(name string) (*File, error) {
    return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
}

第一個參數(shù)是文件名盈魁,第二個參數(shù)是文件模式彭沼,第三個參數(shù)是文件權(quán)限,默認(rèn)權(quán)限是0666
O_RDWR O_CREATE O_TRUNC是file.go文件中定義好的一些常量备埃,標(biāo)識文件以什么模式打開姓惑,常見的模式有讀寫,只寫按脚,只讀于毙,權(quán)限依次降低。

// Flags to OpenFile wrapping those of the underlying system. Not all
// flags may be implemented on a given system.
const (
    O_RDONLY int = syscall.O_RDONLY // open the file read-only.
    O_WRONLY int = syscall.O_WRONLY // open the file write-only.
    O_RDWR   int = syscall.O_RDWR   // open the file read-write.
    O_APPEND int = syscall.O_APPEND // append data to the file when writing.
    O_CREATE int = syscall.O_CREAT  // create a new file if none exists.
    O_EXCL   int = syscall.O_EXCL   // used with O_CREATE, file must not exist
    O_SYNC   int = syscall.O_SYNC   // open for synchronous I/O.
    O_TRUNC  int = syscall.O_TRUNC  // if possible, truncate file when opened.
)

syscall 里面也是一些常量

    O_RDWR                           = 0x2
    O_RSYNC                          = 0x101000
    O_SYNC                           = 0x101000
    O_TRUNC                          = 0x200
    O_WRONLY                         = 0x1

OpenFile 函數(shù)參數(shù)介紹完辅搬,進(jìn)到函數(shù)中唯沮,看到關(guān)鍵一句

r, e = syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))

看到syscall對于文件的操作進(jìn)行了封裝,繼續(xù)進(jìn)入

func Open(path string, mode int, perm uint32) (fd int, err error) {
    return openat(_AT_FDCWD, path, mode|O_LARGEFILE, perm)
}

//sys   openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)

func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) {
    return openat(dirfd, path, flags|O_LARGEFILE, mode)
}
func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) {
    var _p0 *byte
    _p0, err = BytePtrFromString(path)
    if err != nil {
        return
    }
    r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mode), 0, 0)
    use(unsafe.Pointer(_p0))
    fd = int(r0)
    if e1 != 0 {
        err = errnoErr(e1)
    }
    return
}

跟進(jìn)Syscall6堪遂,看到

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)

這里介蛉,看到相似的函數(shù)有四個,后面沒數(shù)字的溶褪,就是4個參數(shù)币旧,后面為6的,就是6個參數(shù)猿妈。調(diào)用的是操作系統(tǒng)封裝好的API吹菱。可以 man syscall 或者這里http://man7.org/linux/man-pages/man2/syscall.2.html#top_of_page看下詳細(xì)信息彭则。

NAME
       syscall - indirect system call

SYNOPSIS
       #define _GNU_SOURCE         /* See feature_test_macros(7) */
       #include <unistd.h>
       #include <sys/syscall.h>   /* For SYS_xxx definitions */

       long syscall(long number, ...);

對于不同架構(gòu)的參數(shù):

       arch/ABI      arg1  arg2  arg3  arg4  arg5  arg6  arg7  Notes
       ──────────────────────────────────────────────────────────────────
       arm/OABI      a1    a2    a3    a4    v1    v2    v3
       arm/EABI      r0    r1    r2    r3    r4    r5    r6
       arm64         x0    x1    x2    x3    x4    x5    -
       blackfin      R0    R1    R2    R3    R4    R5    -
       i386          ebx   ecx   edx   esi   edi   ebp   -
       ia64          out0  out1  out2  out3  out4  out5  -
       mips/o32      a0    a1    a2    a3    -     -     -     See below
       mips/n32,64   a0    a1    a2    a3    a4    a5    -
       parisc        r26   r25   r24   r23   r22   r21   -
       s390          r2    r3    r4    r5    r6    r7    -
       s390x         r2    r3    r4    r5    r6    r7    -
       sparc/32      o0    o1    o2    o3    o4    o5    -
       sparc/64      o0    o1    o2    o3    o4    o5    -
       x86_64        rdi   rsi   rdx   r10   r8    r9    -
       x32           rdi   rsi   rdx   r10   r8    r9    -

好了鳍刷,到這里大致上有了解了。我們在看下細(xì)節(jié)的東西俯抖。

func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)

系統(tǒng)調(diào)用:
第一個參數(shù)是系統(tǒng)調(diào)用號输瓜,每個系統(tǒng)調(diào)用在操作系統(tǒng)里面都有一個唯一的操作碼,后面的參數(shù)是系統(tǒng)調(diào)用所需要的參數(shù)芬萍。返回的參數(shù)是系統(tǒng)調(diào)用的結(jié)果和錯誤(如果有的話)

r0, _, e1 := Syscall(SYS_OPENAT, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)

好了尤揣,回到我們系統(tǒng)調(diào)用的地方,操作碼為SYS_OPENAT 到定義常量的地方担忧,我們看到芹缔,這里定義的都是系統(tǒng)調(diào)用的操作碼坯癣,細(xì)心的你可能已經(jīng)看到了瓶盛,還有一個SYS_OPEN,那他們的差別是什么呢?
從Linux2.6.16開始,linux內(nèi)核提供了一系列新的系統(tǒng)調(diào)用惩猫,為了和以前的系統(tǒng)調(diào)用兼容和區(qū)分芝硬,這些新的系統(tǒng)調(diào)用就以at結(jié)尾,它們在執(zhí)行與傳統(tǒng)系統(tǒng)調(diào)用相似任務(wù)的同時轧房,還提供了一些附加功能拌阴,對某些程序非常有用,這些系統(tǒng)調(diào)用使用目錄文件描述符來解釋相對路徑奶镶。

系統(tǒng)調(diào)用參數(shù)講完了迟赃,說下RawSyscall 和 Syscall的區(qū)別吧。Syscall在開始和結(jié)束的時候厂镇,會分別調(diào)用runtime中的進(jìn)入系統(tǒng)和退出系統(tǒng)的函數(shù)纤壁,所以Syscall是受調(diào)度器控制的,因為調(diào)度器有開始和結(jié)束的的事件捺信。而RawSyscall則不受調(diào)度器控制酌媒,
RawSyscall 可能會導(dǎo)致其他正在運行的線程(協(xié)程)阻塞,調(diào)度器可能會在一段時間后運行它們迄靠,但是也有可能不會秒咨。所以,我們在進(jìn)行系統(tǒng)調(diào)用的時候掌挚,應(yīng)該極力避免使用RawSyscall雨席,除非你確定這個操作是非阻塞的。

看完了系統(tǒng)調(diào)用吠式,但是系統(tǒng)調(diào)用到底有什么用呢舅世??問的好奇徒,其實雏亚,系統(tǒng)調(diào)用的函數(shù)是操作系統(tǒng)提供的,也就是如果我們想用系統(tǒng)的功能摩钙,你就必須使用系統(tǒng)調(diào)用罢低。比如上面講的文件操作(創(chuàng)建,讀取胖笛,更新网持,刪除),網(wǎng)絡(luò)操作(監(jiān)聽端口长踊,接受請求和數(shù)據(jù)功舀,發(fā)送數(shù)據(jù)),最近很火的docker身弊,實現(xiàn)方式也是系統(tǒng)調(diào)用(NameSpace + CGroup)辟汰,簡單的在命令行執(zhí)行 echo hello列敲,也用到了系統(tǒng)調(diào)用。不信帖汞?來看看

jin@Desktop:~$ strace -c echo hello
hello
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
  0.00    0.000000           0         1           read
  0.00    0.000000           0         1           write
  0.00    0.000000           0         3           open
  0.00    0.000000           0         5           close
  0.00    0.000000           0         4           fstat
  0.00    0.000000           0         8           mmap
  0.00    0.000000           0         4           mprotect
  0.00    0.000000           0         1           munmap
  0.00    0.000000           0         3           brk
  0.00    0.000000           0         3         3 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           arch_prctl
------ ----------- ----------- --------- --------- ----------------
100.00    0.000000                    35         3 total
jin@Desktop:~$ 

看到?jīng)]有上渴,滿滿的都是系統(tǒng)調(diào)用技健。go 提供了 linux下面提供了303個系統(tǒng)調(diào)用移盆。不管你實現(xiàn)多么牛逼的功能变汪,都離不開這些系統(tǒng)調(diào)用,再牛逼的系統(tǒng)催首,也離不開cup的指令集扶踊,致“國家高新企業(yè)”中興。

參考資料:
linux syscall 中文資料:https://www.ibm.com/developerworks/cn/linux/kernel/syscall/part1/appendix.html
linux syscall 英文資料:https://syscalls.kernelgrok.com/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末郎任,一起剝皮案震驚了整個濱河市姻檀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌涝滴,老刑警劉巖绣版,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異歼疮,居然都是意外死亡杂抽,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門韩脏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來缩麸,“玉大人,你說我怎么就攤上這事赡矢『贾欤” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵吹散,是天一觀的道長弧械。 經(jīng)常有香客問我,道長空民,這世上最難降的妖魔是什么刃唐? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮界轩,結(jié)果婚禮上画饥,老公的妹妹穿的比我還像新娘。我一直安慰自己浊猾,他們只是感情好抖甘,可當(dāng)我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著葫慎,像睡著了一般衔彻。 火紅的嫁衣襯著肌膚如雪薇宠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天米奸,我揣著相機(jī)與錄音昼接,去河邊找鬼爽篷。 笑死悴晰,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的逐工。 我是一名探鬼主播铡溪,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼泪喊!你這毒婦竟也來了棕硫?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤袒啼,失蹤者是張志新(化名)和其女友劉穎哈扮,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蚓再,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡滑肉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了摘仅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片靶庙。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖娃属,靈堂內(nèi)的尸體忽然破棺而出六荒,到底是詐尸還是另有隱情,我是刑警寧澤矾端,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布掏击,位于F島的核電站,受9級特大地震影響秩铆,放射性物質(zhì)發(fā)生泄漏铐料。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一豺旬、第九天 我趴在偏房一處隱蔽的房頂上張望钠惩。 院中可真熱鬧,春花似錦族阅、人聲如沸篓跛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愧沟。三九已至蔬咬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沐寺,已是汗流浹背林艘。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留混坞,地道東北人狐援。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像究孕,于是被迫代替她去往敵國和親啥酱。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容