いろいろ備忘録日記

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

Goメモ-270 (runtime.Caller()とruntime.Callers()のちょっとした違い)

概要

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

runtime.Caller()runtime.Callers() で skip に 0 を渡したときの結果が少しだけ異なるので、忘れないうちにメモメモ。

runtime.Caller() の方は、0 を指定すると左記の関数を呼び出した箇所からスタックトレースが取得できるのに対して

runtime.Callers() の方は、0 を指定すると runtime.Callers() 自身の呼び出しからスタックトレースが取得できる。

サンプル

runtime.Caller

package runtimes

import (
    "runtime"
    "strings"

    "github.com/devlights/gomy/output"
)

// Caller は、 runtime.Caller() のサンプルです.
//
// runtime.Caller() は、呼び出し元のgoroutineのスタックにある関数呼び出しに関するファイルおよび行番号情報を報告してくれる.
//
// # REFERENCES
//   - https://pkg.go.dev/runtime@go1.19.3#Caller
func Caller() error {
    var (
        programCounter uintptr
        file           string
        line           int
        ok             bool
        sentinel       = "try-golang"
    )

    for skip := 0; ; skip++ {
        // skip = 0 は、runtime.Caller() の場合は、この関数を呼び出した部分になる.
        // runtime.Callers() の場合は、runtime.Callers() 自体を表す.
        // 0 の意味が少し違うことに注意.
        programCounter, file, line, ok = runtime.Caller(skip)
        if !ok {
            break
        }

        if !strings.Contains(file, sentinel) {
            break
        }

        output.Stdoutf("[runtime.Caller]", "%v\t%v\t%v\n", programCounter, file, line)
    }

    return nil
}

実行すると以下ようになります。

gitpod /workspace/try-golang (master) $ task
task: [run] go run . -onetime

ENTER EXAMPLE NAME: runtime_caller

[Name] "runtime_caller"
[runtime.Caller]     7941654    /workspace/try-golang/examples/basic/runtimes/caller.go 29
[runtime.Caller]     8978018    /workspace/try-golang/runner/exec.go    52
[runtime.Caller]     8980078    /workspace/try-golang/runner/loop.go    126
[runtime.Caller]     8979303    /workspace/try-golang/runner/loop.go    86
[runtime.Caller]     8982849    /workspace/try-golang/cmd/root.go       66
[runtime.Caller]     8983446    /workspace/try-golang/main.go   6


[Elapsed] 183.92µs

runtime.Callers

package runtimes

import (
    "runtime"

    "github.com/devlights/gomy/output"
)

// Callers は、 runtime.Callers() のサンプルです。
//
// # REFERENCES
//   - https://pkg.go.dev/runtime@go1.19.3#Callers
func Callers() error {
    var (
        skip       = 0
        pc         = make([]uintptr, 10)
        frameCount = runtime.Callers(skip, pc)
        frames     = runtime.CallersFrames(pc[:frameCount])
    )

    output.Stdoutf("[runtime.CallersFrames]", "frames=%v\n", frameCount)

    // *runtime.Frames を イテレーション して値を取得
    for {
        frame, more := frames.Next()

        output.Stdoutf("[runtime.Frames]", "%v\t%v\t%v\n", frame.PC, frame.File, frame.Line)

        if !more {
            break
        }
    }

    return nil
}

実行すると以下のようになります。

gitpod /workspace/try-golang (master) $ task
task: [run] go run . -onetime

ENTER EXAMPLE NAME: runtime_callers

[Name] "runtime_callers"
[runtime.CallersFrames] frames=9
[runtime.Frames]     7941844    /home/gitpod/go/src/runtime/extern.go   247
[runtime.Frames]     7941826    /workspace/try-golang/examples/basic/runtimes/callers.go        17
[runtime.Frames]     8978018    /workspace/try-golang/runner/exec.go    52
[runtime.Frames]     8980078    /workspace/try-golang/runner/loop.go    126
[runtime.Frames]     8979044    /workspace/try-golang/runner/loop.go    79
[runtime.Frames]     8982849    /workspace/try-golang/cmd/root.go       66
[runtime.Frames]     8983446    /workspace/try-golang/main.go   6
[runtime.Frames]     4438865    /home/gitpod/go/src/runtime/proc.go     250
[runtime.Frames]     4633696    /home/gitpod/go/src/runtime/asm_amd64.s 1594


[Elapsed] 164.88µs

確かに runtime.Callers の結果には一番最初に 7941844 /home/gitpod/go/src/runtime/extern.go 247 が出てきてますね。

参考情報

Go言語による並行処理

Go言語による並行処理

Amazon


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

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