main: Rework windows service sod notification.

The way that shutdown is handled was modified long ago, but it appears
that the windows service code was not updated fully for the changes.  In
particular, the server instance is no longer used by the service at all.
Rather the only information needed is the parsed configuration in order
to log the start of day details.

Consequently, this reworks the windows service start of day code to read
a buffered channel that receives the parsed configuration instead of the
server and modifies the dcrdMain function to no longer require the
channel to be specified in order to simplify it for eventual context
handling.
This commit is contained in:
Dave Collins 2019-03-30 17:58:29 -05:00
parent 6875c3fde9
commit 733b3588d6
No known key found for this signature in database
GPG Key ID: B8904D9D9C93D1F2
2 changed files with 17 additions and 18 deletions

21
dcrd.go
View File

@ -25,12 +25,15 @@ var cfg *config
// as a service and reacts accordingly.
var winServiceMain func() (bool, error)
// serviceStartOfDayChan is only used by Windows when the code is running as a
// service. It signals the service code that startup has completed. Notice
// that it uses a buffered channel so the caller will not be blocked when the
// service is not running.
var serviceStartOfDayChan = make(chan *config, 1)
// dcrdMain is the real main function for dcrd. It is necessary to work around
// the fact that deferred functions do not run when os.Exit() is called. The
// optional serverChan parameter is mainly used by the service code to be
// notified with the server once it is setup so it can gracefully stop it when
// requested from the service control manager.
func dcrdMain(serverChan chan<- *server) error {
// the fact that deferred functions do not run when os.Exit() is called.
func dcrdMain() error {
// Load configuration and parse command line. This function also
// initializes logging and configures it accordingly.
tcfg, _, err := loadConfig()
@ -191,9 +194,6 @@ func dcrdMain(serverChan chan<- *server) error {
}()
server.Start()
if serverChan != nil {
serverChan <- server
}
if interruptRequested(interrupt) {
return nil
@ -201,6 +201,9 @@ func dcrdMain(serverChan chan<- *server) error {
lifetimeNotifier.notifyStartupComplete()
// Signal the Windows service (if running) that startup has completed.
serviceStartOfDayChan <- cfg
// Wait until the interrupt signal is received from an OS signal or
// shutdown is requested through one of the subsystems such as the RPC
// server.
@ -239,7 +242,7 @@ func main() {
}
// Work around defer not working after os.Exit()
if err := dcrdMain(nil); err != nil {
if err := dcrdMain(); err != nil {
os.Exit(1)
}
}

View File

@ -36,7 +36,7 @@ var elog *eventlog.Log
// logServiceStartOfDay logs information about dcrd when the main server has
// been started to the Windows event log.
func logServiceStartOfDay(srvr *server) {
func logServiceStartOfDay(cfg *config) {
var message string
message += fmt.Sprintf("Version %s\n", version.String())
message += fmt.Sprintf("Configuration directory: %s\n", cfg.HomeDir)
@ -61,19 +61,16 @@ func (s *dcrdService) Execute(args []string, r <-chan svc.ChangeRequest, changes
// Start dcrdMain in a separate goroutine so the service can start
// quickly. Shutdown (along with a potential error) is reported via
// doneChan. serverChan is notified with the main server instance once
// it is started so it can be gracefully stopped.
// doneChan.
doneChan := make(chan error)
serverChan := make(chan *server)
go func() {
err := dcrdMain(serverChan)
err := dcrdMain()
doneChan <- err
}()
// Service is now started.
changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
var mainServer *server
loop:
for {
select {
@ -95,9 +92,8 @@ loop:
"request #%d.", c))
}
case srvr := <-serverChan:
mainServer = srvr
logServiceStartOfDay(mainServer)
case cfg := <-serviceStartOfDayChan:
logServiceStartOfDay(cfg)
case err := <-doneChan:
if err != nil {