]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/win32/service.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / common / win32 / service.cc
1 /*
2 * Ceph - scalable distributed file system
3 *
4 * Copyright (C) 2019 SUSE LINUX GmbH
5 *
6 * This is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License version 2.1, as published by the Free Software
9 * Foundation. See file COPYING.
10 *
11 */
12
13 #define dout_context cct
14 #define dout_subsys ceph_subsys_
15
16 #include "common/debug.h"
17 #include "common/errno.h"
18 #include "common/win32/service.h"
19
20 // Initialize the singleton service instance.
21 ServiceBase *ServiceBase::s_service = NULL;
22
23 ServiceBase::ServiceBase(CephContext *cct_): cct(cct_)
24 {
25 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
26 status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
27 status.dwCurrentState = SERVICE_START_PENDING;
28 status.dwWin32ExitCode = NO_ERROR;
29 status.dwCheckPoint = 0;
30 /* The estimated time required for the stop operation in ms. */
31 status.dwWaitHint = 0;
32 }
33
34 /* Register service action callbacks */
35 int ServiceBase::initialize(ServiceBase *service)
36 {
37 s_service = service;
38
39 SERVICE_TABLE_ENTRY service_table[] = {
40 {"", (LPSERVICE_MAIN_FUNCTION)run},
41 {NULL, NULL}
42 };
43
44 /* StartServiceCtrlDispatcher blocks until the service is stopped. */
45 if (!StartServiceCtrlDispatcher(service_table)) {
46 int err = GetLastError();
47 lderr(service->cct) << "StartServiceCtrlDispatcher error: "
48 << err << dendl;
49 return -EINVAL;
50 }
51 return 0;
52 }
53
54 void WINAPI ServiceBase::run()
55 {
56 assert(s_service != NULL);
57
58 /* Register the control handler. This function is called by the service
59 * manager to stop the service. The service name that we're passing here
60 * doesn't have to be valid as we're using SERVICE_WIN32_OWN_PROCESS. */
61 s_service->hstatus = RegisterServiceCtrlHandler(
62 "", (LPHANDLER_FUNCTION)control_handler);
63 if (!s_service->hstatus) {
64 lderr(s_service->cct) << "Could not initialize service control handler. "
65 << "Error: " << GetLastError() << dendl;
66 return;
67 }
68
69 s_service->set_status(SERVICE_START_PENDING);
70
71 // TODO: should we expect exceptions?
72 ldout(s_service->cct, 5) << "Starting service." << dendl;
73 int err = s_service->run_hook();
74 if (err) {
75 lderr(s_service->cct) << "Failed to start service. Error code: "
76 << err << dendl;
77 s_service->shutdown(true);
78 } else {
79 ldout(s_service->cct, 5) << "Successfully started service." << dendl;
80 s_service->set_status(SERVICE_RUNNING);
81 }
82 }
83
84 void ServiceBase::shutdown(bool ignore_errors)
85 {
86 DWORD original_state = status.dwCurrentState;
87 set_status(SERVICE_STOP_PENDING);
88
89 int err = shutdown_hook();
90 if (err) {
91 derr << "Shutdown service hook failed. Error code: " << err << dendl;
92 if (ignore_errors) {
93 derr << "Ignoring shutdown hook failure, marking the service as stopped."
94 << dendl;
95 set_status(SERVICE_STOPPED);
96 } else {
97 derr << "Reverting to original service state." << dendl;
98 set_status(original_state);
99 }
100 } else {
101 dout(5) << "Shutdown hook completed." << dendl;
102 set_status(SERVICE_STOPPED);
103 }
104 }
105
106 void ServiceBase::stop()
107 {
108 DWORD original_state = status.dwCurrentState;
109 set_status(SERVICE_STOP_PENDING);
110
111 int err = stop_hook();
112 if (err) {
113 derr << "Service stop hook failed. Error code: " << err << dendl;
114 set_status(original_state);
115 } else {
116 dout(5) << "Successfully stopped service." << dendl;
117 set_status(SERVICE_STOPPED);
118 }
119 }
120
121 /* This function is registered with the Windows services manager through
122 * a call to RegisterServiceCtrlHandler() and will be called by the Windows
123 * service manager asynchronously to stop the service. */
124 void ServiceBase::control_handler(DWORD request)
125 {
126 switch (request) {
127 case SERVICE_CONTROL_STOP:
128 s_service->stop();
129 break;
130 case SERVICE_CONTROL_SHUTDOWN:
131 s_service->shutdown();
132 break;
133 default:
134 break;
135 }
136 }
137
138 void ServiceBase::set_status(DWORD current_state, DWORD exit_code) {
139 static DWORD dwCheckPoint = 1;
140 if (current_state == SERVICE_RUNNING || current_state == SERVICE_STOPPED) {
141 status.dwCheckPoint = dwCheckPoint++;
142 }
143
144 status.dwCurrentState = current_state;
145 status.dwWin32ExitCode = exit_code;
146
147 if (hstatus) {
148 dout(5) << "Updating service service status (" << current_state
149 << ") and exit code(" << exit_code << ")." << dendl;
150 ::SetServiceStatus(hstatus, &status);
151 } else {
152 derr << "Service control handler not initialized. Cannot "
153 << "update service status (" << current_state
154 << ") and exit code(" << exit_code << ")." << dendl;
155 }
156 }