func (m *Monitor) markDown(err error) {
	m.lock.Lock()
	defer m.lock.Unlock()
	if m.down {
		m.failures = m.failLimit
		return
	}
	m.failures++
	if m.failures < m.failLimit {
		return
	}
	m.down = true
	m.notifyCh <- HostStatus{Host: m.host, Down: m.down, Reason: err}
}
markDown does nothing if the host is already down. If it's up, in increases the failure count
changes the status to down and then sends a channel notification that the host is down.
package pingd
import (
	"sync"
	"time"
)
type PingFunc func(host string) (up bool, err error)
type Monitor struct {
	running   *sync.Mutex  
	lock      *sync.Mutex  
	ping      PingFunc
	host      string
	down      bool
	failures  int
	failLimit int
	interval  time.Duration
	stop      bool
	notifyCh  chan<- HostStatus
}
func NewMonitor(status HostStatus, ping PingFunc, notifyCh chan<- HostStatus) *Monitor {
	h := Monitor{
		ping:     ping,
		host:     status.Host,
		down:     status.Down,
		notifyCh: notifyCh,
		running:  &sync.Mutex{},
		lock:     &sync.Mutex{},
	}
	return &h
}
func (m *Monitor) Start(interval time.Duration, failLimit int) {
	m.running.Lock()
	defer m.running.Unlock()
	defer m.lock.Unlock()
	m.lock.Lock()
	m.interval = interval
	m.failLimit = failLimit
	m.stop = false
	m.lock.Unlock()
	ticker := time.NewTicker(interval)
	defer ticker.Stop()
	for _ = range ticker.C {
		m.lock.Lock()
		if m.stop {
			return
		}
		m.lock.Unlock()
		if up, err := m.ping(m.host); up {
			m.markUp()
		} else {
			m.markDown(err)
		}
	}
}
func (m *Monitor) Stop() {
	m.lock.Lock()
	defer m.lock.Unlock()
	m.stop = true
}
func (m *Monitor) markUp() {
	m.lock.Lock()
	defer m.lock.Unlock()
	if !m.down {
		m.failures = 0
		return
	}
	m.failures--
	if m.failures > 0 {
		return
	}
	m.down = false
	m.notifyCh <- HostStatus{Host: m.host, Down: m.down}
}