File tree 4 files changed +58
-9
lines changed
4 files changed +58
-9
lines changed Original file line number Diff line number Diff line change @@ -252,7 +252,7 @@ func (suit *LinkedBlockDequeTestSuite) TestInterrupt() {
252
252
for i := 0 ; i < 2 ; i ++ {
253
253
_ , e := suit .deque .TakeFirst (ctx )
254
254
_ , ok := e .(* InterruptedErr )
255
- suit .True (ok , "expect InterruptedErr bug get %v" , reflect .TypeOf (e ))
255
+ suit .True (ok , "expect InterruptedErr but get %v" , reflect .TypeOf (e ))
256
256
suit .NotNil (e .Error ())
257
257
}
258
258
wait .Wait ()
@@ -502,3 +502,21 @@ func (suit *LinkedBlockDequeTestSuite) TestHasTakeWaiters() {
502
502
suit .Equal (1 , val )
503
503
suit .False (suit .deque .HasTakeWaiters ())
504
504
}
505
+
506
+ // https://github.com/jolestar/go-commons-pool/issues/44
507
+ func (suit * LinkedBlockDequeTestSuite ) TestDeadLock () {
508
+ ctx := context .Background ()
509
+ suit .deque = NewDeque (1 )
510
+ suit .deque .PutFirst (ctx , 1 )
511
+ count := 1000000
512
+ testWG := sync.WaitGroup {}
513
+ testWG .Add (count )
514
+ for i := 0 ; i < count ; i ++ {
515
+ o := suit .NoErrorWithResult (suit .deque .PollFirstWithContext (ctx ))
516
+ go func () {
517
+ suit .deque .PutFirst (ctx , o )
518
+ testWG .Done ()
519
+ }()
520
+ }
521
+ testWG .Wait ()
522
+ }
Original file line number Diff line number Diff line change @@ -13,11 +13,12 @@ type TimeoutCond struct {
13
13
hasWaiters uint64
14
14
L sync.Locker
15
15
signal chan int
16
+ condL sync.RWMutex
16
17
}
17
18
18
19
// NewTimeoutCond return a new TimeoutCond
19
20
func NewTimeoutCond (l sync.Locker ) * TimeoutCond {
20
- cond := TimeoutCond {L : l , signal : make (chan int , 0 ) }
21
+ cond := TimeoutCond {L : l , signal : make (chan int , 1 ), condL : sync. RWMutex {} }
21
22
return & cond
22
23
}
23
24
@@ -45,8 +46,11 @@ func (cond *TimeoutCond) HasWaiters() bool {
45
46
// Wait waits for a signal, or for the context do be done. Returns true if signaled.
46
47
func (cond * TimeoutCond ) Wait (ctx context.Context ) bool {
47
48
cond .addWaiter ()
49
+
50
+ cond .condL .RLock ()
48
51
//copy signal in lock, avoid data race with Interrupt
49
52
ch := cond .signal
53
+ cond .condL .RUnlock ()
50
54
//wait should unlock mutex, if not will cause deadlock
51
55
cond .L .Unlock ()
52
56
defer cond .removeWaiter ()
@@ -62,16 +66,18 @@ func (cond *TimeoutCond) Wait(ctx context.Context) bool {
62
66
63
67
// Signal wakes one goroutine waiting on c, if there is any.
64
68
func (cond * TimeoutCond ) Signal () {
69
+ cond .condL .RLock ()
65
70
select {
66
71
case cond .signal <- 1 :
67
72
default :
68
73
}
74
+ cond .condL .RUnlock ()
69
75
}
70
76
71
77
// Interrupt goroutine wait on this TimeoutCond
72
78
func (cond * TimeoutCond ) Interrupt () {
73
- cond .L .Lock ()
74
- defer cond .L .Unlock ()
79
+ cond .condL .Lock ()
80
+ defer cond .condL .Unlock ()
75
81
close (cond .signal )
76
82
cond .signal = make (chan int , 0 )
77
83
}
Original file line number Diff line number Diff line change @@ -90,10 +90,10 @@ func TestTimeoutCondWaitTimeoutNotify(t *testing.T) {
90
90
wait := sync.WaitGroup {}
91
91
wait .Add (2 )
92
92
ch := make (chan time.Duration , 1 )
93
- timeout := 2 * time .Second
93
+ timeout := 5 * time .Second
94
94
go func () {
95
95
begin := time .Now ()
96
- obj .lockAndWaitWithTimeout (time . Duration ( timeout ) * time .Millisecond )
96
+ obj .lockAndWaitWithTimeout (timeout * time .Millisecond )
97
97
elapsed := time .Since (begin )
98
98
ch <- elapsed
99
99
wait .Done ()
@@ -196,7 +196,7 @@ func TestInterrupted(t *testing.T) {
196
196
wait .Wait ()
197
197
for i := 0 ; i < count ; i ++ {
198
198
b := <- ch
199
- assert .True (t , b , "expect %v interrupted bug get false" , i )
199
+ assert .True (t , b , "expect %v interrupted but get false" , i )
200
200
}
201
201
}
202
202
@@ -222,7 +222,7 @@ func TestInterruptedWithTimeout(t *testing.T) {
222
222
wait .Wait ()
223
223
for i := 0 ; i < count ; i ++ {
224
224
b := <- ch
225
- assert .True (t , b , "expect %v interrupted bug get false" , i )
225
+ assert .True (t , b , "expect %v interrupted but get false" , i )
226
226
}
227
227
}
228
228
Original file line number Diff line number Diff line change @@ -1317,7 +1317,6 @@ func (suit *PoolTestSuite) TestEvictionSoftMinIdle() {
1317
1317
suit .Equal (0 , suit .pool .GetNumIdle (), "Idle count different than expected." )
1318
1318
}
1319
1319
1320
-
1321
1320
func (suit * PoolTestSuite ) TestEvictionNegativeIdleTime () {
1322
1321
suit .pool .Config .MaxIdle = 5
1323
1322
suit .pool .Config .MaxTotal = 5
@@ -2070,6 +2069,32 @@ func (suit *PoolTestSuite) TestValueFactory() {
2070
2069
})
2071
2070
}
2072
2071
2072
+ // https://github.com/jolestar/go-commons-pool/issues/44
2073
+ func (suit * PoolTestSuite ) TestDeadLock () {
2074
+ ctx := context .Background ()
2075
+ suit .pool .Config .MinIdle = 1
2076
+ suit .pool .Config .MaxIdle = 1
2077
+ suit .pool .Config .MaxTotal = 1
2078
+ count := 1000000
2079
+ testWG := sync.WaitGroup {}
2080
+ testWG .Add (count )
2081
+
2082
+ for i := 0 ; i < count ; i ++ {
2083
+ obj , err := suit .pool .BorrowObject (ctx )
2084
+ if err != nil {
2085
+ panic (err )
2086
+ }
2087
+ go func (obj interface {}) {
2088
+ err = suit .pool .ReturnObject (ctx , obj )
2089
+ if err != nil {
2090
+ panic (err )
2091
+ }
2092
+ testWG .Done ()
2093
+ }(obj )
2094
+ }
2095
+ testWG .Wait ()
2096
+ }
2097
+
2073
2098
var perf bool
2074
2099
2075
2100
func init () {
You can’t perform that action at this time.
0 commit comments