in src/native/windows/apps/prunsrv/prunsrv.c [1219:1416]
static DWORD WINAPI serviceStop(LPVOID lpParameter)
{
APXHANDLE hWorker = NULL;
DWORD rv = 0;
BOOL wait_to_die = FALSE;
DWORD timeout = SO_STOPTIMEOUT * 1000;
DWORD dwCtrlType = (DWORD)((BYTE *)lpParameter - (BYTE *)0);
apxLogWrite(APXLOG_MARK_INFO "Stopping service...");
if (IS_INVALID_HANDLE(gWorker)) {
apxLogWrite(APXLOG_MARK_INFO "Worker is not defined.");
return TRUE; /* Nothing to do */
}
if (timeout > 0x7FFFFFFF)
timeout = INFINITE; /* If the timeout was '-1' wait forewer */
if (_jni_shutdown) {
if (!IS_VALID_STRING(SO_STARTPATH) && IS_VALID_STRING(SO_STOPPATH)) {
/* If the Working path is specified change the current directory
* but only if the start path wasn't specified already.
*/
SetCurrentDirectoryW(SO_STOPPATH);
}
hWorker = apxCreateJava(gPool, _jni_jvmpath, SO_JAVAHOME);
if (IS_INVALID_HANDLE(hWorker)) {
apxLogWrite(APXLOG_MARK_ERROR "Failed creating Java '%S'.", _jni_jvmpath);
return 1;
}
gSargs.hJava = hWorker;
gSargs.szClassPath = _jni_classpath;
gSargs.lpOptions = _jni_jvmoptions;
gSargs.lpOptions9 = _jni_jvmoptions9;
gSargs.dwMs = SO_JVMMS;
gSargs.dwMx = SO_JVMMX;
gSargs.dwSs = SO_JVMSS;
gSargs.bJniVfprintf = SO_JNIVFPRINTF;
gSargs.szClassName = _jni_sclass;
gSargs.szMethodName = _jni_smethod;
gSargs.lpArguments = _jni_sparam;
gSargs.szStdErrFilename = NULL;
gSargs.szStdOutFilename = NULL;
gSargs.szLibraryPath = SO_LIBPATH;
/* Register onexit hook
*/
_onexit(onExitStop);
/* Create shutdown event */
gShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!apxJavaStart(&gSargs)) {
apxLogWrite(APXLOG_MARK_ERROR "Failed starting Java.");
rv = 3;
}
else {
if (lstrcmpA(_jni_sclass, "java/lang/System") == 0) {
reportServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 20 * 1000);
apxLogWrite(APXLOG_MARK_DEBUG "Forcing Java JNI System.exit() worker to finish...");
return 0;
}
else {
apxLogWrite(APXLOG_MARK_DEBUG "Waiting for Java JNI stop worker to finish for %s:%s...", _jni_sclass, _jni_smethod);
if (!timeout)
apxJavaWait(hWorker, INFINITE, FALSE);
else
apxJavaWait(hWorker, timeout, FALSE);
apxLogWrite(APXLOG_MARK_DEBUG "Java JNI stop worker finished.");
}
}
wait_to_die = TRUE;
}
else if (IS_VALID_STRING(SO_STOPMODE)) { /* Only in case we have a stop mode */
DWORD nArgs;
LPWSTR *pArgs;
if (!IS_VALID_STRING(SO_STOPIMAGE)) {
apxLogWrite(APXLOG_MARK_ERROR "Missing service ImageFile.");
if (!_service_mode)
apxDisplayError(FALSE, NULL, 0, "Service '%S' is missing the ImageFile.",
_service_name ? _service_name : L"unknown");
return 1;
}
/* Redirect process */
hWorker = apxCreateProcessW(gPool,
0,
child_callback,
SO_USER,
SO_PASSWORD,
FALSE);
if (IS_INVALID_HANDLE(hWorker)) {
apxLogWrite(APXLOG_MARK_ERROR "Failed creating process.");
return 1;
}
/* If the service process completes before the stop process does the
* cleanup code below will free structures required by the stop process
* which will, in all probability, trigger a crash. Wait for the stop
* process to complete before cleaning up.
*/
gShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!apxProcessSetExecutableW(hWorker, SO_STOPIMAGE)) {
apxLogWrite(APXLOG_MARK_ERROR "Failed setting process executable '%S'.",
SO_STOPIMAGE);
rv = 2;
goto cleanup;
}
/* Assemble the command line */
if (_java_shutdown) {
nArgs = apxJavaCmdInitialize(gPool, SO_CLASSPATH, SO_STOPCLASS,
SO_JVMOPTIONS, SO_JVMMS, SO_JVMMX,
SO_JVMSS, SO_STOPPARAMS, &pArgs);
}
else {
nArgs = apxMultiSzToArrayW(gPool, SO_STOPPARAMS, &pArgs);
}
/* Pass the argv to child process */
if (!apxProcessSetCommandArgsW(hWorker, SO_STOPIMAGE,
nArgs, pArgs)) {
rv = 3;
apxLogWrite(APXLOG_MARK_ERROR "Failed setting process arguments (argc=%d).",
nArgs);
goto cleanup;
}
/* Set the working path */
if (!apxProcessSetWorkingPathW(hWorker, SO_STOPPATH)) {
rv = 4;
apxLogWrite(APXLOG_MARK_ERROR "Failed setting process working path to '%S'.",
SO_STOPPATH);
goto cleanup;
}
/* Finally execute the child process
*/
if (!apxProcessExecute(hWorker)) {
rv = 5;
apxLogWrite(APXLOG_MARK_ERROR "Failed executing process.");
goto cleanup;
} else {
apxLogWrite(APXLOG_MARK_DEBUG "Waiting for stop worker to finish...");
if (!timeout)
apxHandleWait(hWorker, INFINITE, FALSE);
else
apxHandleWait(hWorker, timeout, FALSE);
apxLogWrite(APXLOG_MARK_DEBUG "Stop worker finished.");
}
wait_to_die = TRUE;
}
cleanup:
/* Close Java JNI handle or stop worker
* If this is the single JVM instance it will unload
* the JVM dll too.
* The worker will be closed on service exit.
*/
if (!IS_INVALID_HANDLE(hWorker))
apxCloseHandle(hWorker);
if (gSignalEvent) {
gSignalValid = FALSE;
SetEvent(gSignalEvent);
WaitForSingleObject(gSignalThread, 1000);
CloseHandle(gSignalEvent);
CloseHandle(gSignalThread);
gSignalEvent = NULL;
}
if (wait_to_die && !timeout)
timeout = 300 * 1000; /* Use the 5 minute default shutdown */
if (dwCtrlType == SERVICE_CONTROL_SHUTDOWN)
timeout = MIN(timeout, apxGetMaxServiceTimeout(gPool));
reportServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, timeout);
if (timeout) {
FILETIME fts, fte;
ULARGE_INTEGER s, e;
DWORD nms;
/* Wait to give it a chance to die naturally, then kill it. */
apxLogWrite(APXLOG_MARK_DEBUG "Waiting for worker to die naturally...");
GetSystemTimeAsFileTime(&fts);
rv = apxHandleWait(gWorker, timeout, TRUE);
GetSystemTimeAsFileTime(&fte);
s.LowPart = fts.dwLowDateTime;
s.HighPart = fts.dwHighDateTime;
e.LowPart = fte.dwLowDateTime;
e.HighPart = fte.dwHighDateTime;
nms = (DWORD)((e.QuadPart - s.QuadPart) / 10000);
if (rv == WAIT_OBJECT_0) {
rv = 0;
apxLogWrite(APXLOG_MARK_DEBUG "Worker finished gracefully in %d milliseconds.", nms);
}
else
apxLogWrite(APXLOG_MARK_DEBUG "Worker was killed in %d milliseconds.", nms);
}
else {
apxLogWrite(APXLOG_MARK_DEBUG "Sending WM_CLOSE to worker.");
apxHandleSendMessage(gWorker, WM_CLOSE, 0, 0);
}
apxLogWrite(APXLOG_MARK_INFO "Service stop thread completed.");
if (gShutdownEvent) {
SetEvent(gShutdownEvent);
}
return rv;
}