Skip to content

Commit 9dc2873

Browse files
committed
rewrite
1 parent 7f8a89e commit 9dc2873

File tree

4 files changed

+255
-160
lines changed

4 files changed

+255
-160
lines changed

mutex.go

Lines changed: 0 additions & 118 deletions
This file was deleted.

mutex_test.go

Lines changed: 0 additions & 42 deletions
This file was deleted.

sync.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package sync
2+
3+
import (
4+
"bytes"
5+
"container/list"
6+
"fmt"
7+
"github.com/funny/goid"
8+
"runtime/pprof"
9+
"strconv"
10+
"sync"
11+
"sync/atomic"
12+
)
13+
14+
var WatchDeadLock int32 = 1
15+
16+
var (
17+
lockMutex = new(sync.Mutex)
18+
waitTargets = make(map[int32]*mutexInfo)
19+
goroutineBegin = []byte("goroutine ")
20+
goroutineEnd = []byte("\n\n")
21+
)
22+
23+
func goroutine(id int32, stack []byte) []byte {
24+
head := append(strconv.AppendInt(goroutineBegin, int64(id), 10), ' ')
25+
begin := bytes.Index(stack, head)
26+
end := bytes.Index(stack[begin:], goroutineEnd)
27+
if end == -1 {
28+
end = len(stack) - begin
29+
}
30+
return stack[begin : begin+end]
31+
}
32+
33+
type mutexInfo struct {
34+
holder int32
35+
waiting *list.List
36+
watch bool
37+
}
38+
39+
func (lock *mutexInfo) wait() (int32, *list.Element) {
40+
lockMutex.Lock()
41+
defer lockMutex.Unlock()
42+
43+
holder := goid.Get()
44+
waitTargets[holder] = lock
45+
46+
if lock.waiting == nil {
47+
lock.waiting = list.New()
48+
}
49+
50+
lock.verify(holder, []*mutexInfo{lock})
51+
52+
return holder, lock.waiting.PushBack(holder)
53+
}
54+
55+
func (lock *mutexInfo) verify(holder int32, link []*mutexInfo) {
56+
if lock.holder != 0 {
57+
if lock.holder == holder {
58+
stackBuf := new(bytes.Buffer)
59+
prof := pprof.Lookup("goroutine")
60+
prof.WriteTo(stackBuf, 2)
61+
stack := stackBuf.Bytes()
62+
63+
buf := new(bytes.Buffer)
64+
fmt.Fprintln(buf, "[DEAD LOCK]\n")
65+
fmt.Fprintf(buf, "%s\n\n", goroutine(holder, stack))
66+
for i := 0; i < len(link); i++ {
67+
fmt.Fprintf(buf, "%s\n\n", goroutine(link[i].holder, stack))
68+
}
69+
panic(buf.String())
70+
}
71+
if waitTarget, exists := waitTargets[lock.holder]; exists {
72+
waitTarget.verify(holder, append(link, waitTarget))
73+
}
74+
}
75+
}
76+
77+
func (lock *mutexInfo) using(holder int32, elem *list.Element) {
78+
lockMutex.Lock()
79+
defer lockMutex.Unlock()
80+
81+
delete(waitTargets, holder)
82+
83+
atomic.StoreInt32(&lock.holder, holder)
84+
lock.waiting.Remove(elem)
85+
}
86+
87+
func (lock *mutexInfo) release() {
88+
atomic.StoreInt32(&lock.holder, 0)
89+
}
90+
91+
type Mutex struct {
92+
mutexInfo
93+
sync.Mutex
94+
}
95+
96+
func (m *Mutex) Lock() {
97+
m.mutexInfo.watch = atomic.LoadInt32(&WatchDeadLock) == 1
98+
99+
if m.mutexInfo.watch {
100+
holder, elem := m.mutexInfo.wait()
101+
m.Mutex.Lock()
102+
m.mutexInfo.using(holder, elem)
103+
} else {
104+
m.Mutex.Lock()
105+
}
106+
}
107+
108+
func (m *Mutex) Unlock() {
109+
if m.mutexInfo.watch {
110+
m.mutexInfo.release()
111+
}
112+
m.Mutex.Unlock()
113+
}

0 commit comments

Comments
 (0)