OSDN Git Service

Merge branch 'bvm' into demo
[bytom/bytom.git] / blockchain / pseudohsm / watch.go
1 // Copyright 2016 The go-ethereum Authors
2 // This file is part of the go-ethereum library.
3 //
4 // The go-ethereum library is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Lesser General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // The go-ethereum library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Lesser General Public License for more details.
13 //
14 // You should have received a copy of the GNU Lesser General Public License
15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16
17 // +build darwin,!ios freebsd linux,!arm64 netbsd solaris windows
18
19 package pseudohsm
20
21 import (
22     "time"
23     "fmt"
24     "github.com/rjeczalik/notify"
25 )
26
27 type watcher struct {
28     ac       *addrCache
29     starting bool
30     running  bool
31     ev       chan notify.EventInfo
32     quit     chan struct{}
33 }
34
35 func newWatcher(ac *addrCache) *watcher {
36     return &watcher{
37         ac:   ac,
38         ev:   make(chan notify.EventInfo, 10),
39         quit: make(chan struct{}),
40     }
41 }
42
43 // starts the watcher loop in the background.
44 // Start a watcher in the background if that's not already in progress.
45 // The caller must hold w.ac.mu.
46 func (w *watcher) start() {
47     if w.starting || w.running {
48         return
49     }
50     w.starting = true
51     go w.loop()
52 }
53
54 func (w *watcher) close() {
55     close(w.quit)
56 }
57
58 func (w *watcher) loop() {
59     defer func() {
60         w.ac.mu.Lock()
61         w.running = false
62         w.starting = false
63         w.ac.mu.Unlock()
64     }()
65
66     err := notify.Watch(w.ac.keydir, w.ev, notify.All)
67     if err != nil {
68         fmt.Printf("can't watch %s: %v", w.ac.keydir, err)
69         return
70     }
71     defer notify.Stop(w.ev)
72     fmt.Printf("now watching %s", w.ac.keydir)
73     defer fmt.Printf("no longer watching %s", w.ac.keydir)
74
75     w.ac.mu.Lock()
76     w.running = true
77     w.ac.mu.Unlock()
78
79     // Wait for file system events and reload.
80     // When an event occurs, the reload call is delayed a bit so that
81     // multiple events arriving quickly only cause a single reload.
82     var (
83         debounce          = time.NewTimer(0)
84         debounceDuration  = 500 * time.Millisecond
85         inCycle, hadEvent bool
86     )
87     defer debounce.Stop()
88     for {
89         select {
90         case <-w.quit:
91             return
92         case <-w.ev:
93             if !inCycle {
94                 debounce.Reset(debounceDuration)
95                 inCycle = true
96             } else {
97                 hadEvent = true
98             }
99         case <-debounce.C:
100             w.ac.mu.Lock()
101             w.ac.reload()
102             w.ac.mu.Unlock()
103             if hadEvent {
104                 debounce.Reset(debounceDuration)
105                 inCycle, hadEvent = true, false
106             } else {
107                 inCycle, hadEvent = false, false
108             }
109         }
110     }
111 }