いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

Goメモ-580 (RawSyscall関数を使ってシステムコールの呼び出し)(syscall.RawSyscall, unix.RawSyscall, 絶対にブロッキングしないシステムコール用)

関連記事

GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ

概要

以下、自分用のメモです。

syscallパッケージやunixには RawSyscall という関数が用意されています。

これはsyscall(2)のラッパーで、かつ、Goランタイムの制御を全く行わない関数です。

なので、Syscall()Syscall6()と違って、「絶対にブロッキングしないシステムコール」に対してのみ利用するべき関数となります。

ブロッキングされないシステムコールとしては getpid(2)getcpu(2)などがあります。

その中でも getcpu(2) は、glibcにもラップされていないシステムコールなので Syscall のサンプルにも丁度良いですね。

サンプル(間接システムコールの呼び出し)

main.go

package main

import (
    "fmt"
    "log"
    "unsafe"

    "golang.org/x/sys/unix"
)

func main() {
    log.SetFlags(0)

    if err := run(); err != nil {
        log.Fatal(err)
    }
}

func run() error {
    var (
        // syscall(2)のための引数とポインタ情報
        trap    = uintptr(unix.SYS_GETCPU)
        cpu     uint32
        node    uint32
        ptrCpu  = uintptr(unsafe.Pointer(&cpu))
        ptrNode = uintptr(unsafe.Pointer(&node))

        // syscall(2)の結果
        r1    uintptr
        errno unix.Errno
        err   error
    )
    // getcpu(2)はブロッキングしない単純なシステムコールなのでRawSyscall()を使っても問題無い
    r1, _, errno = unix.RawSyscall(trap, ptrCpu, ptrNode, uintptr(0))
    if errno != unix.Errno(0) {
        err = errno
        return err
    }

    if int(r1) < 0 {
        return fmt.Errorf("getcpu syscall returned %d", r1)
    }

    log.Printf("CPU: %d, NUMA: %d", cpu, node)

    return nil
}

Taskfile.yml

# https://taskfile.dev

version: '3'

tasks:
  default:
    cmds:
      - rm -f ./app
      - go build -o app .
      - ./app

実行結果

$ task
task: [default] rm -f ./app
task: [default] go build -o app .
task: [default] ./app
CPU: 10, NUMA: 0

参考情報

try-golang/examples/syscall/syscall_getcpu at main · devlights/try-golang · GitHub

Goのおすすめ書籍


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。