@@ -4,11 +4,10 @@ package sync
44
55import (
66 "bytes"
7+ "github.com/funny/debug"
78 "github.com/funny/goid"
8- "runtime/pprof"
99 "strconv"
1010 "sync"
11- "sync/atomic"
1211)
1312
1413type Mutex struct {
@@ -17,9 +16,9 @@ type Mutex struct {
1716}
1817
1918func (m * Mutex ) Lock () {
20- holder := m .mointor .wait ()
19+ holder , holderStack := m .mointor .wait ()
2120 m .Mutex .Lock ()
22- m .mointor .using (holder )
21+ m .mointor .using (holder , holderStack )
2322}
2423
2524func (m * Mutex ) Unlock () {
@@ -51,70 +50,58 @@ var (
5150 globalMutex = new (sync.Mutex )
5251 waitTargets = make (map [int32 ]* mointor )
5352 goroutineBegin = []byte ("goroutine " )
54- goroutineEnd = []byte ( " \n \n " )
53+ newline = []byte { '\n' }
5554)
5655
5756type mointor struct {
58- holder int32
57+ holder int32
58+ holderStack debug.StackInfo
5959}
6060
61- func (m * mointor ) wait () int32 {
61+ func (m * mointor ) wait () ( int32 , debug. StackInfo ) {
6262 globalMutex .Lock ()
6363 defer globalMutex .Unlock ()
6464
6565 holder := goid .Get ()
66+ holderStack := debug .StackTrace (3 , 0 )
6667 waitTargets [holder ] = m
6768
68- m .verify (holder , []int32 {holder })
69- return holder
69+ m .verify ([]* mointor {{holder , holderStack }})
70+
71+ return holder , holderStack
7072}
7173
72- func (m * mointor ) verify (holder int32 , holderLink []int32 ) {
74+ func (m * mointor ) verify (holderLink []* mointor ) {
7375 if m .holder != 0 {
7476 // deadlock detected
75- if m .holder == holder {
76- // dump stack
77- stackBuf := new (bytes.Buffer )
78- prof := pprof .Lookup ("goroutine" )
79- prof .WriteTo (stackBuf , 2 )
80- stack := stackBuf .Bytes ()
81-
82- // match goroutines
77+ if m .holder == holderLink [0 ].holder {
8378 buf := new (bytes.Buffer )
8479 buf .WriteString ("[DEAD LOCK]\n " )
85- buf .Write (traceGoroutine (holder , stack ))
86- buf .Write (goroutineEnd )
8780 for i := 0 ; i < len (holderLink ); i ++ {
88- buf .Write (traceGoroutine (holderLink [i ], stack ))
89- buf .Write (goroutineEnd )
81+ buf .Write (goroutineBegin )
82+ buf .WriteString (strconv .Itoa (int (holderLink [i ].holder )))
83+ buf .Write (newline )
84+ buf .Write (holderLink [i ].holderStack .Bytes (" " ))
9085 }
9186 panic (DeadlockError (buf .String ()))
9287 }
9388 // the lock holder is waiting for another lock
9489 if waitTarget , exists := waitTargets [m .holder ]; exists {
95- waitTarget .verify (holder , append (holderLink , m . holder ))
90+ waitTarget .verify (append (holderLink , m ))
9691 }
9792 }
9893}
9994
100- func (m * mointor ) using (holder int32 ) {
95+ func (m * mointor ) using (holder int32 , holderStack debug. StackInfo ) {
10196 globalMutex .Lock ()
10297 defer globalMutex .Unlock ()
10398
10499 delete (waitTargets , holder )
105- atomic .StoreInt32 (& m .holder , holder )
100+ m .holder = holder
101+ m .holderStack = holderStack
106102}
107103
108104func (m * mointor ) release () {
109- atomic .StoreInt32 (& m .holder , 0 )
110- }
111-
112- func traceGoroutine (id int32 , stack []byte ) []byte {
113- head := append (strconv .AppendInt (goroutineBegin , int64 (id ), 10 ), ' ' )
114- begin := bytes .Index (stack , head )
115- end := bytes .Index (stack [begin :], goroutineEnd )
116- if end == - 1 {
117- end = len (stack ) - begin
118- }
119- return stack [begin : begin + end ]
105+ m .holder = 0
106+ m .holderStack = nil
120107}
0 commit comments