Make Shaker's methods goroutine safe
This commit is contained in:
parent
0c7007486a
commit
f6beed899b
7
err.go
7
err.go
|
@ -1,8 +1,15 @@
|
||||||
package tcp
|
package tcp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
// ErrTimeout indicates I/O timeout
|
// ErrTimeout indicates I/O timeout
|
||||||
var ErrTimeout = &timeoutError{}
|
var ErrTimeout = &timeoutError{}
|
||||||
|
|
||||||
|
// ErrNotInitialized occurs while the Shaker is not initialized
|
||||||
|
var ErrNotInitialized = errors.New("not initialized")
|
||||||
|
|
||||||
type timeoutError struct{}
|
type timeoutError struct{}
|
||||||
|
|
||||||
func (e *timeoutError) Error() string { return "I/O timeout" }
|
func (e *timeoutError) Error() string { return "I/O timeout" }
|
||||||
|
|
29
shaker.go
29
shaker.go
|
@ -26,12 +26,15 @@
|
||||||
// Usually this means the server will not notice the health checking
|
// Usually this means the server will not notice the health checking
|
||||||
// traffic at all, thus the act of health chekcing will not be
|
// traffic at all, thus the act of health chekcing will not be
|
||||||
// considered as some misbehaviour of client.
|
// considered as some misbehaviour of client.
|
||||||
|
//
|
||||||
|
// Shaker's methods may be called by multiple goroutines simultaneously.
|
||||||
package tcp
|
package tcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -40,12 +43,19 @@ const maxEpollEvents = 32
|
||||||
|
|
||||||
// Shaker contains an epoll instance for TCP handshake checking
|
// Shaker contains an epoll instance for TCP handshake checking
|
||||||
type Shaker struct {
|
type Shaker struct {
|
||||||
|
sync.RWMutex
|
||||||
epollFd int
|
epollFd int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init creates inner epoll instance, call this before anything else
|
// Init creates inner epoll instance, call this before anything else
|
||||||
func (s *Shaker) Init() error {
|
func (s *Shaker) Init() error {
|
||||||
var err error
|
var err error
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
if s.epollFd > 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
s.epollFd, err = syscall.EpollCreate1(0)
|
s.epollFd, err = syscall.EpollCreate1(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return os.NewSyscallError("epoll_create1", err)
|
return os.NewSyscallError("epoll_create1", err)
|
||||||
|
@ -101,13 +111,22 @@ func (s *Shaker) Test(addr string, timeout time.Duration) error {
|
||||||
|
|
||||||
// Close closes the inner epoll fd
|
// Close closes the inner epoll fd
|
||||||
func (s *Shaker) Close() error {
|
func (s *Shaker) Close() error {
|
||||||
return syscall.Close(s.epollFd)
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
if s.epollFd > 0 {
|
||||||
|
err := syscall.Close(s.epollFd)
|
||||||
|
s.epollFd = 0
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Shaker) addEpoll(fd int) error {
|
func (s *Shaker) addEpoll(fd int) error {
|
||||||
var event syscall.EpollEvent
|
var event syscall.EpollEvent
|
||||||
event.Events = syscall.EPOLLOUT
|
event.Events = syscall.EPOLLOUT
|
||||||
event.Fd = int32(fd)
|
event.Fd = int32(fd)
|
||||||
|
s.RLock()
|
||||||
|
defer s.RUnlock()
|
||||||
if err := syscall.EpollCtl(s.epollFd, syscall.EPOLL_CTL_ADD, fd, &event); err != nil {
|
if err := syscall.EpollCtl(s.epollFd, syscall.EPOLL_CTL_ADD, fd, &event); err != nil {
|
||||||
return os.NewSyscallError("epoll_ctl", err)
|
return os.NewSyscallError("epoll_ctl", err)
|
||||||
}
|
}
|
||||||
|
@ -118,7 +137,13 @@ func (s *Shaker) addEpoll(fd int) error {
|
||||||
// The boolean returned indicates whether the connect is successful
|
// The boolean returned indicates whether the connect is successful
|
||||||
func (s *Shaker) wait(fd int, timeoutMS int) (bool, error) {
|
func (s *Shaker) wait(fd int, timeoutMS int) (bool, error) {
|
||||||
var events [maxEpollEvents]syscall.EpollEvent
|
var events [maxEpollEvents]syscall.EpollEvent
|
||||||
nevents, err := syscall.EpollWait(s.epollFd, events[:], timeoutMS)
|
s.RLock()
|
||||||
|
epollFd := s.epollFd
|
||||||
|
if epollFd <= 0 {
|
||||||
|
return false, ErrNotInitialized
|
||||||
|
}
|
||||||
|
s.RUnlock()
|
||||||
|
nevents, err := syscall.EpollWait(epollFd, events[:], timeoutMS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, os.NewSyscallError("epoll_wait", err)
|
return false, os.NewSyscallError("epoll_wait", err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue