• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 12231215572

09 Dec 2024 07:52AM UTC coverage: 58.805% (+9.0%) from 49.807%
12231215572

push

github

web-flow
Merge pull request #9338 from yyforyongyu/fix-invoice-htlcs-order

lnrpc: sort `Invoice.HTLCs` based on `HtlcIndex`

3 of 3 new or added lines in 1 file covered. (100.0%)

400 existing lines in 30 files now uncovered.

133172 of 226462 relevant lines covered (58.81%)

19432.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.74
/signal/signal.go
1
// Copyright (c) 2013-2017 The btcsuite developers
2
// Copyright (c) 2015-2016 The Decred developers
3
// Heavily inspired by https://github.com/btcsuite/btcd/blob/master/signal.go
4
// Copyright (C) 2015-2022 The Lightning Network Developers
5

6
package signal
7

8
import (
9
        "errors"
10
        "fmt"
11
        "os"
12
        "os/signal"
13
        "sync/atomic"
14
        "syscall"
15

16
        "github.com/coreos/go-systemd/daemon"
17
)
18

19
var (
20
        // started indicates whether we have started our main interrupt handler.
21
        // This field should be used atomically.
22
        started int32
23
)
24

25
// systemdNotifyReady notifies systemd about LND being ready, logs the result of
26
// the operation or possible error. Besides logging, systemd being unavailable
27
// is ignored.
28
func systemdNotifyReady() error {
3✔
29
        notified, err := daemon.SdNotify(false, daemon.SdNotifyReady)
3✔
30
        if err != nil {
3✔
31
                err := fmt.Errorf("failed to notify systemd %v (if you aren't "+
×
32
                        "running systemd clear the environment variable "+
×
33
                        "NOTIFY_SOCKET)", err)
×
34
                log.Error(err)
×
35

×
36
                // The SdNotify doc says it's common to ignore the
×
37
                // error. We don't want to ignore it because if someone
×
38
                // set up systemd to wait for initialization other
×
39
                // processes would get stuck.
×
40
                return err
×
41
        }
×
42
        if notified {
3✔
43
                log.Info("Systemd was notified about our readiness")
×
44
        } else {
3✔
45
                log.Info("We're not running within systemd or the service " +
3✔
46
                        "type is not 'notify'")
3✔
47
        }
3✔
48
        return nil
3✔
49
}
50

51
// systemdNotifyStop notifies systemd that LND is stopping and logs error if
52
// the notification failed. It also logs if the notification was actually sent.
53
// Systemd being unavailable is intentionally ignored.
54
func systemdNotifyStop() {
3✔
55
        notified, err := daemon.SdNotify(false, daemon.SdNotifyStopping)
3✔
56

3✔
57
        // Just log - we're stopping anyway.
3✔
58
        if err != nil {
3✔
59
                log.Errorf("Failed to notify systemd: %v", err)
×
60
        }
×
61
        if notified {
3✔
62
                log.Infof("Systemd was notified about stopping")
×
63
        }
×
64
}
65

66
// Notifier handles notifications about status of LND.
67
type Notifier struct {
68
        // notifiedReady remembers whether Ready was sent to avoid sending it
69
        // multiple times.
70
        notifiedReady bool
71
}
72

73
// NotifyReady notifies other applications that RPC is ready.
74
func (notifier *Notifier) NotifyReady(walletUnlocked bool) error {
3✔
75
        if !notifier.notifiedReady {
6✔
76
                err := systemdNotifyReady()
3✔
77
                if err != nil {
3✔
78
                        return err
×
79
                }
×
80
                notifier.notifiedReady = true
3✔
81
        }
82
        if walletUnlocked {
6✔
83
                _, _ = daemon.SdNotify(false, "STATUS=Wallet unlocked")
3✔
84
        } else {
6✔
85
                _, _ = daemon.SdNotify(false, "STATUS=Wallet locked")
3✔
86
        }
3✔
87

88
        return nil
3✔
89
}
90

91
// notifyStop notifies other applications that LND is stopping.
92
func (notifier *Notifier) notifyStop() {
3✔
93
        systemdNotifyStop()
3✔
94
}
3✔
95

96
// Interceptor contains channels and methods regarding application shutdown
97
// and interrupt signals.
98
type Interceptor struct {
99
        // interruptChannel is used to receive SIGINT (Ctrl+C) signals.
100
        interruptChannel chan os.Signal
101

102
        // shutdownChannel is closed once the main interrupt handler exits.
103
        shutdownChannel chan struct{}
104

105
        // shutdownRequestChannel is used to request the daemon to shutdown
106
        // gracefully, similar to when receiving SIGINT.
107
        shutdownRequestChannel chan struct{}
108

109
        // quit is closed when instructing the main interrupt handler to exit.
110
        // Note that to avoid losing notifications, only shutdown func may
111
        // close this channel.
112
        quit chan struct{}
113

114
        // Notifier handles sending shutdown notifications.
115
        Notifier Notifier
116
}
117

118
// Intercept starts the interception of interrupt signals and returns an `Interceptor` instance.
119
// Note that any previous active interceptor must be stopped before a new one can be created.
120
func Intercept() (Interceptor, error) {
3✔
121
        if !atomic.CompareAndSwapInt32(&started, 0, 1) {
3✔
122
                return Interceptor{}, errors.New("intercept already started")
×
123
        }
×
124

125
        channels := Interceptor{
3✔
126
                interruptChannel:       make(chan os.Signal, 1),
3✔
127
                shutdownChannel:        make(chan struct{}),
3✔
128
                shutdownRequestChannel: make(chan struct{}),
3✔
129
                quit:                   make(chan struct{}),
3✔
130
        }
3✔
131

3✔
132
        signalsToCatch := []os.Signal{
3✔
133
                os.Interrupt,
3✔
134
                os.Kill,
3✔
135
                syscall.SIGTERM,
3✔
136
                syscall.SIGQUIT,
3✔
137
        }
3✔
138
        signal.Notify(channels.interruptChannel, signalsToCatch...)
3✔
139
        go channels.mainInterruptHandler()
3✔
140

3✔
141
        return channels, nil
3✔
142
}
143

144
// mainInterruptHandler listens for SIGINT (Ctrl+C) signals on the
145
// interruptChannel and shutdown requests on the shutdownRequestChannel, and
146
// invokes the registered interruptCallbacks accordingly. It also listens for
147
// callback registration.
148
// It must be run as a goroutine.
149
func (c *Interceptor) mainInterruptHandler() {
3✔
150
        defer atomic.StoreInt32(&started, 0)
3✔
151
        // isShutdown is a flag which is used to indicate whether or not
3✔
152
        // the shutdown signal has already been received and hence any future
3✔
153
        // attempts to add a new interrupt handler should invoke them
3✔
154
        // immediately.
3✔
155
        var isShutdown bool
3✔
156

3✔
157
        // shutdown invokes the registered interrupt handlers, then signals the
3✔
158
        // shutdownChannel.
3✔
159
        shutdown := func() {
6✔
160
                // Ignore more than one shutdown signal.
3✔
161
                if isShutdown {
3✔
162
                        log.Infof("Already shutting down...")
×
163
                        return
×
164
                }
×
165
                isShutdown = true
3✔
166
                log.Infof("Shutting down...")
3✔
167
                c.Notifier.notifyStop()
3✔
168

3✔
169
                // Signal the main interrupt handler to exit, and stop accept
3✔
170
                // post-facto requests.
3✔
171
                close(c.quit)
3✔
172
        }
173

174
        for {
6✔
175
                select {
3✔
176
                case signal := <-c.interruptChannel:
×
177
                        log.Infof("Received %v", signal)
×
178
                        shutdown()
×
179

180
                case <-c.shutdownRequestChannel:
3✔
181
                        log.Infof("Received shutdown request.")
3✔
182
                        shutdown()
3✔
183

184
                case <-c.quit:
3✔
185
                        log.Infof("Gracefully shutting down.")
3✔
186
                        close(c.shutdownChannel)
3✔
187
                        signal.Stop(c.interruptChannel)
3✔
188
                        return
3✔
189
                }
190
        }
191
}
192

193
// Listening returns true if the main interrupt handler has been started, and
194
// has not been killed.
UNCOV
195
func (c *Interceptor) Listening() bool {
×
UNCOV
196
        // If our started field is not set, we are not yet listening for
×
UNCOV
197
        // interrupts.
×
UNCOV
198
        if atomic.LoadInt32(&started) != 1 {
×
199
                return false
×
200
        }
×
201

202
        // If we have started our main goroutine, we check whether we have
203
        // stopped it yet.
UNCOV
204
        return c.Alive()
×
205
}
206

207
// Alive returns true if the main interrupt handler has not been killed.
UNCOV
208
func (c *Interceptor) Alive() bool {
×
UNCOV
209
        select {
×
210
        case <-c.quit:
×
211
                return false
×
UNCOV
212
        default:
×
UNCOV
213
                return true
×
214
        }
215
}
216

217
// RequestShutdown initiates a graceful shutdown from the application.
218
func (c *Interceptor) RequestShutdown() {
3✔
219
        select {
3✔
220
        case c.shutdownRequestChannel <- struct{}{}:
3✔
221
        case <-c.quit:
×
222
        }
223
}
224

225
// ShutdownChannel returns the channel that will be closed once the main
226
// interrupt handler has exited.
227
func (c *Interceptor) ShutdownChannel() <-chan struct{} {
3✔
228
        return c.shutdownChannel
3✔
229
}
3✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc