Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

win32: Forte as a Windows service #106

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/arch/utils/mainparam_utils.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*******************************************************************************
* Copyright (c) 2018 fortiss GmbH
* 2024 Samator Indo Gas
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
Expand All @@ -9,6 +10,7 @@
* Contributors:
* Tarik Terzimehic
* - initial API and implementation and/or initial documentation
* Ketut Kumajaya - option to run as a Windows service
*******************************************************************************/

#include <forte_config.h>
Expand Down Expand Up @@ -40,6 +42,10 @@ void listHelp(){
#ifdef FORTE_TRACE_CTF
printf("%-20s Set the output directory for TRACE_CTF\n", " -t <directory>");
#endif //FORTE_TRACE_CTF
#ifdef FORTE_WINDOWS_SERVICE
printf("%-20s To install as a Windows service\n", " -install");
printf("%-20s To remove the service\n", " -remove");
#endif //FORTE_WINDOWS_SERVICE
}

/*!\brief Parses the command line arguments passed to the main function
Expand Down Expand Up @@ -90,6 +96,10 @@ const char *parseCommandLineArguments(int argc, char *arg[]){
barectfSetup(arg[i + 1] ?: "");
break;
#endif //FORTE_TRACE_CTF
#ifdef FORTE_WINDOWS_SERVICE
case 's':
break;
#endif //FORTE_WINDOWS_SERVICE
default: //! Unknown parameter or -h -> Lists the help for FORTE
return "";
}
Expand Down
8 changes: 8 additions & 0 deletions src/arch/win32/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#*******************************************************************************
# Copyright (c) 2010 - 2015 ACIN, Profactor GmbH, fortiss GmbH
# 2024 Samator Indo Gas
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0.
Expand All @@ -9,6 +10,7 @@
# Contributors:
# Alois Zoitl, Gerhard Ebenhofer, Martin Melik-Merkumians - initial API and implementation and/or initial documentation
# Christoph Binder - add possibility to configure simulated time
# Ketut Kumajaya - option to run as a Windows service
# *******************************************************************************/

SET(SOURCE_GROUP ${SOURCE_GROUP}\\win32)
Expand Down Expand Up @@ -93,4 +95,10 @@ if("${FORTE_ARCHITECTURE}" STREQUAL "Win32")
endif(FORTE_TESTS AND FORTE_USE_TEST_CONFIG_IN_FORTE)


set(FORTE_WINDOWS_SERVICE OFF CACHE BOOL "Set as a Windows service")
if(FORTE_WINDOWS_SERVICE)
forte_add_definition("-DFORTE_WINDOWS_SERVICE")
add_subdirectory(service)
endif()

endif()
10 changes: 9 additions & 1 deletion src/arch/win32/main.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*******************************************************************************
* Copyright (c) 2010 - 2018 ACIN, Profactor GmbH, fortiss GmbH
* 2024 Samator Indo Gas
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
Expand All @@ -9,6 +10,7 @@
* Contributors:
* Alois Zoitl, Ingo Hegny, Gerhard Ebenhofer - initial API and implementation and/or initial documentation
* Alois Zoitl - cleaned up main, inserted new architecture initilasation api
* Ketut Kumajaya - option to run as a Windows service
*******************************************************************************/
#include "../forte_architecture.h"
#include "../devlog.h"
Expand Down Expand Up @@ -51,7 +53,7 @@ CDevice *createDev(const char *paMGRID){
return dev;
}

int main(int argc, char *arg[]){
int _main(int argc, char *arg[]){

if(CForteArchitecture::initialize()){

Expand Down Expand Up @@ -88,3 +90,9 @@ void hookSignals() {
signal(SIGINT, endForte);
signal(SIGTERM, endForte);
}

#ifndef FORTE_WINDOWS_SERVICE
int main(int argc, char *arg[]){
return _main(argc, arg);
}
#endif
15 changes: 15 additions & 0 deletions src/arch/win32/service/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#*******************************************************************************
# Copyright (c) 2024 Samator Indo Gas
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0.
#
# SPDX-License-Identifier: EPL-2.0
#
# Contributors:
# Ketut Kumajaya - initial API and implementation and/or initial documentation
# *******************************************************************************/
if(FORTE_WINDOWS_SERVICE)
forte_add_to_executable_h(ForteService ServiceBase ServiceInstaller ThreadPool)
forte_add_to_executable_cpp(wmain ForteService ServiceBase ServiceInstaller)
endif()
168 changes: 168 additions & 0 deletions src/arch/win32/service/ForteService.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/****************************** Module Header ******************************\
* Module Name: SampleService.cpp
* Project: CppWindowsService
* Copyright (c) Microsoft Corporation.
*
* 2024, Ketut Kumajaya - modified for FORTE to run as a Windows service
*
* Provides a sample service class that derives from the service base class -
* CServiceBase. The sample service logs the service start and stop
* information to the Application event log, and shows how to run the main
* function of the service in a thread pool worker thread.
*
* This source is subject to the Microsoft Public License.
* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL.
* All other rights reserved.
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
\***************************************************************************/

#pragma region Includes
#include "ForteService.h"
#include "ThreadPool.h"
#pragma endregion


#include <sstream>
#include "../../devlog.h"
#include "../../forte_stringFunctions.h"

void endForte(int paSig);
int _main(int argc, char *arg[]);


CForteService::CForteService(PWSTR pszServiceName,
int argc,
char *argv[],
BOOL fCanStop,
BOOL fCanShutdown,
BOOL fCanPauseContinue)
: CServiceBase(pszServiceName, fCanStop, fCanShutdown, fCanPauseContinue)
{
m_fStopping = FALSE;
m_argc = argc;
m_argv = argv;

// Create a manual-reset event that is not signaled at first to indicate
// the stopped signal of the service.
m_hStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_hStoppedEvent == NULL)
{
throw GetLastError();
}
}


CForteService::~CForteService(void)
{
if (m_hStoppedEvent)
{
CloseHandle(m_hStoppedEvent);
m_hStoppedEvent = NULL;
}
}


//
// FUNCTION: CForteService::OnStart(DWORD, LPWSTR *)
//
// PURPOSE: The function is executed when a Start command is sent to the
// service by the SCM or when the operating system starts (for a service
// that starts automatically). It specifies actions to take when the
// service starts. In this code sample, OnStart logs a service-start
// message to the Application log, and queues the main service function for
// execution in a thread pool worker thread.
//
// PARAMETERS:
// * dwArgc - number of command line arguments
// * lpszArgv - array of command line arguments
//
// NOTE: A service application is designed to be long running. Therefore,
// it usually polls or monitors something in the system. The monitoring is
// set up in the OnStart method. However, OnStart does not actually do the
// monitoring. The OnStart method must return to the operating system after
// the service's operation has begun. It must not loop forever or block. To
// set up a simple monitoring mechanism, one general solution is to create
// a timer in OnStart. The timer would then raise events in your code
// periodically, at which time your service could do its monitoring. The
// other solution is to spawn a new thread to perform the main service
// functions, which is demonstrated in this code sample.
//
void CForteService::OnStart(DWORD, LPWSTR*)
{
// Log command line arguments
std::ostringstream stream;
for (int i = 0; i < m_argc; ++i)
{
stream << " " << m_argv[i];
}

// Log a service start message to the Application log.
WriteEventLogEntry((PWSTR)(forte_stringToWstring(("FORTE service started:" + stream.str())).c_str()),
EVENTLOG_INFORMATION_TYPE);

// Queue the main service function for execution in a worker thread.
CThreadPool::QueueUserWorkItem(&CForteService::ServiceWorkerThread, this);
}


//
// FUNCTION: CForteService::ServiceWorkerThread(void)
//
// PURPOSE: The method performs the main function of the service. It runs
// on a thread pool worker thread.
//
void CForteService::ServiceWorkerThread(void)
{
// Periodically check if the service is stopping.
while (!m_fStopping)
{
// Log a prosess start message
DEVLOG_INFO("FORTE process start\n");

// Perform main service function here...
_main(m_argc, m_argv);

// Log a prosess stop message
DEVLOG_INFO("FORTE process end\n");

::Sleep(2000); // Simulate some lengthy operations.
}

// Signal the stopped event.
SetEvent(m_hStoppedEvent);
}


//
// FUNCTION: CForteService::OnStop(void)
//
// PURPOSE: The function is executed when a Stop command is sent to the
// service by SCM. It specifies actions to take when a service stops
// running. In this code sample, OnStop logs a service-stop message to the
// Application log, and waits for the finish of the main service function.
//
// COMMENTS:
// Be sure to periodically call ReportServiceStatus() with
// SERVICE_STOP_PENDING if the procedure is going to take long time.
//
void CForteService::OnStop()
{
// Log a service stop message to the Application log.
WriteEventLogEntry((PWSTR)L"FORTE service stopped",
EVENTLOG_INFORMATION_TYPE);

// Indicate that the service is stopping and wait for the finish of the
// main service function (ServiceWorkerThread).
m_fStopping = TRUE;

// Kill FORTE process
endForte(0);

if (WaitForSingleObject(m_hStoppedEvent, INFINITE) != WAIT_OBJECT_0)
{
throw GetLastError();
}
}
53 changes: 53 additions & 0 deletions src/arch/win32/service/ForteService.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/****************************** Module Header ******************************\
* Module Name: SampleService.h
* Project: CppWindowsService
* Copyright (c) Microsoft Corporation.
*
* 2024, Ketut Kumajaya - modified for FORTE to run as a Windows service
*
* Provides a sample service class that derives from the service base class -
* CServiceBase. The sample service logs the service start and stop
* information to the Application event log, and shows how to run the main
* function of the service in a thread pool worker thread.
*
* This source is subject to the Microsoft Public License.
* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL.
* All other rights reserved.
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
\***************************************************************************/

#pragma once

#include "ServiceBase.h"


class CForteService : public CServiceBase
{
public:

CForteService(PWSTR pszServiceName,
int argc,
char *argv[],
BOOL fCanStop = TRUE,
BOOL fCanShutdown = TRUE,
BOOL fCanPauseContinue = FALSE);
virtual ~CForteService(void);

protected:

virtual void OnStart(DWORD dwArgc, PWSTR *pszArgv);
virtual void OnStop();

void ServiceWorkerThread(void);

private:

BOOL m_fStopping;
HANDLE m_hStoppedEvent;

int m_argc;
char **m_argv;
};
Loading