File tree 3 files changed +50
-2
lines changed
3 files changed +50
-2
lines changed Original file line number Diff line number Diff line change @@ -26,6 +26,9 @@ type FD struct {
26
26
// Writev cache.
27
27
iovecs * []syscall.Iovec
28
28
29
+ // Semaphore signaled when file is closed.
30
+ csema uint32
31
+
29
32
// Whether this is a streaming descriptor, as opposed to a
30
33
// packet-based descriptor like a UDP socket. Immutable.
31
34
IsStream bool
@@ -62,6 +65,7 @@ func (fd *FD) destroy() error {
62
65
fd .pd .close ()
63
66
err := CloseFunc (fd .Sysfd )
64
67
fd .Sysfd = - 1
68
+ runtime_Semrelease (& fd .csema )
65
69
return err
66
70
}
67
71
@@ -79,7 +83,11 @@ func (fd *FD) Close() error {
79
83
fd .pd .evict ()
80
84
// The call to decref will call destroy if there are no other
81
85
// references.
82
- return fd .decref ()
86
+ err := fd .decref ()
87
+ // Wait until the descriptor is closed. If this was the only
88
+ // reference, it is already closed.
89
+ runtime_Semacquire (& fd .csema )
90
+ return err
83
91
}
84
92
85
93
// Shutdown wraps the shutdown network call.
Original file line number Diff line number Diff line change @@ -278,6 +278,9 @@ type FD struct {
278
278
readbyte []byte // buffer to hold decoding of readuint16 from utf16 to utf8
279
279
readbyteOffset int // readbyte[readOffset:] is yet to be consumed with file.Read
280
280
281
+ // Semaphore signaled when file is closed.
282
+ csema uint32
283
+
281
284
skipSyncNotif bool
282
285
283
286
// Whether this is a streaming descriptor, as opposed to a
@@ -399,6 +402,7 @@ func (fd *FD) destroy() error {
399
402
err = CloseFunc (fd .Sysfd )
400
403
}
401
404
fd .Sysfd = syscall .InvalidHandle
405
+ runtime_Semrelease (& fd .csema )
402
406
return err
403
407
}
404
408
@@ -410,7 +414,11 @@ func (fd *FD) Close() error {
410
414
}
411
415
// unblock pending reader and writer
412
416
fd .pd .evict ()
413
- return fd .decref ()
417
+ err := fd .decref ()
418
+ // Wait until the descriptor is closed. If this was the only
419
+ // reference, it is already closed.
420
+ runtime_Semacquire (& fd .csema )
421
+ return err
414
422
}
415
423
416
424
// Shutdown wraps the shutdown network call.
Original file line number Diff line number Diff line change @@ -13,6 +13,7 @@ import (
13
13
"runtime"
14
14
"syscall"
15
15
"testing"
16
+ "time"
16
17
)
17
18
18
19
func (ln * TCPListener ) port () string {
@@ -696,3 +697,34 @@ func multicastRIBContains(ip IP) (bool, error) {
696
697
}
697
698
return false , nil
698
699
}
700
+
701
+ // Issue 21856.
702
+ func TestClosingListener (t * testing.T ) {
703
+ listener , err := Listen ("tcp" , ":0" )
704
+ if err != nil {
705
+ t .Fatal (err )
706
+ }
707
+ addr := listener .Addr ()
708
+
709
+ go func () {
710
+ for {
711
+ c , err := listener .Accept ()
712
+ if err != nil {
713
+ return
714
+ }
715
+ c .Close ()
716
+ }
717
+ }()
718
+
719
+ // Let the goroutine start. We don't sleep long: if the
720
+ // goroutine doesn't start, the test will pass without really
721
+ // testing anything, which is OK.
722
+ time .Sleep (time .Millisecond )
723
+
724
+ listener .Close ()
725
+
726
+ _ , err = Listen ("tcp" , addr .String ())
727
+ if err != nil {
728
+ t .Error (err )
729
+ }
730
+ }
You can’t perform that action at this time.
0 commit comments