pthread_join hangs forever C++ - c++

I am running this g_test where I simply initialize and close a client.
TEST(safIpc, createAndCloseClient)
{
std::shared_ptr<fnv::ipcsvc::IpcSvc> safIpc = std::make_shared<fnv::ipcsvc::IpcSvc>();
const std::string& app1 {"/testApp1"};
const std::string& groupName {"wir_clients"};
fnv::ipcsvc::IpcSvcAttrMq attr(fnv::ipcsvc::IpcSvcAttrType::MQ_CLIENT,
app1,
groupName,
"/server");
std::shared_ptr<IpcSvcTestSafHandler> msgHandler = std::make_shared<IpcSvcTestSafHandler>();
// initialize the ipc library
IpcSvcPriv::SharedPtr ipcPrivData {nullptr};
fnv::ipcsvc::IpcSvcRet ret = safIpc->init(attr, msgHandler, ipcPrivData);
EXPECT_EQ(ret, fnv::ipcsvc::IpcSvcRet::SUCCESS);
EXPECT_NE(ipcPrivData, nullptr);
ret = safIpc->close(ipcPrivData, app1); //HANGS here
EXPECT_EQ(fnv::ipcsvc::IpcSvcRet::SUCCESS, ret);
}
In init I create 3 threads: (here is the relevant part of the init code):
1- A process thread
2- a Receive thread
3- A timer thread
int rc = pthread_create(&m_timerThread,
NULL,
&IpcSvcImpl::timer_start,
this);
if (rc != 0)
{
ipcSvcLog(LOGE, "Failed to create timer thread!");
close(tmpPrivData,
attr.getAppId());
return error;
}
pthread_setname_np(m_timerThread,
"IpcSvcTimerThread");
}
// Start the worker threads
int rc = pthread_create(&m_receiveThread,
NULL,
&IpcSvcImpl::receive,
this);
if (rc != 0)
{
//TODO some error log
close(tmpPrivData,
attr.getAppId());
return error;
}
pthread_setname_np(m_receiveThread,
"IpcSvcReceiveThread");
rc = pthread_create(&m_processThread,
NULL,
&IpcSvcImpl::process,
this);
if (rc != 0)
{
//TODO some error log
close(tmpPrivData,
attr.getAppId());
return error;
}
pthread_setname_np(m_processThread,
"IpcSvcProcessThread");
Here is the close function:
IpcSvcRet IpcSvcImpl::close(IpcSvcPriv::SharedPtr privateData,
const std::string& appId)
{
if (!privateData)
{
//TODO log about client not providing sane private data
return IpcSvcRet::FAIL;
}
// acquire the mutex and set close called to true
{
std::lock_guard<std::mutex> guard(m_closeMtx);
m_closed = true;
}
if (m_msgQueue)
{
m_msgQueue->mutexInit();
// writing dummy message to process thread
std::pair<std::array<uint8_t, IPCSVC_MAX_MSG_SIZE>, ssize_t> queueMsg;
m_msgQueue->enqueue(queueMsg);
}
// writing dummy message to receive thread
uint32_t buffer = 0;
sendData(privateData,
(void*)&buffer,
sizeof(uint32_t),
appId);
pthread_join(m_receiveThread,
NULL);
pthread_join(m_processThread,
NULL);
if (m_isClient)
{
m_cv.notify_one();
printf("timer thread hangs\n"); // HANGS HERE ///////////////////////////////////////
pthread_join(m_timerThread,
NULL);
//This line is never reached..
}
delete m_msgQueue;
m_msgQueue = nullptr;
// close the ipc layer
if (m_ipc)
{
m_ipc->close();
delete m_ipc;
m_ipc = nullptr;
}
m_clientsList.clear();
m_hbManager = { };
return IpcSvcRet::SUCCESS;
}
Here is the timer_start function:
The timer thread is a timer that is keeps looping forever unless the fc->m_closed is set to true. It triggers fc->timerExpiry() every 2 seconds.
// timer thread entry
void* IpcSvcImpl::timer_start(void *arg)
{
if (!arg)
{
return nullptr;
}
printf("starting timer\n");
IpcSvcImpl* fc = static_cast<IpcSvcImpl *>(arg);
std::unique_lock<std::mutex> lock(fc->m_closeMtx);
while (!(fc->m_closed))
{
printf("Entering loop\n");
lock.unlock();
auto expireAt = std::chrono::steady_clock::now() +
std::chrono::seconds(fc->getTimerInterval());
fc->timerExpiry();
lock.lock();
printf("here?\n");
fc->m_cv.wait_until(lock, expireAt);
printf("Here 2\n");
}
printf("Exited loop\n\n");
return nullptr;
}
The output of the unittest:
[----------] 5 tests from safIpc
[ RUN ] safIpc.createAndCloseClient
starting timer
Entering loop
closing..
timer thread hangs
pthread join hangs forever, I am not sure why. The "here" prints are never hit, which seems odd.
Thanks for the help!

Related

Force Windows to load my service before any other non-critical ones

As discussed in WTSQueryUserToken throws error 1008, even when running under LocalSystem, I'm having trouble getting my Windows service to launch an interactive process on a particular user's desktop as soon as they log in.
The proposed solution there was to handle the SERVICE_CONTROL_SESSIONCHANGE control code and use the passed dwSessionId. Here's all of the code (apologies that it's quite lengthy, but I was told to post it here anyway):
// These headers just contain system header #include's function prototypes
// and global variable declarations. If a variable below seems like it is
// undefined, rest assured that it *is* defined in one of these headers.
#include "events.h"
#include "main.h"
int __cdecl _tmain(int argc, LPTSTR argv[]) {
sysStart = system_clock::now();
LogInit();
// If command-line parameter is "install", install the service.
// Otherwise, the service is probably being started by the SCM
if (lstrcmpi(argv[1], L"install") == 0) {
return SvcInstall();
}
SERVICE_TABLE_ENTRY dispatchTable[] = {
{ &svcName[0], (LPSERVICE_MAIN_FUNCTION)SvcMain },
{ nullptr, nullptr }
};
// This call returns when the service has stopped. The
// process should simply terminate when the call returns
if (!StartServiceCtrlDispatcher(dispatchTable)) {
ReportSvcEvent("StartServiceCtrlDispatcher");
}
return ERROR_SUCCESS;
}
char* WINAPI GetTimestamp(string& buf) {
int ms = (high_resolution_clock::now().
time_since_epoch().count() / 1000000) % 1000;
auto tt = system_clock::to_time_t(
system_clock::now());
tm time;
localtime_s(&time, &tt);
strftime(&buf[0], 21, "[%d-%m-%Y %T", &time);
snprintf(&buf[0], 26, "%s.%03d] ", &buf[0], ms);
buf[25] = ' ';
return &buf[0];
}
bool WINAPI LaunchDebugger(void) {
// Get System directory, typically C:\Windows\System32
wstring systemDir(MAX_PATH + 1, '\0');
UINT nChars = GetSystemDirectory(&systemDir[0], systemDir.length());
if (nChars == 0) {
return false; // failed to get system directory
}
systemDir.resize(nChars);
// Get process ID and create the command line
// wostringstream ss;
// ss << systemDir << L"\\vsjitdebugger.exe -p " << GetCurrentProcessId();
wstring cmdLine = L"";
// Start debugger process
STARTUPINFOW si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcess(nullptr, &cmdLine[0], nullptr,
nullptr, false, 0, nullptr, nullptr, &si, &pi)) {
return false;
}
// Close debugger process handles to eliminate resource leaks
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
// Wait for the debugger to attach
while (!IsDebuggerPresent()) {
Sleep(100);
}
// Stop execution so the debugger can take over
DebugBreak();
return true;
}
VOID WINAPI LogActiveTime(void) {
// The computer is shutting down - write an entry to logFile to reflect
// this, prefixed with a null byte to mark the current file position
// (used for parsing in the timestamp on the next system boot)
logFile << '\0';
LogMessage("User action", "System shutting down after being "
"active for " + DurationString(system_clock::now() - sysStart));
logFile.close();
// If the log file contains > 40 lines (10 boot/shutdown cycles),
// remove the first 4 lines (the earliest boot/shutdown cycle).
// This stops the file from getting too long to read easily
ifstream inFile(logFilePath);
string line;
auto count = 0;
while (getline(inFile, line)) {
count++;
}
}
DWORD WINAPI LogError(const string& funcName) {
auto err = 0;
LogMessage(funcName, system_category(
).message(err = GetLastError()), true);
return err;
}
DWORD WINAPI LogInactiveTime(void) {
// Create a new log file to be used as the input on the next run
LogInit("temp");
// Open the existing log file for reading and find the last shutdown
// log entry by copying its contents to the new file until a null byte
// or EOF is found (see LogActiveTime() for more info)
ifstream inFile(logFilePath);
if (!inFile) {
return LogError("LogInactiveTime");
}
char ch = inFile.get();
while (ch != '\0' && !inFile.eof()) {
logFile << ch;
ch = inFile.get();
}
if (inFile.eof()) {
// No shutdown log entry was found, i.e. this is probably the first
// time the service has run on the current instance of our log file.
// Close the temp file and re-open the original log file before
// returning, otherwise future messages won't make it to the file!
LogInit();
return ERROR_SUCCESS;
}
// At this point we can be sure that a valid shutdown log entry
// exists, so we now need to parse it into a chrono::time_point.
// Also save the entry's starting position in pos for later use
auto pos = inFile.tellg();
auto tt = system_clock::to_time_t(sysStart);
tm start, end = { 0 };
localtime_s(&start, &tt);
inFile >> get_time(&end, "[%d-%m-%Y %T");
if (inFile.fail() || inFile.bad()) {
return LogError("LogInactiveTime");
}
// Ensure that both time_points refer to
// the correct time, regardless of DST
end.tm_isdst = start.tm_isdst;
sysEnd = system_clock::from_time_t(mktime(&end));
// Go back to the *actual* start of the shutdown
// log entry so we can copy it into the new file
inFile.seekg(pos);
// Finish copying over the rest of our existing log
// file, then close it and replace it with the new one
ch = inFile.get();
while (!inFile.eof()) {
logFile << ch;
ch = inFile.get();
}
inFile.close();
remove(logFilePath.c_str());
logFile.close();
rename("temp", logFilePath.c_str());
// Finally, do what we *actually* came here to do!
LogMessage("User action", "System booting after being "
"inactive for " + DurationString(sysStart - sysEnd));
return ERROR_SUCCESS;
}
VOID WINAPI LogInit(const string& filePath) {
setlocale(LC_ALL, "en_US.UTF8");
if (logFile.is_open()) {
logFile.close();
}
logFile.open(filePath == "" ?
logFilePath : filePath, ios::app);
if (!logFile) {
exit(GetLastError());
}
}
VOID WINAPI LogMessage(const string& funcName,
const string& msg, bool isError) {
if (!logFile.is_open()) {
LogInit();
}
string buf(52, '\0');
snprintf(&buf[0], 52, "%s%-6s %-18s ", GetTimestamp(buf),
isError ? "ERROR:" : "INFO:", &(funcName + ':')[0]);
buf[51] = ' ';
logFile << buf << msg << endl;
}
VOID WINAPI ReportSvcEvent(const string& funcName) {
HANDLE eventSrc = RegisterEventSource(nullptr, &svcName[0]);
if (eventSrc != nullptr) {
LPCSTR errParams[2] = { "WinUtilities" };
char buf[MAX_PATH];
StringCchPrintfA(buf, MAX_PATH, "Function '%s' failed: %s",
funcName.c_str(), system_category().message(GetLastError(
)).c_str());
errParams[1] = buf;
ReportEventA(eventSrc, // event log handle
EVENTLOG_ERROR_TYPE, // event type
0, // event category
SVC_ERROR, // event identifier
nullptr, // no security identifier
2, // size of lpszStrings array
0, // no binary data
errParams, // array of strings
nullptr); // no binary data
DeregisterEventSource(eventSrc);
}
}
VOID WINAPI ReportSvcStatus(DWORD newState,
DWORD exitCode, DWORD waitHint) {
static DWORD dwCheckPoint = 1;
static unordered_map<int, string> svcStates;
if (svcStates.empty()) {
// Initialise mapping from service state codes to readable strings
svcStates.insert({ SERVICE_STOPPED, "Stopped" });
svcStates.insert({ SERVICE_START_PENDING, "Start Pending" });
svcStates.insert({ SERVICE_STOP_PENDING, "Stop Pending" });
svcStates.insert({ SERVICE_RUNNING, "Running" });
svcStates.insert({ SERVICE_CONTINUE_PENDING, "Continue Pending" });
svcStates.insert({ SERVICE_PAUSE_PENDING, "Pause Pending" });
svcStates.insert({ SERVICE_PAUSED, "Paused" });
}
// Update the SERVICE_STATUS structure with the new passed-in values
svcStatus.dwCurrentState = newState;
svcStatus.dwWin32ExitCode = exitCode;
svcStatus.dwWaitHint = waitHint;
if (newState == SERVICE_START_PENDING) {
svcStatus.dwControlsAccepted = 0;
} else {
svcStatus.dwControlsAccepted =
SERVICE_ACCEPT_SESSIONCHANGE |
SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PRESHUTDOWN;
}
if (newState == SERVICE_RUNNING ||
newState == SERVICE_STOPPED) {
svcStatus.dwCheckPoint = 0;
} else {
svcStatus.dwCheckPoint = dwCheckPoint++;
}
// Report the status of the service to the SCM and our log file
if (!SetServiceStatus(statusHandle, &svcStatus)) {
LogError("SetServiceStatus");
} else {
LogMessage("SetServiceStatus", "Service status " \
"updated to '" + svcStates[newState] + "'.");
}
}
DWORD WINAPI SvcCtrlHandler(DWORD ctrlCode, DWORD
eventType, LPVOID eventData, LPVOID context) {
switch (ctrlCode) {
case SERVICE_CONTROL_SESSIONCHANGE: {
auto sessionId = ((WTSSESSION_NOTIFICATION*
)eventData)->dwSessionId;
switch (eventType) {
case WTS_SESSION_LOGON: {
string userName;
DWORD size;
WTSQuerySessionInformationA(WTS_CURRENT_SERVER_HANDLE, sessionId,
WTS_INFO_CLASS::WTSUserName, (LPSTR*)&userName[0], &size);
ReportSvcEvent("log on");
// A user has successfully logged on to the PC. Now we can start
// an interactive worker process under that user's account which
// will perform the actual work that we want to do
STARTUPINFO si = { 0 };
si.cb = sizeof(si);
si.wShowWindow = true;
HANDLE hToken;
if (!WTSQueryUserToken(sessionId, &hToken)) {
LogError("WTSQueryUserToken");
return ERROR_CALL_NOT_IMPLEMENTED;
}
wstring cmdLine = L"C:\\Path\\to\\my\\app.exe";
if (!CreateProcessAsUser(hToken, &cmdLine[0], nullptr, nullptr, nullptr,
false, CREATE_NO_WINDOW, nullptr, nullptr, &si, &workerProc)) {
LogError("CreateProcessAsUser");
return ERROR_CALL_NOT_IMPLEMENTED;
}
CloseHandle(hToken);
break;
} default: {
break;
}
}
break;
} case SERVICE_CONTROL_STOP: {
// Signal the service to stop
ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
SetEvent(svcStopEvent);
break;
} case SERVICE_CONTROL_PRESHUTDOWN: {
LogActiveTime();
break;
} default: {
return ERROR_CALL_NOT_IMPLEMENTED;
}
}
return NO_ERROR;
}
VOID WINAPI SvcInit(DWORD argc, LPTSTR argv[]) {
// Get the time at which the last shutdown occurred, and
// log the duration for which the system was inactive
if (LogInactiveTime() > 0) {
return;
}
// Create an event. The control handler function (SvcCtrlHandler)
// signals this event when it receives the stop control code
svcStopEvent = CreateEvent(
nullptr, // default security attributes
TRUE, // manual reset event
FALSE, // not signaled
nullptr); // no name
if (svcStopEvent == nullptr) {
LogError("CreateEvent");
ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
return;
}
// Report running status when initialisation is complete
ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
// Wait until our stop event has been signalled
WaitForSingleObject(svcStopEvent, INFINITE);
// Code execution won't reach here until the service has been
// fully stopped. Report this to the SCM when it happens, then
// terminate the worker process and clean up its handles
ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
if (workerProc.hProcess) {
TerminateProcess(workerProc.hProcess, 0);
CloseHandle(workerProc.hProcess);
CloseHandle(workerProc.hThread);
}
}
DWORD WINAPI SvcInstall(void) {
TCHAR path[MAX_PATH];
if (!GetModuleFileName(nullptr, path, MAX_PATH)) {
return LogError("GetModuleFileName");
}
// Get a handle to the SCM database
auto scm = OpenSCManager(
nullptr, // local computer
nullptr, // ServicesActive database
SC_MANAGER_ALL_ACCESS); // full access rights
if (scm == nullptr) {
return LogError("OpenSCManager");
}
// Create the service
auto svc = CreateService(
scm, // SCM database
&svcName[0], // name of service
L"Windows Utilities", // service name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS, // service type
SERVICE_AUTO_START, // start type
SERVICE_ERROR_NORMAL, // error control type
path, // path to service's binary
nullptr, // no load ordering group
nullptr, // no tag identifier
nullptr, // no dependencies
nullptr, // LocalSystem account
nullptr); // no password
if (svc == nullptr) {
CloseServiceHandle(scm);
return LogError("CreateService");
}
SERVICE_DESCRIPTION sd;
sd.lpDescription = const_cast<LPTSTR>(L"Logs system "
"shutdown events to a text file on the desktop. "
"Also creates a system-wide hot key to perform "
"internet searches on any selected text.");
if (!ChangeServiceConfig2(
svc, // handle to service
SERVICE_CONFIG_DESCRIPTION, // change: description
&sd)) // new description
{
CloseServiceHandle(svc);
CloseServiceHandle(scm);
return LogError("ChangeServiceConfig2");
}
CloseServiceHandle(svc);
CloseServiceHandle(scm);
LogMessage("SvcInstall", "Service installed successfully.");
return ERROR_SUCCESS;
}
VOID WINAPI SvcMain(DWORD argc, LPTSTR argv[]) {
// Register the handler function for the service
statusHandle = RegisterServiceCtrlHandlerEx(
&svcName[0], SvcCtrlHandler, 0);
if (!statusHandle) {
ReportSvcEvent("RegisterServiceCtrlHandlerEx");
return;
}
// These SERVICE_STATUS members remain as set here
svcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
svcStatus.dwServiceSpecificExitCode = 0;
// Report initial status to the SCM
ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
// Perform service-specific initialization and work
SvcInit(argc, argv);
}
The part that doesn't work is in the SvcCtrlHandler() function, where I'm trying to catch the aforementioned control code.
I've even gone so far as to rewrite this whole thing in C# (which is the language that I should have used in the first place since my code is soooooooooo much cleaner and clearer now) and guess what? I still have the exact same problem with the OnSessionChange() method!
When I cold boot the computer and allow my PC to autologin to my single user account, nothing happens (i.e. no app.exe started). But if I then log out and back in again, I get the results I'm looking for.
So it seems as though my service is one of the last few to load and this is stopping it from properly catching the SERVICE_CONTROL_SESSIONCHANGE control code. How can I fix this? MTIA! :D

Read access violation in GetDlgItem when thread is closed and program is shut down

I'm having trouble understand an exception thrown (read access violation, this is nullptr) when closing my application. The exception occurs on GetDlgItem(IDC_Button1)->EnableWindow(true); when the CDialogEx::OnCancel(); is called. It appears as though the thread is correctly shut down but the error still persists.
When c_DialogFunctionsThreadRunning = false; is called before the MessageBox then the issue does not occur but this also means the thread is terminated before the prompt is accepted or cancelled.
void CFRP_3D_PrinterDlg::OnBnClickedShutdown()
{
if (MessageBox(_T("Close program?"), _T("Program"), MB_ICONQUESTION | MB_OKCANCEL | MB_TOPMOST) == IDOK)
{
c_DialogFunctionsThreadRunning = false;
StateMachine.StateEnter(ShutDown);
CDialogEx::OnCancel();
}
}
void CFRP_3D_PrinterDlg::DialogFunctionsThread()
{
c_DialogFunctionsThreadRunning = true;
CWinThread *CDialogFunctionsThread = AfxBeginThread(DoDialogFunctions, this, THREAD_PRIORITY_NORMAL, 0, 0, nullptr);
CDialogFunctionsThread->m_bAutoDelete = true;
}
UINT CFRP_3D_PrinterDlg::DoDialogFunctions(LPVOID t)
{
CFRP_3D_PrinterDlg *DialogFunctions = static_cast<CFRP_3D_PrinterDlg *>(t);
DialogFunctions->DoDialogFunctions();
return NULL;
}
void CFRP_3D_PrinterDlg::DoDialogFunctions()
{
while (c_DialogFunctionsThreadRunning && c_DialogCreated)
{
GetDlgItem(IDC_Button1)->EnableWindow(true);
Sleep(20);
}
}
This issue is happening because the call CDialogEx::OnCancel() destroy all the UI elements ,then the Thread is trying to access a deleted item, the way to solve this is as follow:
when you create the thread, store the return value in a member variable of the class:
class CFRP_3D_PrinterDlg{
CWinThread *CDialogFunctionsThread;
//.....
};
void CFRP_3D_PrinterDlg::DialogFunctionsThread()
{
c_DialogFunctionsThreadRunning = true;
CDialogFunctionsThread = AfxBeginThread(DoDialogFunctions, this, THREAD_PRIORITY_NORMAL, 0, 0, nullptr);
CDialogFunctionsThread->m_bAutoDelete = true;
}
then in the prompt to cancel it wait for the thread to finish before to call OnCancel, in this example is waiting forever but you use your own time.
void CFRP_3D_PrinterDlg::OnBnClickedShutdown()
{
if (MessageBox(_T("Close program?"), _T("Program"), MB_ICONQUESTION | MB_OKCANCEL | MB_TOPMOST) == IDOK)
{
c_DialogFunctionsThreadRunning = false;
StateMachine.StateEnter(ShutDown);
::WaitForSingleObject(CDialogFunctionsThread->m_hThread, INFINITE);
CDialogEx::OnCancel();
}
}

Auto Thread resume c++

i build Simple Anticheat module for a game and i need protect the Thread's from a Suspend (Like Suspend Thread from Processhacker).
Is there any way to automatically resume the thread if is suspended?
Here is my module code:
#include "stdafx.h"
#include "Start.h"
void Msg_Sf_Br(){
MessageBoxA(NULL,"SpeedHack - Detect", load.Nome_das_Janelas, MB_SERVICE_NOTIFICATION | MB_ICONWARNING);
ExitProcess(0);
}
void Msg_Sf_En(){
MessageBoxA(NULL,"SpeedHack - Detect", load.Nome_das_Janelas, MB_SERVICE_NOTIFICATION | MB_ICONWARNING);
ExitProcess(0);
}
void Speed_perf()
{
if( *(unsigned long*)QueryPerformanceCounter != 2337669003 ){
if (load.Log_Txt_Hack == 1){
}
if (load.Message_Warning_En == 1){
ExitProcess(0);
}
if (load.Message_Warning_En == 2){
CreateThread(NULL,NULL,LPTHREAD_START_ROUTINE(Msg_Sf_Br),NULL,0,0);
Sleep(3000);
ExitProcess(0);
}
if (load.Message_Warning_En == 0){
ExitProcess(0);
}
else
ExitProcess(0);
}
}
void performance(){
if (load.Anti_Kill_Scans == 1)
{
again:
Speed_perf();
Sleep(load.Detecta_Speed_PerformanceT);
goto again;
}
else
{
again2:
Speed_perf();
Sleep(load.Detecta_Speed_PerformanceT);
goto again2;
}
}
void SPerformance(){
CreateThread(NULL,NULL,LPTHREAD_START_ROUTINE(performance),NULL,0,0);
}
Any idea?
With a little trick you can hide your thread from any debugger or tools like process hacker.
void func()
{
}
int main()
{
int(__stdcall* ZwCreateThreadEx)(HANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, HANDLE, PVOID, PVOID, ULONG, ULONG_PTR, SIZE_T, SIZE_T, PVOID) = (decltype(ZwCreateThreadEx))GetProcAddress(GetModuleHandle("ntdll.dll"),"ZwCreateThreadEx");
HANDLE hThread=0;
ZwCreateThreadEx(&hThread,0x1FFFFF,0,GetCurrentProcess(),
(LPTHREAD_START_ROUTINE)func,0, 0x4/*hide flag*/,0,0x1000,0x10000,0);
return 0;
}
You can do it this way:
get list of process thread ids, using CreateToolhelp32Snapshot
go to first thread using methods: Thread32First.
for each found thread (you should check if belong to the given process):
then Open the thread using OpenThread in manner to retrieve handle to the thread from it thread id,
when you have the handle, you can suspend the thread using SuspendThread in manner to retrieve the previous suspension count,
then you can Resume the thread until it suspension count is 0. you must resume at least once in manner to cancel the suspension from the previous step.
if thread are not allowed to be suspended, you can use ResumeThread just to get the suspension count even if it was not suspended.
Close the thread handle using CloseHandle
iterate to next thread use Thread32Next.
In manner to be able to do the whole thing you must run as administrator.
Here is an example:
void TraverseProcessThreads(DWORD pid)
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); //get list of all system thread
if( hSnapshot == INVALID_HANDLE_VALUE)
{
//print error and return;
return;
}
THREADENTRY32 threadEntry;
if( Thread32First( hSnapshot, &threadEntry) )
{
size_t threadsCounter = 0, suspendedThreadsCounter=0;
do{
if(te.th32OwnerProcessID == pid) //we get all threads in system, should filter the relevant pid.
{
threadsCounter ++; //found thread
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS,FALSE,te.th32ThreadID); //get handle to thread from its thread id
if(hThread == NULL) //
{
//print error and break. (will be permission error if not administrator)
break;
}
int suspensionCount = SuspendThread( hThread ) ;//will return previous suspension count. you can also use ResumeThread if there's no way it can be suspended.
if(suspensionCount > 0)
{
//thread was suspended
suspendedThreadsCounter ++;
}
//cancel our suspension...
suspensionCount = ResumeThread(hThread );
/*to resume suspended thread use ResumeThread until it return 1.
do{
suspensionCount = ResumeThread(hThread );
}while (suspensionCount > 1); //similar to Suspend Resume return previous Suspention count.
*/
}
CloseHandle(hThread);
}while(Thread32Next( hSnapshot, &threadEntry) );
//print results:
cout<<"process id"<<pid<<endl<<" has "<<threadsCounter <<" threads " <<endl
<<suspendedThreadsCounter <<" threads was suspended"<<endl;
}
else{
//print some error...
}
CloseHandle(hSnapshot);
}

Windows Errorcode : 298 for Bounded buffer solution in vc++

I have encountered bounded buffer problem in my project, For solving
this, im using 2 semaphores Full and empty.
Write operation waits for empty semaphore signal and signals full
semaphore after finishing write.
Read operation waits for Full semaphore signal and signals Empty
semaphore after read.
Since im using blocking calls for read and write, each read and
write happens in sequence.
i'm implementing this in VC++ in windows, but im facing windows
errorcode:298 while signalling empty semaphore which says Too many posts were made to a semaphore.
what would be the possible causes for the error 'too may posts were
made to a semaphore' ?
List item
semaphore creation:
string semName = m_mqName;
semName.append(SEMAPHORE_FULL_NAME_SUFFIX);
cout<<"\n <MessageQueue<DType, size>::CreateMsgQSemaphores ()> Semaphore name = "<<semName<<endl;
m_mqFullSemaphore = CreateSemaphore(
NULL, // default security attributes
0, // initial count
size, // maximum count
semName.c_str()); //semaphore name
if (m_mqFullSemaphore == nullptr)
{
cout<<"ERROR::CreateSemaphore Failed, Name:"<<semName<<",error code:"<<GetLastError()<<endl;
CloseHandle(m_mqMutex); // close the existing m_mqMutex
createSemaphoresStatus = CreateMsgQSemaphoresFailedError;
}
else if (ERROR_ALREADY_EXISTS == GetLastError())
{
cout<<"\n <MessageQueue<DType, size>::CreateMsgQSemaphores ()>::WARNING: 'full' Semaphore exist.. "<<semName<<endl;
}
else
//cout<<"***INFO:: semaphore created: m_mqFullSemaphore= "<<m_mqFullSemaphore<<endl;
//------------------------------------------Empty semaphore creation--------------------------------------------//
semName = m_mqName;
semName.append(SEMAPHORE_EMPTY_NAME_SUFFIX);
//cout<<"\n <MessageQueue<DType, size>::CreateMsgQSemaphores ()> Semaphore name = "<<semName<<endl;
m_mqEmptySemaphore = CreateSemaphore(
NULL, // default security attributes
size, // initial count
size, // maximum count
semName.c_str()); // semaphore Name
if(m_mqEmptySemaphore == nullptr)
{
cout<<"\n <MessageQueue<DType, size>::CreateMsgQSemaphores ()>::ERROR: Create empty Semaphore failed.. "<<semName<<endl;
CloseHandle(m_mqMutex); // close the existing m_mqMutex
createSemaphoresStatus = CreateMsgQSemaphoresFailedError;
}
Consumer thread (reader in my project)
DWORD dwFullSemaphoreWaitResult = WaitForSingleObject(m_mqFullSemaphore,
timeoutVal);//wair for full semaphore
if(dwFullSemaphoreWaitResult== WAIT_OBJECT_0) // got the full semaphore
{
//proceed further
DWORD dwMutexWaitResult = WaitForSingleObject( m_mqMutex, timeoutVal); // no time-out interval
//Queue_Mutex_Handler mutexHandler(m_mqMutex);
//RAII
LOG_MSG("SUCCESS: to aquire m_mqFullSemaphore:"<<m_mqName);
switch (dwMutexWaitResult)
{
case WAIT_OBJECT_0: // got ownership of the mutex
{
LOG_MSG("SUCCESS: to aquire m_mqMutex:"<<m_mqName);
size_t qSize = 0;
if(! m_pMsgQueueImpl->Dequeue(destMsg,qSize))
{
LOG_MSG("SUCCESS: Reached here:"<<m_mqName);
LOG_MSG("ERROR: Dequeue failed, MSG Queue is Empty:"<< m_mqName);
//ReleaseMutex(m_mqMutex);
execResult = MQState_Queue_Empty_Error;
if(0 == ReleaseMutex(m_mqMutex))
{
LOG_MSG("Release mutex error:"<<GetLastError());
}
}
else
{
int semCount = 0;
LOG_MSG("MQ POP successful:"<< m_mqName<<", qSize="<<qSize);
//ReleaseMutex(m_mqMutex);
if(0 == ReleaseMutex(m_mqMutex))
{
LOG_MSG("Release mutex error:"<<GetLastError());
}
if ( 0 == ReleaseSemaphore(
m_mqEmptySemaphore, // handle to semaphore
1, // increase count by one
NULL)) // not interested in previous count
{
//LOG_MSG("semCount = "<<semCount);
LOG_MSG("Release Empty Semaphore error: "<<GetLastError());
}
else
{
//LOG_MSG("semCount = "<<semCount);
LOG_MSG("empty Semaphore signalled successfully");
}
return (int)qSize;
}
break;
}
case WAIT_TIMEOUT:
{
LOG_MSG("ERROR: Failed to aquire Mutex:"<<m_mqName<<", due to Timeout:"<<timeoutVal);
execResult = MQState_QOpTimeOut_Error;
break;
}
default: // The thread got ownership of an abandoned mutex
{
LOG_MSG("ERROR: Failed to aquire Mutex:"<<m_mqName<<", due to GetLastError:"<<GetLastError());
execResult = MQState_Queue_Unhandled_Error;
}
} // end of switch (dwMutexWaitResult)
}
else if(dwFullSemaphoreWaitResult == WAIT_TIMEOUT)
{
LOG_MSG("ERROR: Failed to aquire m_mqFullSemaphore:"<<m_mqName<<", due to Timeout:"<<timeoutVal);
execResult = MQState_QOpTimeOut_Error;
}
else
{
LOG_MSG("ERROR: Failed to aquire m_mqFullSemaphore:"<<m_mqName<<", GetLastError:"<<GetLastError());
execResult = MQState_Queue_Unhandled_Error;
}
if(execResult != MQState_QOp_Success)
return execResult;
//=================================================================================================
//LOG_FUNC_END;
return execResult;
Producer thread
MSG_QUEUE_STATUS execResult = MQState_QOp_Success;
//Wait for empty semaphore
DWORD dwSemaphoreWaitResult = WaitForSingleObject( m_mqEmptySemaphore, // handle to mutex
timeoutValInMs); // time-out interval
LOG_MSG("m_mqEmptySemaphore: "<<m_mqEmptySemaphore);
LOG_MSG("Got the m_mqEmptySemaphore");
//Wait for mutex
if(dwSemaphoreWaitResult == WAIT_OBJECT_0)
{
DWORD dwMutexWaitResult = WaitForSingleObject( m_mqMutex, // handle to mutex
timeoutValInMs); // time-out interval
//Queue_Mutex_Handler mutexHandler(m_mqMutex);
LOG_MSG("Got the m_mqMutex");
switch(dwMutexWaitResult)
{
case WAIT_OBJECT_0:
LOG_MSG("going to send Message");
if(m_pMsgQueueImpl->Enqueue(srcMsg) )
{
LOG_MSG("Message Sent successfully");
//int semCount;
if(0 == ReleaseMutex(m_mqMutex))
{
LOG_MSG("Release mutex error:"<<GetLastError());
}
if ( 0 == ReleaseSemaphore(
m_mqFullSemaphore, // handle to semaphore
1, // increase count by one
NULL)) // not interested in previous count
{
//LOG_MSG("semCount = "<<semCount);
LOG_MSG("Release full Semaphore error: "<<GetLastError());
}
else
{
//LOG_MSG("semCount = "<<semCount);
LOG_MSG("full Semaphore signalled successfully");
}
///++++++++++++++
}
else
{
LOG_MSG("ERROR: Enqueue failed, MSG Queue is Full, QName = "<< m_mqName);
if(0 == ReleaseMutex(m_mqMutex))
{
LOG_MSG("Release mutex error:"<<GetLastError());
}
execResult = MQState_Queue_Full_Error;
}
break;
case WAIT_TIMEOUT:
LOG_MSG("ERROR: Failed to aquire MsgQueue Mutex:"<<m_mqName<<", due to Timeout:"<<timeoutValInMs);
execResult = MQState_QOpTimeOut_Error;
break;
default:
LOG_MSG("ERROR: Failed to aquire MsgQueue Mutex:"<<m_mqName);
execResult = MQState_Queue_Unhandled_Error;
}//switch ends
}
else if(WAIT_TIMEOUT==dwSemaphoreWaitResult)
{
LOG_MSG("ERROR: Failed to aquire MsgQueue semaphore:"<<m_mqName<<", due to Timeout:"<<timeoutValInMs);
execResult = MQState_QOpTimeOut_Error;
}
else
{
LOG_MSG("ERROR: Failed to aquire MsgQueue semaphore:"<<m_mqName);
execResult = MQState_Queue_Unhandled_Error;
}
//RAII
//LOG_FUNC_END;
return execResult;

Crash when thread is deleted

I am developing an application with MFC.
The UI thread launch a worker thread and stop it when the app is closing. The issue is that the app is crashing each time it tries to delete the thread.
here is the code :
First the thread class and its implementation :
class FileThread : public CWinThread
{
public:
static FileThread* CreateWorkerThread(LPVOID params, UINT priority, UINT flags);
void InitThread();
void StopThread();
inline HANDLE GetStopHandle() const { return m_stopThread; }
inline HANDLE GetWaitHandle() const { return m_waitThread; }
private:
HANDLE m_stopThread;
HANDLE m_waitThread;
FileThread(): m_stopThread(NULL), m_waitThread(NULL) { }
static UINT MyThreadProc(LPVOID pParam);
};
FileThread* FileThread::CreateWorkerThread(LPVOID params, UINT priority, UINT flags)
{
return (FileThread*) AfxBeginThread(FileThread::MyThreadProc, params, priority, 0, flags);
}
void FileThread::InitThread()
{
m_stopThread = CreateEvent(0, TRUE, FALSE, 0);
m_waitThread = CreateEvent(0, TRUE, FALSE, 0);
}
void FileThread::StopThread()
{
::SetEvent(m_stopThread);
::WaitForSingleObject(m_waitThread, INFINITE);
::CloseHandle(m_stopThread);
::CloseHandle(m_waitThread);
}
UINT FileThread::MyThreadProc(LPVOID pParam)
{
ThreadData* pLink = (ThreadData*)pParam;
BOOL continueProcess = TRUE;
int returnCode = EXITCODE_SUCCESS;
while (continueProcess)
{
if(::WaitForSingleObject(pLink->pMe->GetStopHandle(), 0) == WAIT_OBJECT_0)
{
::SetEvent(pLink->pMe->GetWaitHandle());
continueProcess = FALSE;
}
// the thread is looking for some files...
}
delete pLink; // it was allocated from the UI thread
return returnCode;
}
Then, where I start the thread:
ThreadData * td = new ThreadData();
m_myFileThread = FileThread::CreateWorkerThread((LPVOID)td, THREAD_PRIORITY_LOWEST, CREATE_SUSPENDED);
td->pMe = m_myFileThread;
m_myFileThread->m_bAutoDelete = FALSE;
m_myFileThread->InitThread();
m_myFileThread->ResumeThread();
Finally, the stop (and the crash):
DWORD exitCode;
if (m_myFileThread != NULL && GetExitCodeThread(m_myFileThread->m_hThread, &exitCode) && (exitCode == STILL_ACTIVE))
{
m_myFileThread->StopThread();
if(::WaitForSingleObject(m_myFileThread->m_hThread, 5000) == WAIT_TIMEOUT)
{
TerminateThread(m_myFileThread->m_hThread, EXITCODE_ABORT);
}
}
if (m_myFileThread != NULL)
{
delete m_myFileThread; // => CRASH
}
It seems I try to delete something already deleted and end up with a heap corruption. I have try to set the m_bAutoDelete to TRUE and not delete the thread myself by I got the same crash (while the program was trying to call AfxEndThread).
The thread terminate its thread proc and return the exit code.
It looks to me like there is a problem here:
FileThread* FileThread::CreateWorkerThread(LPVOID params, UINT priority,
UINT flags)
{
return (FileThread*) AfxBeginThread(FileThread::MyThreadProc, params,
priority, 0, flags);
}
AfxBeginThread returns a CWinthread*, so just casting this to a derived class of your own does not make it an instance of that derived class. I'm surprised it works at all.
Rather than deriving FileThread from CWinThread, it might be better to hold a CWinthread* member variable inside your wrapper class and expose the thread handle via an accessor if necessary.