GPUServiceDirect
Navigation: Programming with ADLX → ADLX Samples → C Samples → ServiceCall
Demonstrates how to use ADLX into a system service application for ADLX v1.4 and above.
Command Prompts
| Command Prompt | Description |
|---|---|
| -install | Install “ADLX GPU Service” into services. |
| -remove | Remove “ADLX GPU Service” from services. |
Sample Path
/Samples/C/ServiceCall/GPUServiceDirect
C
Code
C
//// Copyright Advanced Micro Devices, Inc. All rights reserved.////-------------------------------------------------------------------------------------------------
/// \file mainGPUServiceDirect.c/// \brief This document demonstrate how to use windows service call to get GPU information.
#pragma warning(suppress: 6248)
#include <Windows.h>#include <TlHelp32.h>#include <WtsApi32.h>#include <wchar.h>#include "SDK/ADLXHelper/Windows/C/ADLXHelper.h"#include "SDK/Include/ISystem.h"#include "SDK/Include/IPerformanceMonitoring3.h"#include <stdio.h>
#pragma comment(lib, "wtsapi32.lib")
#define MAX_DEBUG_STR_LEN 1024
void XTrace (wchar_t* lpszFormat, ...){ va_list args; va_start (args, lpszFormat); int nBuf; WCHAR szBuffer[MAX_DEBUG_STR_LEN]; nBuf = _vsnwprintf_s (szBuffer, MAX_DEBUG_STR_LEN, _TRUNCATE, lpszFormat, args); OutputDebugStringW (szBuffer); va_end (args);}
// Indicates that ADLX is functionalBOOL g_ADLXAlive = FALSE;// An event to wait for the right conditions to initialize ADLXHANDLE g_ADLXInitReady = NULL;
// Service name#define ADLX_SERVICE_NAME L"ADLX GPU Service"
// Global variables for service routineSERVICE_STATUS_HANDLE g_StatusHandle = NULL;SERVICE_STATUS g_ServiceStatus = { 0 };HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;BOOL g_StopWorkThread = FALSE;
// Service routineVOID WINAPI ServiceMain (DWORD argc, LPTSTR* argv);DWORD WINAPI ServiceCtrlHandler (DWORD ctrlCode, DWORD eventType, LPVOID eventData, LPVOID context);DWORD WINAPI ServiceWorkerThread (LPVOID lpParam);
// Check if any user is logged onBOOL IsAnyUserLogon ();
// Install/unistall this service// N.B: Need admin permission// User can also install/unistall this service by windows command line// Usage: SC CREATE "ADLX GPU Service" "GPUServiceDirect.exe -install"// SC DELETE "ADLX GPU Service" "GPUServiceDirect.exe -remove"void InstallService ();void RemoveService ();
// Usagevoid Usage (){ printf ("\n"); printf ("\tThis exe is a service executable, you can install/unistall it with:\n"); printf ("\t SC CREATE 'ADLX GPU Service' 'GPUService.exe'\n"); printf ("\t SC DELETE 'ADLX GPU Service'\n"); printf ("\n"); printf ("\tOr use the executable itself to install/uninstall:\n"); printf ("\t GPUService.exe -install or GPUService.exe /install\n"); printf ("\t GPUService.exe -remove or GPUService.exe /remove\n"); printf ("\n"); printf ("\t Use GPUService.exe -help, GPUService.exe /help to show this usage, or GPUService.exe ?\n"); printf ("\n");}
int wmain (int argc, wchar_t* argv[]){ XTrace (L"ADLX Call Service: Main: Entry"); XTrace (L"ADLX Call Service: Main: Args:%s", GetCommandLineW ());
if ((argc > 1)) { if (((*argv[1] == '-') || (*argv[1] == '/'))) { if (_wcsicmp (L"install", argv[1] + 1) == 0) { InstallService (); return 0; } else if (_wcsicmp (L"remove", argv[1] + 1) == 0) { RemoveService (); return 0; } else if (_wcsicmp (L"help", argv[1] + 1) == 0) { Usage (); return 0; } } else if (_wcsicmp (L"?", argv[1]) == 0) { Usage (); return 0; } }
SERVICE_TABLE_ENTRYW ServiceTable[] = { { ADLX_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTIONW)ServiceMain }, { NULL, NULL } };
if (StartServiceCtrlDispatcherW (ServiceTable) == FALSE) { XTrace (L"ADLX Call Service: Main: StartServiceCtrlDispatcher returned error."); return GetLastError (); }
XTrace (L"ADLX Call Service: Main: Exit");
return 0;}
VOID WINAPI ServiceMain (DWORD argc, LPTSTR* argv){ DWORD Status = E_FAIL;
XTrace (L"ADLX Call Service: ServiceMain: Entry");
g_StatusHandle = RegisterServiceCtrlHandlerExW (ADLX_SERVICE_NAME, ServiceCtrlHandler, NULL); if (g_StatusHandle == NULL) { XTrace (L"ADLX Call Service: ServiceMain: RegisterServiceCtrlHandler returned error"); goto EXIT; }
// Tell the service controller we are starting ZeroMemory (&g_ServiceStatus, sizeof (g_ServiceStatus)); g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SESSIONCHANGE; g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; g_ServiceStatus.dwWin32ExitCode = 0; g_ServiceStatus.dwServiceSpecificExitCode = 0; g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) { XTrace (L"ADLX Call Service: ServiceMain: SetServiceStatus returned error"); }
/* * Perform tasks neccesary to start the service here */ XTrace (L"ADLX Call Service: ServiceMain: Performing Service Start Operations");
g_ADLXInitReady = CreateEvent(NULL, FALSE, FALSE, NULL); // Create stop event to wait on later. g_ServiceStopEvent = CreateEvent (NULL, TRUE, FALSE, NULL); if (g_ServiceStopEvent == NULL) { XTrace (L"ADLX Call Service: ServiceMain: CreateEvent(g_ServiceStopEvent) returned error");
g_ServiceStatus.dwControlsAccepted = 0; g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; g_ServiceStatus.dwWin32ExitCode = GetLastError (); g_ServiceStatus.dwCheckPoint = 1;
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) { XTrace (L"ADLX Call Service: ServiceMain: SetServiceStatus returned error"); } goto EXIT; }
// Tell the service controller we are started g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SESSIONCHANGE; g_ServiceStatus.dwCurrentState = SERVICE_RUNNING; g_ServiceStatus.dwWin32ExitCode = 0; g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) { XTrace (L"ADLX Call Service: ServiceMain: SetServiceStatus returned error"); }
// Start the thread that will perform the main task of the service HANDLE hThread = CreateThread (NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
XTrace (L"ADLX Call Service: ServiceMain: Waiting for Worker Thread to complete");
if (hThread) { // Wait until our worker thread exits effectively signaling that the service needs to stop WaitForSingleObject(hThread, INFINITE);
XTrace(L"ADLX Call Service: ServiceMain: Worker Thread Stop Event signaled"); } /* * Perform any cleanup tasks */ XTrace (L"ADLX Call Service: ServiceMain: Performing Cleanup Operations");
CloseHandle (g_ServiceStopEvent);
g_ServiceStatus.dwControlsAccepted = 0; g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; g_ServiceStatus.dwWin32ExitCode = 0; g_ServiceStatus.dwCheckPoint = 3;
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) { XTrace (L"ADLX Call Service: ServiceMain: SetServiceStatus returned error"); }
EXIT: XTrace (L"ADLX Call Service: ServiceMain: Exit");
return;}
DWORD WINAPI ServiceCtrlHandler (DWORD ctrlCode, DWORD eventType, LPVOID eventData, LPVOID context){ XTrace (L"ADLX Call Service: ServiceCtrlHandler: Entry");
switch (ctrlCode) { case SERVICE_CONTROL_STOP: { XTrace (L"ADLX Call Service: ServiceCtrlHandler: SERVICE_CONTROL_STOP Request");
if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING) break;
/* * Perform tasks neccesary to stop the service here */
g_ServiceStatus.dwControlsAccepted = 0; g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; g_ServiceStatus.dwWin32ExitCode = 0; g_ServiceStatus.dwCheckPoint = 4;
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) { XTrace (L"ADLX Call Service: ServiceCtrlHandler: SetServiceStatus returned error"); }
// This will signal the worker thread to shut down SetEvent (g_ServiceStopEvent); g_StopWorkThread = TRUE; } break; case SERVICE_CONTROL_SESSIONCHANGE: { XTrace(L"ADLX Call Service: ServiceCtrlHandler: SERVICE_CONTROL_SESSIONCHANGE"); WTSSESSION_NOTIFICATION* pSessionNotification = (WTSSESSION_NOTIFICATION*)eventData; switch (eventType) { case WTS_SESSION_LOGOFF: { XTrace(L"ADLX Call Service: ServiceCtrlHandler: WTS_SESSION_LOGOFF"); } break; case WTS_SESSION_LOGON: { XTrace(L"ADLX Call Service: ServiceCtrlHandler: WTS_SESSION_LOGON"); // When user logon, initialize ADLX if (!g_ADLXAlive) { auto res = ADLXHelper_Initialize(); if (ADLX_SUCCEEDED(res)) { XTrace(L"Initialize ADLX succeed: %d\n", res); g_ADLXAlive = true; } else { XTrace(L"Initialize ADLX failed: %d\n", res); } SetEvent(g_ADLXInitReady); } } break; default: break; } } break; default: break; }
XTrace (L"ADLX Call Service: ServiceCtrlHandler: Exit"); return NO_ERROR;}
DWORD WINAPI ServiceWorkerThread (LPVOID lpParam){ XTrace (L"ADLX Call Service: ServiceWorkerThread: Entry");
// Check if any user is logged on if (!IsAnyUserLogon()) { XTrace(L"No user logon, wait for user logon"); g_ADLXAlive = FALSE; WaitForSingleObject(g_ADLXInitReady, INFINITE); }
if (ADLX_FAILED(ADLXHelper_Initialize())) { XTrace(L"ADLX Call Service: GetAdlxGpuInfo: ADLX helper initalize failed."); return FALSE; } g_ADLXAlive = TRUE;
int loop = 40; while (loop-- > 0 && !g_StopWorkThread) { // Get GPU list IADLXSystem* sys = ADLXHelper_GetSystemServices(); IADLXGPUList* gpus = NULL; ADLX_RESULT res = sys->pVtbl->GetGPUs(sys, &gpus); if (ADLX_SUCCEEDED(res) && !gpus->pVtbl->Empty(gpus)) { IADLXGPU* gpu = NULL; res = gpus->pVtbl->At_GPUList(gpus, 0, &gpu); if (ADLX_SUCCEEDED(res) && gpu) { const char* vendorId = NULL; res = gpu->pVtbl->VendorId(gpu, &vendorId); if (ADLX_SUCCEEDED(res)) { XTrace(L"VenderId=%hs ", vendorId); }
const char* gpuName = NULL; res = gpu->pVtbl->Name(gpu, &gpuName); if (ADLX_SUCCEEDED(res)) { XTrace(L"GpuName=%hs", gpuName); } } if (gpu != NULL) { gpu->pVtbl->Release(gpu); gpu = NULL; } } if (gpus != NULL) { gpus->pVtbl->Release(gpus); gpus = NULL; } if (res == ADLX_ORPHAN_OBJECTS) { XTrace(L"ADLX return ADLX_ORPHAN_OBJECTS"); // Terminate ADLX, discard all the cached ADLX interfaces and wait for the right conditions to re-initialize ADLX ADLXHelper_Terminate(); g_ADLXAlive = FALSE;
//Attempt to re-initialize, if another user is still logged on if (IsAnyUserLogon()) { res = ADLXHelper_Initialize(); if (ADLX_SUCCEEDED(res)) { XTrace(L"ADLX recovered "); g_ADLXAlive = TRUE; } }
if (!g_ADLXAlive) { WaitForSingleObject(g_ADLXInitReady, INFINITE); continue; } }
// Get performance monitoring service IADLXPerformanceMonitoringServices* perfMonitorServ = NULL; res = sys->pVtbl->GetPerformanceMonitoringServices(sys, &perfMonitorServ); if (ADLX_SUCCEEDED(res)) { ADLX_IntRange range; res = perfMonitorServ->pVtbl->GetSamplingIntervalRange(perfMonitorServ, &range); XTrace(L"--GetSamplingIntervalRange: %d\n", res); XTrace(L"range.minValue: %d, range.maxValue: %d, range.step: %d", range.minValue, range.maxValue, range.step); } if (perfMonitorServ != NULL) { perfMonitorServ->pVtbl->Release(perfMonitorServ); perfMonitorServ = NULL; } if (res == ADLX_ORPHAN_OBJECTS) { XTrace(L"ADLX return ADLX_ORPHAN_OBJECTS"); // Terminate ADLX, discard all the cached ADLX interfaces and wait for the right conditions to re-initialize ADLX ADLXHelper_Terminate(); g_ADLXAlive = FALSE;
//Attempt to re-initialize, if another user is still logged on if (IsAnyUserLogon()) { res = ADLXHelper_Initialize(); if (ADLX_SUCCEEDED(res)) { XTrace(L"ADLX recovered "); g_ADLXAlive = TRUE; } }
if (!g_ADLXAlive) { WaitForSingleObject(g_ADLXInitReady, INFINITE); continue; } } Sleep(3000); }
Sleep(3000); ADLXHelper_Terminate();
XTrace (L"ADLX Call Service: ServiceWorkerThread: Exit");
return ERROR_SUCCESS;}
BOOL IsAnyUserLogon (){ BOOL isUserLogon = false; WTS_SESSION_INFO *pSessionInfo = NULL; DWORD sessionCount = 0; if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &sessionCount) == TRUE && pSessionInfo != NULL) { for (DWORD i = 0; i < sessionCount; i++) { if (pSessionInfo[i].State == WTSActive) { isUserLogon = true; break; } } WTSFreeMemory(pSessionInfo); } return isUserLogon;}
void InstallService (){ WCHAR path[512] = { 0 }; if (GetModuleFileNameW (NULL, path, 512) == 0) { XTrace (L"ADLX Call Service: InstallService: Cannot get g_SharedFile path."); return; }
SC_HANDLE serviceManager = OpenSCManager (NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE); if (serviceManager) { SC_HANDLE serviceHandle = CreateServiceW ( serviceManager, ADLX_SERVICE_NAME, ADLX_SERVICE_NAME, SERVICE_QUERY_STATUS, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, path, NULL, NULL, L"", NULL, NULL);
if (serviceHandle) { CloseServiceHandle (serviceHandle); } else { XTrace (L"ADLX Call Service: InstallService: Cannot create service."); }
CloseServiceHandle (serviceManager); } else { XTrace (L"ADLX Call Service: InstallService: Cannot open service."); }}
void RemoveService (){ SC_HANDLE serviceManager = OpenSCManager (NULL, NULL, SC_MANAGER_CONNECT); if (!serviceManager) { XTrace (L"ADLX Call Service: RemoveService: Cannot open service manager."); return; }
SC_HANDLE serviceHandle = OpenServiceW (serviceManager, ADLX_SERVICE_NAME, DELETE | SERVICE_STOP); if (!serviceHandle) { CloseServiceHandle (serviceManager); XTrace (L"ADLX Call Service: RemoveService: Cannot open service."); return; }
if (!DeleteService (serviceHandle)) { CloseServiceHandle (serviceHandle); CloseServiceHandle (serviceManager); XTrace (L"ADLX Call Service: RemoveService: Delete service failed."); return; }
XTrace (L"ADLX Call Service: RemoveService: Deleted service.");
SERVICE_STATUS serviceStatus = { 0 }; ControlService (serviceHandle, SERVICE_CONTROL_STOP, (LPSERVICE_STATUS)&serviceStatus);
CloseServiceHandle (serviceHandle); CloseServiceHandle (serviceManager);}See Also: ADLX Macro, ADLX_IntRange, ADLX Enums