Skip to content

Instantly share code, notes, and snippets.

@robbmanes
Created February 28, 2025 20:54
Show Gist options
  • Save robbmanes/24116e46ccf518c9d4c7041ba290d458 to your computer and use it in GitHub Desktop.
Save robbmanes/24116e46ccf518c9d4c7041ba290d458 to your computer and use it in GitHub Desktop.
Quick Delve Golang Example

Example of what a running Go program looks like from https://go.dev/tour/concurrency/9.

Using the delve debugger: https://github.com/go-delve/delve

Use delve to compile and debug:

$ dlv debug mutex-counter.go

(dlv) l main.main:3
Showing /home/rmanes/Downloads/mutex-counter.go:34 (PC: 0x49b82f)
    29: }
    30:
    31: func main() {
    32:         c := SafeCounter{v: make(map[string]int)}
    33:         for i := 0; i < 1000; i++ {
    34:                 go c.Inc("somekey")
    35:         }
    36:
    37:         time.Sleep(time.Second)
    38:         fmt.Println(c.Value("somekey"))
    39: }

Set a breakpoint and continue to stop our process:

(dlv) b /home/rmanes/Downloads/mutex-counter.go:37
Breakpoint 1 set at 0x49b899 for main.main() ./mutex-counter.go:37

(dlv) c
> [Breakpoint 1] main.main() ./mutex-counter.go:37 (hits goroutine(1):1 total:1) (PC: 0x49b899)
    32:         c := SafeCounter{v: make(map[string]int)}
    33:         for i := 0; i < 1000; i++ {
    34:                 go c.Inc("somekey")
    35:         }
    36:
=>  37:         time.Sleep(time.Second)
    38:         fmt.Println(c.Value("somekey"))
    39: }
    40:

Check all goroutines:

(dlv) goroutines
* Goroutine 1 - User: ./mutex-counter.go:37 main.main (0x49b899) (thread 3871629)
  Goroutine 17 - User: /usr/lib/golang/src/runtime/proc.go:403 runtime.gopark (0x43ce1c) [force gc (idle)]
  Goroutine 18 - User: /usr/lib/golang/src/runtime/proc.go:403 runtime.gopark (0x43ce1c) [GC sweep wait]
  Goroutine 19 - User: /usr/lib/golang/src/runtime/proc.go:403 runtime.gopark (0x43ce1c) [GC scavenge wait]
  Goroutine 20 - User: /usr/lib/golang/src/runtime/proc.go:403 runtime.gopark (0x43ce1c) [finalizer wait]
  Goroutine 924 - User: /usr/lib/golang/src/runtime/sema.go:77 sync.runtime_SemacquireMutex (0x468005) (thread 3871649)
  Goroutine 1020 - User: ./mutex-counter.go:34 main.main.gowrap1 (0x49b960)
[7 goroutines]

Switch to a goroutine running in the for loop:

(dlv) goroutine 924
Switched from 1020 to 924 (thread 3871649)

(dlv) goroutine
Thread 3871649 at /usr/lib/golang/src/runtime/proc.go:1122
Goroutine 924:
        Runtime: /usr/lib/golang/src/runtime/proc.go:1122 runtime.casgstatus (0x43ea31)
        User: /usr/lib/golang/src/runtime/sema.go:77 sync.runtime_SemacquireMutex (0x468005)
        Go: ./mutex-counter.go:34 main.main (0x49b890)
        Start: ./mutex-counter.go:16 main.(*SafeCounter).Inc (0x49b520)

Stack for that goroutine:

(dlv) bt
 0  0x000000000043ea31 in runtime.casgstatus
    at /usr/lib/golang/src/runtime/proc.go:1122
 1  0x0000000000441bfb in runtime.execute
    at /usr/lib/golang/src/runtime/proc.go:3107
 2  0x000000000044385e in runtime.schedule
    at /usr/lib/golang/src/runtime/proc.go:3918
 3  0x00000000004442b8 in runtime.goexit0
    at /usr/lib/golang/src/runtime/proc.go:4181
 4  0x000000000046930e in runtime.mcall
    at /usr/lib/golang/src/runtime/asm_amd64.s:458
 5  0x000000000043ce1c in runtime.gopark
    at /usr/lib/golang/src/runtime/proc.go:402
 6  0x000000000043cea5 in runtime.goparkunlock
    at /usr/lib/golang/src/runtime/proc.go:408
 7  0x000000000044d92d in runtime.semacquire1
    at /usr/lib/golang/src/runtime/sema.go:160
 8  0x0000000000468005 in sync.runtime_SemacquireMutex
    at /usr/lib/golang/src/runtime/sema.go:77
 9  0x000000000047d2cd in sync.(*Mutex).lockSlow
    at /usr/lib/golang/src/sync/mutex.go:171
10  0x000000000047d065 in sync.(*Mutex).Lock
    at /usr/lib/golang/src/sync/mutex.go:90
11  0x000000000049b549 in main.(*SafeCounter).Inc
    at ./mutex-counter.go:17
12  0x000000000049b991 in main.main.gowrap1
    at ./mutex-counter.go:34
13  0x000000000046b1c1 in runtime.goexit
    at /usr/lib/golang/src/runtime/asm_amd64.s:1695

Check the frame which is trying to claim a mutex (some other goroutine currently has it):

(dlv) frame 11
> [Breakpoint 1] main.main() ./mutex-counter.go:37 (hits goroutine(1):1 total:1) (PC: 0x49b899)
> runtime.casgstatus() /usr/lib/golang/src/runtime/proc.go:1122 (PC: 0x43ea31)
Warning: debugging optimized function
Frame 11: ./mutex-counter.go:17 (PC: 49b549)
    12:         v  map[string]int
    13: }
    14:
    15: // Inc increments the counter for the given key.
    16: func (c *SafeCounter) Inc(key string) {
=>  17:         c.mu.Lock()
    18:         // Lock so only one goroutine at a time can access the map c.v.
    19:         c.v[key]++
    20:         c.mu.Unlock()
    21: }
    22:

Check the struct and the mutex in it:

(dlv) p c
(*main.SafeCounter)(0xc00008c270)
*main.SafeCounter {
        mu: sync.Mutex {state: 2, sema: 1},
        v: map[string]int [
                "somekey": 998,
        ],}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment