2 * Ceph - scalable distributed file system
4 * Copyright (C) 2019 SUSE LINUX GmbH
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.
13 #define dout_context cct
14 #define dout_subsys ceph_subsys_
16 #include "common/debug.h"
17 #include "common/errno.h"
18 #include "common/win32/service.h"
20 // Initialize the singleton service instance.
21 ServiceBase
*ServiceBase::s_service
= NULL
;
23 ServiceBase::ServiceBase(CephContext
*cct_
): cct(cct_
)
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;
34 /* Register service action callbacks */
35 int ServiceBase::initialize(ServiceBase
*service
)
39 SERVICE_TABLE_ENTRY service_table
[] = {
40 {"", (LPSERVICE_MAIN_FUNCTION
)run
},
44 /* StartServiceCtrlDispatcher blocks until the service is stopped. */
45 if (!StartServiceCtrlDispatcher(service_table
)) {
46 int err
= GetLastError();
47 lderr(service
->cct
) << "StartServiceCtrlDispatcher error: "
54 void WINAPI
ServiceBase::run()
56 assert(s_service
!= NULL
);
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
;
69 s_service
->set_status(SERVICE_START_PENDING
);
71 // TODO: should we expect exceptions?
72 ldout(s_service
->cct
, 5) << "Starting service." << dendl
;
73 int err
= s_service
->run_hook();
75 lderr(s_service
->cct
) << "Failed to start service. Error code: "
77 s_service
->shutdown(true);
79 ldout(s_service
->cct
, 5) << "Successfully started service." << dendl
;
80 s_service
->set_status(SERVICE_RUNNING
);
84 void ServiceBase::shutdown(bool ignore_errors
)
86 DWORD original_state
= status
.dwCurrentState
;
87 set_status(SERVICE_STOP_PENDING
);
89 int err
= shutdown_hook();
91 derr
<< "Shutdown service hook failed. Error code: " << err
<< dendl
;
93 derr
<< "Ignoring shutdown hook failure, marking the service as stopped."
95 set_status(SERVICE_STOPPED
);
97 derr
<< "Reverting to original service state." << dendl
;
98 set_status(original_state
);
101 dout(5) << "Shutdown hook completed." << dendl
;
102 set_status(SERVICE_STOPPED
);
106 void ServiceBase::stop()
108 DWORD original_state
= status
.dwCurrentState
;
109 set_status(SERVICE_STOP_PENDING
);
111 int err
= stop_hook();
113 derr
<< "Service stop hook failed. Error code: " << err
<< dendl
;
114 set_status(original_state
);
116 dout(5) << "Successfully stopped service." << dendl
;
117 set_status(SERVICE_STOPPED
);
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
)
127 case SERVICE_CONTROL_STOP
:
130 case SERVICE_CONTROL_SHUTDOWN
:
131 s_service
->shutdown();
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
++;
144 status
.dwCurrentState
= current_state
;
145 status
.dwWin32ExitCode
= exit_code
;
148 dout(5) << "Updating service service status (" << current_state
149 << ") and exit code(" << exit_code
<< ")." << dendl
;
150 ::SetServiceStatus(hstatus
, &status
);
152 derr
<< "Service control handler not initialized. Cannot "
153 << "update service status (" << current_state
154 << ") and exit code(" << exit_code
<< ")." << dendl
;