소스 검색

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: Brad Fitzpatrick <bradfitz@golang.org>
Alex Brainman 6 년 전
부모
커밋
12036c158a
5개의 변경된 파일25개의 추가작업 그리고 15개의 파일을 삭제
  1. 4 1
      windows/svc/example/service.go
  2. 12 12
      windows/svc/service.go
  3. 5 1
      windows/svc/svc_test.go
  4. 2 1
      windows/svc/sys_386.s
  5. 2 0
      windows/svc/sys_amd64.s

+ 4 - 1
windows/svc/example/service.go

@@ -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:
 				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}

+ 12 - 12
windows/svc/service.go

@@ -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() {
 	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() {
 		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:
 			}
 			}
 			inch = nil
 			inch = nil
 			outch = cmdsToHandler
 			outch = cmdsToHandler
-			cmd = r.cmd
-			evtype = r.eventType
-			evdata = r.eventData
-		case outch <- ChangeRequest{cmd, evtype, evdata, status}:
+			outcr.Cmd = r.cmd
+			outcr.EventType = r.eventType
+			outcr.EventData = r.eventData
+			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:
 				}
 				}
 				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 {
 	}
 	}
 
 
 	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

+ 5 - 1
windows/svc/svc_test.go

@@ -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)
 	}
 	}
 }
 }

+ 2 - 1
windows/svc/sys_386.s

@@ -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

+ 2 - 0
windows/svc/sys_amd64.s

@@ -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