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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy