I'm studying multi-thread program using Visual c++ to develop a sound signal processing program. To create basic structure of the program, I wrote a simple code having four threads that move synchronously, but they do not work well.
Specifications are as follows.
There are four threads: bg_thread, main_thread, sub_thread [0], sub_thread [1].
bg_thread triggers main_thread at regular intervals
main_thread triggers sub_thread [0] every time and triggers sub_thread [1] once every two times.
main_thread is a function in main_class
sub_thread [0], sub_thread [1] are functions in sub_class
The program is as follows:
#include "process.h"
#include "windows.h"
#include "stdio.h"
class Sub_class
{
public:
HANDLE hEvent2;
Sub_class(int no);
bool loop_ok;
bool calcstart;
int sub_class_no;
void do_sub_loop2();
};
class Main_class {
public:
bool thread_go;
bool go_flag = false;
Sub_class *sub_cls[2];
Main_class();
~Main_class();
int start_loop();
};
Main_class *main_cls = 0;
HANDLE g_bg_wait = 0;
HANDLE g_main_event = 0;
bool bg_go = true;
unsigned __stdcall start_bg_loop(void *parg)
{
WaitForSingleObject(g_bg_wait, INFINITE);
while (bg_go)
{
Sleep(100); // goto sleep for 100 milliseconds
SetEvent(g_main_event);
}
return 0;
}
unsigned __stdcall start_main_loop(void *parg)
{
main_cls->start_loop();
return 0;
}
//---------------------------------------------------------------------------------
int main()
{
main_cls = new Main_class();
HANDLE hEvent = 0;
HANDLE hndl = 0;
hEvent = CreateEvent(NULL, TRUE, FALSE, "bg_event");
hndl = (HANDLE)_beginthreadex(0, 0, &start_bg_loop, 0, 0, 0);
g_bg_wait = hEvent;
hEvent = CreateEvent(NULL, FALSE, FALSE, "main_event");
hndl = (HANDLE)_beginthreadex(0, 0, &start_main_loop, 0, 0, 0);
g_main_event = hEvent;
main_cls->sub_cls[0] = new Sub_class(0);
main_cls->sub_cls[1] = new Sub_class(1);
Sleep(1000);
bg_go = false;
CloseHandle(g_bg_wait);
CloseHandle(g_main_event);
}
int Main_class::start_loop()
{
Sleep(10);
SetEvent(g_bg_wait);
while (thread_go)
{
WaitForSingleObject(g_main_event, INFINITE);
printf("Trigger SubClass 0\n");
sub_cls[0]->calcstart = true;
SetEvent(sub_cls[0]->hEvent2);
if (go_flag)
{
printf("Trigger SubClass 1\n");
sub_cls[1]->calcstart = true;
SetEvent(sub_cls[1]->hEvent2);
}
else
{
sub_cls[1]->calcstart = false;
}
go_flag = !go_flag;
}
return 0;
}
Main_class::Main_class()
{
thread_go = true;
}
Main_class::~Main_class()
{
thread_go = false;
}
static unsigned __stdcall executeLauncher2(void* args) {
reinterpret_cast<Sub_class*>(args)->do_sub_loop2();
return 0;
}
Sub_class::Sub_class(int no)
{
sub_class_no = no;
loop_ok = true;
hEvent2 = CreateEvent(0, FALSE, FALSE, "event_2");
_beginthreadex(0, 0, &executeLauncher2, (void *)this, 0, 0);
}
void Sub_class::do_sub_loop2()
{
while (loop_ok)
{
WaitForSingleObject(hEvent2, INFINITE);
if (calcstart) printf("Start SubClass %d : OK\n", sub_class_no);
else printf("Start SubClass %d : NG ---\n", sub_class_no);
}
}
The result of running this program is as follows:
Trigger SubClass 0
Start SubClass 0 : OK
Trigger SubClass 0
Trigger SubClass 1
Start SubClass 1 : NG ---
Start SubClass 0 : OK
Trigger SubClass 0
Start SubClass 1 : NG ---
Trigger SubClass 0
Trigger SubClass 1
Start SubClass 0 : OK
Start SubClass 1 : OK
Trigger SubClass 0
Start SubClass 0 : OK
Trigger SubClass 0
Trigger SubClass 1
Start SubClass 1 : NG ---
Start SubClass 0 : OK
Trigger SubClass 0
Start SubClass 1 : NG ---
Trigger SubClass 0
Trigger SubClass 1
Start SubClass 1 : OK
Start SubClass 0 : OK
Trigger SubClass 0
Start SubClass 1 : NG ---
As you can see from the result, sub_thread [1] is often invoked (line of NG) even though triggering sub_thread [0].
I want to create the program so that when sub_thread [0] is triggered, sub_thread [0] is invoked and when sub_thread [1] is triggered,
sub_thread [1] is invoked, that is, I want to prevent NG lines.
Could you teach me how to fix this program, please ?
Thank you in advance.
CreateEvent(0, FALSE, FALSE, "event_2");
Here you create or open the same event, because you pass a name to the function. Even multiple instances of your program would open the same event object. If any other program had created an event with such a generic name as "event_2", you would also open that. That's certainly not what you want.
Pass NULL for the last parameter to create distinct event objects for each thread. Named events are usually only used for cross-process synchronization (in which case one uses unique names like a GUID), which you don't need here.
Related
To terminate a blocking Input from another thread, I tried to simulate a input event or more precisely a kayboard input using WriteConsoleInput function.
#include<Windows.h>
#include<conio.h>
#include<thread>
void KillBlockingIO() {
DWORD entityWritten;
INPUT_RECORD inputs;
inputs.EventType = KEY_EVENT;
inputs.Event.KeyEvent.bKeyDown = true;
inputs.Event.KeyEvent.uChar.AsciiChar = VK_RETURN;
inputs.Event.KeyEvent.wRepeatCount = 0;
inputs.Event.KeyEvent.dwControlKeyState = 0;
inputs.Event.KeyEvent.wVirtualKeyCode = 0;
inputs.Event.KeyEvent.wVirtualScanCode = 0;
// inputs.Event = { true, 0, 0, 0, VK_RETURN, 0 }; // same as above
Sleep(2000);
WriteConsoleInputA(GetStdHandle(STD_INPUT_HANDLE), &inputs, 1, &entityWritten);
}
int main()
{
std::thread t(KillBlockingIO);
char c = _getch();
printf("character recieved without typing: %c\n", c);
t.join();
}
It is working but I'm not sure, I've used WriteConsoleInput function property because members like wVirtualKeyCode, wVirtualScanCode and dwControlKeyState is set zero. No matter what value I pass, It is always going to have same result. It is also not very well Documented. I tried finding code examples but there is no such example.
what is purpose of these parameters and How to use WriteConsoleInput function properly?
This question already has answers here:
Why does Windows 10 start extra threads in my program?
(3 answers)
Closed 5 years ago.
Here is the screenshot of the situation!
I created a Visual C++ Win32 Console Application with VS2010. When I started the application, I found that there were four threads: one 'Main Thread' and three worker threads (I didn't write any code).
I don't know where these three worker threads came from.
I would like to know the role of these three threads.
Thanks in advance!
Windows 10 implemented a new way of loading DLLs - several worker threads do it in parallel (LdrpWorkCallback). All Windows 10 processes now have several such threads.
Before Win10, the system (ntdll.dll) always loaded DLLs in a single thread, but starting with Win10 this behaviour changed. Now a "Parallel loader" exists in ntdll. Now the loading task (NTSTATUS LdrpSnapModule(LDRP_LOAD_CONTEXT* LoadContext)) can be executed in worker threads. Almost every DLL has imports (dependent DLLs), so when a DLL is loaded - its dependent DLLs are also loaded and this process is recursive (dependent DLLs have own dependencies).
The function void LdrpMapAndSnapDependency(LDRP_LOAD_CONTEXT* LoadContext) walks the current loaded DLL import table and loads its direct (1st level) dependent DLLs by calling LdrpLoadDependentModule() (which internally calls LdrpMapAndSnapDependency() for the newly loaded DLL - so this process is recursive). Finally, LdrpMapAndSnapDependency() needs to call NTSTATUS LdrpSnapModule(LDRP_LOAD_CONTEXT* LoadContext) to bind imports to the already loaded DLLs. LdrpSnapModule() is executed for many DLLs in the top level DLL load process, and this process is independent for every DLL - so this is a good place to parallelize. LdrpSnapModule() in most cases does not load new DLLs, but only binds import to export from already loaded ones. But if an import is resolved to a forwarded export (which rarely happens) - the new, forwarded DLL, is loaded.
Some current implementation details:
first of all, let us look into the struct _RTL_USER_PROCESS_PARAMETERS new field - ULONG LoaderThreads. this LoaderThreads (if set to nonzero) enables or disables "Parallel loader" in the new process. When we create a new process by ZwCreateUserProcess() - the 9th argument is
PRTL_USER_PROCESS_PARAMETERS ProcessParameters. but if we use CreateProcess[Internal]W() - we cannot pass PRTL_USER_PROCESS_PARAMETERS directly - only STARTUPINFO. RTL_USER_PROCESS_PARAMETERS is partially initialized from STARTUPINFO, but we do not control ULONG LoaderThreads, and it will always be zero (if we do not call ZwCreateUserProcess() or set a hook to this routine).
In the new process initialization phase, LdrpInitializeExecutionOptions() is called (from LdrpInitializeProcess()). This routine checks HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\<app name> for several values (if the <app name> subkey exists - usually it doesn't), including MaxLoaderThreads (REG_DWORD) - if MaxLoaderThreads exists - its value overrides RTL_USER_PROCESS_PARAMETERS.LoaderThreads.
LdrpCreateLoaderEvents() is called. This routine must create 2 global events: HANDLE LdrpWorkCompleteEvent, LdrpLoadCompleteEvent;, which are used for synchronization.
NTSTATUS LdrpCreateLoaderEvents()
{
NTSTATUS status = ZwCreateEvent(&LdrpWorkCompleteEvent, EVENT_ALL_ACCESS, 0, SynchronizationEvent, TRUE);
if (0 <= status)
{
status = ZwCreateEvent(&LdrpLoadCompleteEvent, EVENT_ALL_ACCESS, 0, SynchronizationEvent, TRUE);
}
return status;
}
LdrpInitializeProcess() calls void LdrpDetectDetour(). This name speaks for itself. it does not return a value but initializes the global variable BOOLEAN LdrpDetourExist. This routine first checks whether some loader critical routines are hooked - currently these are 5 routines:
NtOpenFile
NtCreateSection
NtQueryAttributesFile
NtOpenSection
NtMapViewOfSection
If yes - LdrpDetourExist = TRUE;
If not hooked - ThreadDynamicCodePolicyInfo is queried - full code:
void LdrpDetectDetour()
{
if (LdrpDetourExist) return ;
static PVOID LdrpCriticalLoaderFunctions[] = {
NtOpenFile,
NtCreateSection,
ZwQueryAttributesFile,
ZwOpenSection,
ZwMapViewOfSection,
};
static M128A LdrpThunkSignature[5] = {
//***
};
ULONG n = RTL_NUMBER_OF(LdrpCriticalLoaderFunctions);
M128A* ppv = (M128A*)LdrpCriticalLoaderFunctions;
M128A* pps = LdrpThunkSignature;
do
{
if (ppv->Low != pps->Low || ppv->High != pps->High)
{
if (LdrpDebugFlags & 5)
{
DbgPrint("!!! Detour detected, disable parallel loading\n");
LdrpDetourExist = TRUE;
return;
}
}
} while (pps++, ppv++, --n);
BOOL DynamicCodePolicy;
if (0 <= ZwQueryInformationThread(NtCurrentThread(), ThreadDynamicCodePolicyInfo, &DynamicCodePolicy, sizeof(DynamicCodePolicy), 0))
{
if (LdrpDetourExist = (DynamicCodePolicy == 1))
{
if (LdrpMapAndSnapWork)
{
WaitForThreadpoolWorkCallbacks(LdrpMapAndSnapWork, TRUE);//TpWaitForWork
TpReleaseWork(LdrpMapAndSnapWork);//CloseThreadpoolWork
LdrpMapAndSnapWork = 0;
TpReleasePool(LdrpThreadPool);//CloseThreadpool
LdrpThreadPool = 0;
}
}
}
}
LdrpInitializeProcess() calls NTSTATUS LdrpEnableParallelLoading (ULONG LoaderThreads) - as LdrpEnableParallelLoading(ProcessParameters->LoaderThreads):
NTSTATUS LdrpEnableParallelLoading (ULONG LoaderThreads)
{
LdrpDetectDetour();
if (LoaderThreads)
{
LoaderThreads = min(LoaderThreads, 16);// not more than 16 threads allowed
if (LoaderThreads <= 1) return STATUS_SUCCESS;
}
else
{
if (RtlGetSuiteMask() & 0x10000) return STATUS_SUCCESS;
LoaderThreads = 4;// default for 4 threads
}
if (LdrpDetourExist) return STATUS_SUCCESS;
NTSTATUS status = TpAllocPool(&LdrpThreadPool, 1);//CreateThreadpool
if (0 <= status)
{
TpSetPoolWorkerThreadIdleTimeout(LdrpThreadPool, -300000000);// 30 second idle timeout
TpSetPoolMaxThreads(LdrpThreadPool, LoaderThreads - 1);//SetThreadpoolThreadMaximum
TP_CALLBACK_ENVIRON CallbackEnviron = { };
CallbackEnviron->CallbackPriority = TP_CALLBACK_PRIORITY_NORMAL;
CallbackEnviron->Size = sizeof(TP_CALLBACK_ENVIRON);
CallbackEnviron->Pool = LdrpThreadPool;
CallbackEnviron->Version = 3;
status = TpAllocWork(&LdrpMapAndSnapWork, LdrpWorkCallback, 0, &CallbackEnviron);//CreateThreadpoolWork
}
return status;
}
A special loader thread pool is created - LdrpThreadPool, with LoaderThreads - 1 max threads. Idle timeout is set to 30 seconds (after which the thread exits) and allocated PTP_WORK LdrpMapAndSnapWork, which is then used in void LdrpQueueWork(LDRP_LOAD_CONTEXT* LoadContext).
Global variables used by the parallel loader:
HANDLE LdrpWorkCompleteEvent, LdrpLoadCompleteEvent;
CRITICAL_SECTION LdrpWorkQueueLock;
LIST_ENTRY LdrpWorkQueue = { &LdrpWorkQueue, &LdrpWorkQueue };
ULONG LdrpWorkInProgress;
BOOLEAN LdrpDetourExist;
PTP_POOL LdrpThreadPool;
PTP_WORK LdrpMapAndSnapWork;
enum DRAIN_TASK {
WaitLoadComplete, WaitWorkComplete
};
struct LDRP_LOAD_CONTEXT
{
UNICODE_STRING BaseDllName;
PVOID somestruct;
ULONG Flags;//some unknown flags
NTSTATUS* pstatus; //final status of load
_LDR_DATA_TABLE_ENTRY* ParentEntry; // of 'parent' loading dll
_LDR_DATA_TABLE_ENTRY* Entry; // this == Entry->LoadContext
LIST_ENTRY WorkQueueListEntry;
_LDR_DATA_TABLE_ENTRY* ReplacedEntry;
_LDR_DATA_TABLE_ENTRY** pvImports;// in same ordef as in IMAGE_IMPORT_DESCRIPTOR piid
ULONG ImportDllCount;// count of pvImports
LONG TaskCount;
PVOID pvIAT;
ULONG SizeOfIAT;
ULONG CurrentDll; // 0 <= CurrentDll < ImportDllCount
PIMAGE_IMPORT_DESCRIPTOR piid;
ULONG OriginalIATProtect;
PVOID GuardCFCheckFunctionPointer;
PVOID* pGuardCFCheckFunctionPointer;
};
Unfortunately LDRP_LOAD_CONTEXT is not contained in published .pdb files, so my definitions include only partial names.
struct {
ULONG MaxWorkInProgress;//4 - values from explorer.exe at some moment
ULONG InLoaderWorker;//7a (this mean LdrpSnapModule called from worker thread)
ULONG InLoadOwner;//87 (LdrpSnapModule called direct, in same thread as `LdrpMapAndSnapDependency`)
} LdrpStatistics;
// for statistics
void LdrpUpdateStatistics()
{
LdrpStatistics.MaxWorkInProgress = max(LdrpStatistics.MaxWorkInProgress, LdrpWorkInProgress);
NtCurrentTeb()->LoaderWorker ? LdrpStatistics.InLoaderWorker++ : LdrpStatistics.InLoadOwner++
}
In TEB.CrossTebFlags - now exist 2 new flags:
USHORT LoadOwner : 01; // 0x1000;
USHORT LoaderWorker : 01; // 0x2000;
Last 2 bits is spare (USHORT SpareSameTebBits : 02; // 0xc000)
LdrpMapAndSnapDependency(LDRP_LOAD_CONTEXT* LoadContext) includes the following code:
LDR_DATA_TABLE_ENTRY* Entry = LoadContext->CurEntry;
if (LoadContext->pvIAT)
{
Entry->DdagNode->State = LdrModulesSnapping;
if (LoadContext->PrevEntry)// if recursive call
{
LdrpQueueWork(LoadContext); // !!!
}
else
{
status = LdrpSnapModule(LoadContext);
}
}
else
{
Entry->DdagNode->State = LdrModulesSnapped;
}
So, if LoadContext->PrevEntry (say we load user32.dll. In the first call to LdrpMapAndSnapDependency(), LoadContext->PrevEntry will be always 0 (when CurEntry points to user32.dll), but when we recursively call LdrpMapAndSnapDependency() for it dependency gdi32.dll - PrevEntry will be for user32.dll and CurEntry for gdi32.dll), we do not direct call LdrpSnapModule(LoadContext); but LdrpQueueWork(LoadContext);.
LdrpQueueWork() is simply:
void LdrpQueueWork(LDRP_LOAD_CONTEXT* LoadContext)
{
if (0 <= ctx->pstatus)
{
EnterCriticalSection(&LdrpWorkQueueLock);
InsertHeadList(&LdrpWorkQueue, &LoadContext->WorkQueueListEntry);
LeaveCriticalSection(&LdrpWorkQueueLock);
if (LdrpMapAndSnapWork && !RtlGetCurrentPeb()->Ldr->ShutdownInProgress)
{
SubmitThreadpoolWork(LdrpMapAndSnapWork);//TpPostWork
}
}
}
We insert LoadContext to LdrpWorkQueue and if "Parallel loader" is started (LdrpMapAndSnapWork != 0) and not ShutdownInProgress - we submit work to loader pool. But even if the pool is not initialized (say because Detours exist) - there will be no error - we process this task in LdrpDrainWorkQueue().
In a worker thread callback, this is executed:
void LdrpWorkCallback()
{
if (LdrpDetourExist) return;
EnterCriticalSection(&LdrpWorkQueueLock);
PLIST_ENTRY Entry = RemoveEntryList(&LdrpWorkQueue);
if (Entry != &LdrpWorkQueue)
{
++LdrpWorkInProgress;
LdrpUpdateStatistics()
}
LeaveCriticalSection(&LdrpWorkQueueLock);
if (Entry != &LdrpWorkQueue)
{
LdrpProcessWork(CONTAINING_RECORD(Entry, LDRP_LOAD_CONTEXT, WorkQueueListEntry), FALSE);
}
}
We simply popup an entry from LdrpWorkQueue, convert it to LDRP_LOAD_CONTEXT* (CONTAINING_RECORD(Entry, LDRP_LOAD_CONTEXT, WorkQueueListEntry)) and call void LdrpProcessWork(LDRP_LOAD_CONTEXT* LoadContext, BOOLEAN LoadOwner).
void LdrpProcessWork(LDRP_LOAD_CONTEXT* ctx, BOOLEAN LoadOwner)
in general calls LdrpSnapModule(LoadContext) and in the end the next code is executed:
if (!LoadOwner)
{
EnterCriticalSection(&LdrpWorkQueueLock);
BOOLEAN bSetEvent = --LdrpWorkInProgress == 1 && IsListEmpty(&LdrpWorkQueue);
LeaveCriticalSection(&LdrpWorkQueueLock);
if (bSetEvent) ZwSetEvent(LdrpWorkCompleteEvent, 0);
}
So, if we are not LoadOwner (in worked thread), we decrement LdrpWorkInProgress, and if LdrpWorkQueue is empty then signal LdrpWorkCompleteEvent (LoadOwner can wait on it).
and finally, LdrpDrainWorkQueue() is called from LoadOwner (primary thread) to "drain" the WorkQueue. It can possible pop and directly execute tasks pushed to LdrpWorkQueue by LdrpQueueWork(), and yet is not popped by worked threads or because parallel loader is disabled (in this case LdrpQueueWork() also push LDRP_LOAD_CONTEXT but not really post work to worked thread), and finally wait (if need) on LdrpWorkCompleteEvent or LdrpLoadCompleteEvent events.
enum DRAIN_TASK {
WaitLoadComplete, WaitWorkComplete
};
void LdrpDrainWorkQueue(DRAIN_TASK task)
{
BOOLEAN LoadOwner = FALSE;
HANDLE hEvent = task ? LdrpWorkCompleteEvent : LdrpLoadCompleteEvent;
for(;;)
{
PLIST_ENTRY Entry;
EnterCriticalSection(&LdrpWorkQueueLock);
if (LdrpDetourExist && task == WaitLoadComplete)
{
if (!LdrpWorkInProgress)
{
LdrpWorkInProgress = 1;
LoadOwner = TRUE;
}
Entry = &LdrpWorkQueue;
}
else
{
Entry = RemoveHeadList(&LdrpWorkQueue);
if (Entry == &LdrpWorkQueue)
{
if (!LdrpWorkInProgress)
{
LdrpWorkInProgress = 1;
LoadOwner = TRUE;
}
}
else
{
if (!LdrpDetourExist)
{
++LdrpWorkInProgress;
}
LdrpUpdateStatistics();
}
}
LeaveCriticalSection(&LdrpWorkQueueLock);
if (LoadOwner)
{
NtCurrentTeb()->LoadOwner = 1;
return;
}
if (Entry != &LdrpWorkQueue)
{
LdrpProcessWork(CONTAINING_RECORD(Entry, LDRP_LOAD_CONTEXT, WorkQueueListEntry), FALSE);
}
else
{
ZwWaitForSingleObject(hEvent, 0, 0);
}
}
}
void LdrpDropLastInProgressCount()
{
NtCurrentTeb()->LoadOwner = 0;
EnterCriticalSection(&LdrpWorkQueueLock);
LdrpWorkInProgress = 0;
LeaveCriticalSection(&LdrpWorkQueueLock);
ZwSetEvent(LdrpLoadCompleteEvent);
}
I wrote a little debugger for analysing and looging certain problems. Now I implemented a hardwarebreakpoint for detecting the access of a memory address being overwritten. When I run my debugger with a test process, then everything works fine. When I access the address, the breakpoint fires and the callstack is logged. The problem is, when I run the same against an application running multiple threads. I'm replicating the breakpoint into every thread that gets created and also the main thread. None of the functions report an error and everything looks fine, but when the address is accessed, the breakpoint never fires.
So I wonder if there is some documentation where this is described or if there are additionaly things that I have to do in case of a multithreaded application.
The function to set the breakpoint is this:
#ifndef _HARDWARE_BREAKPOINT_H
#define _HARDWARE_BREAKPOINT_H
#include "breakpoint.h"
#define MAX_HARDWARE_BREAKPOINT 4
#define REG_DR0_BIT 1
#define REG_DR1_BIT 4
#define REG_DR2_BIT 16
#define REG_DR3_BIT 64
class HardwareBreakpoint : public Breakpoint
{
public:
typedef enum
{
REG_INVALID = -1,
REG_DR0 = 0,
REG_DR1 = 1,
REG_DR2 = 2,
REG_DR3 = 3
} Register;
typedef enum
{
CODE,
READWRITE,
WRITE,
} Type;
typedef enum
{
SIZE_1,
SIZE_2,
SIZE_4,
SIZE_8,
} Size;
typedef struct
{
void *pAddress;
bool bBusy;
Type nType;
Size nSize;
Register nRegister;
} Info;
public:
HardwareBreakpoint(HANDLE hThread);
virtual ~HardwareBreakpoint(void);
/**
* Sets a hardware breakpoint. If no register is free or an error occured
* REG_INVALID is returned, otherwise the hardware register for the given breakpoint.
*/
HardwareBreakpoint::Register set(void *pAddress, Type nType, Size nSize);
void remove(void *pAddress);
void remove(Register nRegister);
inline Info const *getInfo(Register nRegister) const { return &mBreakpoint[nRegister]; }
private:
typedef Breakpoint super;
private:
Info mBreakpoint[MAX_HARDWARE_BREAKPOINT];
size_t mRegBit[MAX_HARDWARE_BREAKPOINT];
size_t mRegOffset[MAX_HARDWARE_BREAKPOINT];
};
#endif // _HARDWARE_BREAKPOINT_H
void SetBits(DWORD_PTR &dw, size_t lowBit, size_t bits, size_t newValue)
{
DWORD_PTR mask = (1 << bits) - 1;
dw = (dw & ~(mask << lowBit)) | (newValue << lowBit);
}
HardwareBreakpoint::HardwareBreakpoint(HANDLE hThread)
: super(hThread)
{
mRegBit[REG_DR0] = REG_DR0_BIT;
mRegBit[REG_DR1] = REG_DR1_BIT;
mRegBit[REG_DR2] = REG_DR2_BIT;
mRegBit[REG_DR3] = REG_DR3_BIT;
CONTEXT ct;
mRegOffset[REG_DR0] = reinterpret_cast<size_t>(&ct.Dr0) - reinterpret_cast<size_t>(&ct);
mRegOffset[REG_DR1] = reinterpret_cast<size_t>(&ct.Dr1) - reinterpret_cast<size_t>(&ct);
mRegOffset[REG_DR2] = reinterpret_cast<size_t>(&ct.Dr2) - reinterpret_cast<size_t>(&ct);
mRegOffset[REG_DR3] = reinterpret_cast<size_t>(&ct.Dr3) - reinterpret_cast<size_t>(&ct);
memset(&mBreakpoint[0], 0, sizeof(mBreakpoint));
for(int i = 0; i < MAX_HARDWARE_BREAKPOINT; i++)
mBreakpoint[i].nRegister = (Register)i;
}
HardwareBreakpoint::Register HardwareBreakpoint::set(void *pAddress, Type nType, Size nSize)
{
CONTEXT ct = {0};
super::setAddress(pAddress);
ct.ContextFlags = CONTEXT_DEBUG_REGISTERS;
if(!GetThreadContext(getThread(), &ct))
return HardwareBreakpoint::REG_INVALID;
size_t iReg = 0;
for(int i = 0; i < MAX_HARDWARE_BREAKPOINT; i++)
{
if (ct.Dr7 & mRegBit[i])
mBreakpoint[i].bBusy = true;
else
mBreakpoint[i].bBusy = false;
}
Info *reg = NULL;
// Address already used?
for(int i = 0; i < MAX_HARDWARE_BREAKPOINT; i++)
{
if(mBreakpoint[i].pAddress == pAddress)
{
iReg = i;
reg = &mBreakpoint[i];
break;
}
}
if(reg == NULL)
{
for(int i = 0; i < MAX_HARDWARE_BREAKPOINT; i++)
{
if(!mBreakpoint[i].bBusy)
{
iReg = i;
reg = &mBreakpoint[i];
break;
}
}
}
// No free register available
if(!reg)
return HardwareBreakpoint::REG_INVALID;
*(void **)(((char *)&ct)+mRegOffset[iReg]) = pAddress;
reg->bBusy = true;
ct.Dr6 = 0;
int st = 0;
if (nType == CODE)
st = 0;
if (nType == READWRITE)
st = 3;
if (nType == WRITE)
st = 1;
int le = 0;
if (nSize == SIZE_1)
le = 0;
else if (nSize == SIZE_2)
le = 1;
else if (nSize == SIZE_4)
le = 3;
else if (nSize == SIZE_8)
le = 2;
SetBits(ct.Dr7, 16 + iReg*4, 2, st);
SetBits(ct.Dr7, 18 + iReg*4, 2, le);
SetBits(ct.Dr7, iReg*2, 1, 1);
ct.ContextFlags = CONTEXT_DEBUG_REGISTERS;
if(!SetThreadContext(getThread(), &ct))
return REG_INVALID;
return reg->nRegister;
}
I'm setting the breakpoint in the main debugger loop whenever a new thread is created CREATE_THREAD_DEBUG_EVENT but looking at the sourcecode of GDB it seems not to be done there, so maybe that is to early?
So I finally found the answer to this problem.
In the debug event loop, I'm monitoring the events that windows sends me. One of those events is CREATE_THREAD_DEBUG_EVENT which I used to set the hardware breakpoint whenever a new thread was created.
The problem is, that the notification of this event comes before the thread got actually started. So Windows is setting the context for the first time AFTER this event is sent, which of course overwrites any context data that I have set before.
The solution I implemented now is, when a CREATE_THREAD_DEBUG_EVENT comes I put a software breakpoint at the start adress of the thread, so that the first instruction is my breakpoint. When I receive the breakpoint event, I restore the original code and install the hardware breakpoint, which now fires fine.
If there is a better solution, I'm all ears. :)
I have a CFRunLoopTimer created within a C++ class as shown below:
#import <CoreFoundation/CoreFoundation.h>
void cClass::StartTimer()
{
if(!mActiveSenseTimer)
{
CFTimeInterval TIMER_INTERVAL = 5;
CFRunLoopTimerContext TimerContext = {0, this, NULL, NULL, NULL};
CFAbsoluteTime FireTime = CFAbsoluteTimeGetCurrent() + TIMER_INTERVAL;
mTimer = CFRunLoopTimerCreate(kCFAllocatorDefault,
FireTime,
0, 0, 0,
ActiveSenseTimerCallback,
&TimerContext);
NSLog(#"RunLoop:0x%x, TimerIsValid:%d, TimeIsNow:%f, TimerWillFireAt:%f",
CFRunLoopGetCurrent(),
CFRunLoopTimerIsValid(mActiveSenseTimer),
CFAbsoluteTimeGetCurrent(),
FireTime);
}
}
void ActiveSenseTimerCallback(CFRunLoopTimerRef timer, void *info)
{
NSLog(#"Timeout");
CFRunLoopTimerContext TimerContext;
TimerContext.version = 0;
CFRunLoopTimerGetContext(timer, &TimerContext);
((cClass *)TimerContext.info)->Timeout();
}
Calling cClass::StartTimer() results in the following log output:
RunLoop:0x7655d60, TimerIsValid:1, TimeIsNow:389196910.537962, TimerWillFireAt:389196915.537956
However, my timer never fires. Any ideas why?
Quote from the docs
A timer needs to be added to a run loop mode before it will fire. To add the timer to a run loop, use CFRunLoopAddTimer. A timer can be registered to only one run loop at a time, although it can be in multiple modes within that run loop.
Also make sure your run loop doesn't die before the timer fires.
Im implementing a chat application using Jabber/XMPP and gloox framework which should send and receive messages concurrently in Ubuntu Linux.
My current code implementation is :
int main()
{
...
int temp = pthread_create(&iSend, NULL, SendMessage, &b);
int temp1 = pthread_create(&iRecv, NULL, ConnServer, &b);
}
void* ConnServer(void *athis)
{
UserClient *t = (UserClient*)athis;
t->ConnecttosServer();
}
bool UserClient::ConnecttosServer()
{
//JID jid( "map#jo-hely.hu/gloox" );
j = new Client( iUserJid, iUser.getPassword() );
j->registerMessageHandler( this);
j->registerConnectionListener( this );
j->registerMessageSessionHandler(this);
bool result = j->connect(false);
if(result == true)
{
iConnected = true;
ConnectionError er = ConnNoError;
ConnectionError er1 = ConnNoError;
while(er == ConnNoError || er1 == ConnNoError)
{
er = j->recv(500000);
sleep(2);
}
delete j;
}
...
}
void* SendMessage(void * athis )// JID *aDest)
{
UserClient *t = (UserClient*)athis;
//JID *t = (JID)dest;
string ip ;
cout << "enter here";
cin >> ip;
if(t->iConnected == true)
{
if(t->iMessageSession == NULL )
{
string aBody = "hello";
MessageSession *session = new MessageSession(t->j, t->iDestJid);
session->registerMessageHandler(t);
session->send(aBody.c_str());
}
}
}
The problem faced is both the threads are created and pthread_join( ) is called for both.
The iSend thread is scheduled first but gets suspended at cin. Once the recv( ) function is called, which runs in iRecv thread, the recv call back function handleMessage( ) is called. However the control never shifts back to the iSend thread which should call SendMessage( ) function.
Please help
I cannot see in there how SendMessage ever sends more than one "hello" message.
There are various memory issues here of course, eg j won't get deleted at all if connect failed, and as its scope is function-only there is no real need to create it with new at all.
You cannot count on the iSend thread being scheduled first. That is completely up to the operating system.