Commit 12036c15 authored by Alex Brainman's avatar Alex Brainman

windows/svc: add Context to ChangeRequest

New Context field will be used in the following CL to test
ctlHandler parameter alignments.

Also adjust TestExample to pass hard coded Context value of 123456
to test service, and verify that correct value is logged. Final
part of the test is commented out, and will be adjusted in the next
CL.

Updates golang/go#25660

Change-Id: Iad2896ae497ee1edc0d62655eaf08671ec2651c5
Reviewed-on: https://go-review.googlesource.com/c/158697
Run-TryBot: Alex Brainman <alex.brainman@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
parent a34e9553
...@@ -27,7 +27,6 @@ func (m *myservice) Execute(args []string, r <-chan svc.ChangeRequest, changes c ...@@ -27,7 +27,6 @@ func (m *myservice) Execute(args []string, r <-chan svc.ChangeRequest, changes c
slowtick := time.Tick(2 * time.Second) slowtick := time.Tick(2 * time.Second)
tick := fasttick tick := fasttick
changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted} changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
elog.Info(1, strings.Join(args, "-"))
loop: loop:
for { for {
select { select {
...@@ -42,6 +41,10 @@ loop: ...@@ -42,6 +41,10 @@ loop:
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
changes <- c.CurrentStatus changes <- c.CurrentStatus
case svc.Stop, svc.Shutdown: case svc.Stop, svc.Shutdown:
// golang.org/x/sys/windows/svc.TestExample is verifying this output.
testOutput := strings.Join(args, "-")
testOutput += fmt.Sprintf("-%d", c.Context)
elog.Info(1, testOutput)
break loop break loop
case svc.Pause: case svc.Pause:
changes <- svc.Status{State: svc.Paused, Accepts: cmdsAccepted} changes <- svc.Status{State: svc.Paused, Accepts: cmdsAccepted}
......
...@@ -80,6 +80,7 @@ type ChangeRequest struct { ...@@ -80,6 +80,7 @@ type ChangeRequest struct {
EventType uint32 EventType uint32
EventData uintptr EventData uintptr
CurrentStatus Status CurrentStatus Status
Context uintptr
} }
// Handler is the interface that must be implemented to build Windows service. // Handler is the interface that must be implemented to build Windows service.
...@@ -121,12 +122,11 @@ func init() { ...@@ -121,12 +122,11 @@ func init() {
cRegisterServiceCtrlHandlerExW = a.MustFindProc("RegisterServiceCtrlHandlerExW").Addr() cRegisterServiceCtrlHandlerExW = a.MustFindProc("RegisterServiceCtrlHandlerExW").Addr()
} }
// The HandlerEx prototype also has a context pointer but since we don't use
// it at start-up time we don't have to pass it over either.
type ctlEvent struct { type ctlEvent struct {
cmd Cmd cmd Cmd
eventType uint32 eventType uint32
eventData uintptr eventData uintptr
context uintptr
errno uint32 errno uint32
} }
...@@ -238,13 +238,12 @@ func (s *service) run() { ...@@ -238,13 +238,12 @@ func (s *service) run() {
exitFromHandler <- exitCode{ss, errno} exitFromHandler <- exitCode{ss, errno}
}() }()
status := Status{State: Stopped}
ec := exitCode{isSvcSpecific: true, errno: 0} ec := exitCode{isSvcSpecific: true, errno: 0}
outcr := ChangeRequest{
CurrentStatus: Status{State: Stopped},
}
var outch chan ChangeRequest var outch chan ChangeRequest
inch := s.c inch := s.c
var cmd Cmd
var evtype uint32
var evdata uintptr
loop: loop:
for { for {
select { select {
...@@ -255,10 +254,11 @@ loop: ...@@ -255,10 +254,11 @@ loop:
} }
inch = nil inch = nil
outch = cmdsToHandler outch = cmdsToHandler
cmd = r.cmd outcr.Cmd = r.cmd
evtype = r.eventType outcr.EventType = r.eventType
evdata = r.eventData outcr.EventData = r.eventData
case outch <- ChangeRequest{cmd, evtype, evdata, status}: outcr.Context = r.context
case outch <- outcr:
inch = s.c inch = s.c
outch = nil outch = nil
case c := <-changesFromHandler: case c := <-changesFromHandler:
...@@ -271,7 +271,7 @@ loop: ...@@ -271,7 +271,7 @@ loop:
} }
break loop break loop
} }
status = c outcr.CurrentStatus = c
case ec = <-exitFromHandler: case ec = <-exitFromHandler:
break loop break loop
} }
...@@ -316,7 +316,7 @@ func Run(name string, handler Handler) error { ...@@ -316,7 +316,7 @@ func Run(name string, handler Handler) error {
} }
ctlHandler := func(ctl uint32, evtype uint32, evdata uintptr, context uintptr) uintptr { ctlHandler := func(ctl uint32, evtype uint32, evdata uintptr, context uintptr) uintptr {
e := ctlEvent{cmd: Cmd(ctl), eventType: evtype, eventData: evdata} e := ctlEvent{cmd: Cmd(ctl), eventType: evtype, eventData: evdata, context: context}
// We assume that this callback function is running on // We assume that this callback function is running on
// the same thread as Run. Nowhere in MS documentation // the same thread as Run. Nowhere in MS documentation
// I could find statement to guarantee that. So putting // I could find statement to guarantee that. So putting
......
...@@ -125,7 +125,11 @@ func TestExample(t *testing.T) { ...@@ -125,7 +125,11 @@ func TestExample(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("wevtutil failed: %v\n%v", err, string(out)) t.Fatalf("wevtutil failed: %v\n%v", err, string(out))
} }
if want := strings.Join(append([]string{name}, args...), "-"); !strings.Contains(string(out), want) { want := strings.Join(append([]string{name}, args...), "-")
// Test context passing (see servicemain in sys_386.s and sys_amd64.s).
// TODO(brainman): Uncomment next line once issue #25660 is fixed.
//want += "-123456"
if !strings.Contains(string(out), want) {
t.Errorf("%q string does not contain %q", string(out), want) t.Errorf("%q string does not contain %q", string(out), want)
} }
} }
...@@ -22,7 +22,8 @@ TEXT ·servicemain(SB),7,$0 ...@@ -22,7 +22,8 @@ TEXT ·servicemain(SB),7,$0
MOVL AX, (SP) MOVL AX, (SP)
MOVL $·servicectlhandler(SB), AX MOVL $·servicectlhandler(SB), AX
MOVL AX, 4(SP) MOVL AX, 4(SP)
MOVL $0, 8(SP) // Set context to 123456 to test issue #25660.
MOVL $123456, 8(SP)
MOVL ·cRegisterServiceCtrlHandlerExW(SB), AX MOVL ·cRegisterServiceCtrlHandlerExW(SB), AX
MOVL SP, BP MOVL SP, BP
CALL AX CALL AX
......
...@@ -14,6 +14,8 @@ TEXT ·servicemain(SB),7,$0 ...@@ -14,6 +14,8 @@ TEXT ·servicemain(SB),7,$0
MOVQ ·sName(SB), CX MOVQ ·sName(SB), CX
MOVQ $·servicectlhandler(SB), DX MOVQ $·servicectlhandler(SB), DX
// BUG(pastarmovj): Figure out a way to pass in context in R8. // BUG(pastarmovj): Figure out a way to pass in context in R8.
// Set context to 123456 to test issue #25660.
MOVQ $123456, R8
MOVQ ·cRegisterServiceCtrlHandlerExW(SB), AX MOVQ ·cRegisterServiceCtrlHandlerExW(SB), AX
CALL AX CALL AX
CMPQ AX, $0 CMPQ AX, $0
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment