Click here to Skip to main content
15,892,298 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I isolated the following code which is a Windows console application which creates a Kernel timer which will be fired every 3s then wait.

When running, if I quickly clic on No, the behavior is as expected.

But If I wait 10s or more before cliking on No, I expect all the APC in the queue (which are supposed to have been queued every 3s when I was waiting before clicking No on the first MessageBox) to be executed successively, which means to have the same number of MessageBox displayed each after each other when I click No immediatly after they are displayed. It seams that only 1 or 2 APC have been queued instead.

Any idea?


C++
// TestKernelTimer.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <sdkddkver.h>

#include <stdio.h>
#include <tchar.h>
#include <time.h>
#include <string>
#include <sstream>
#include <iostream>

#include <windows.h>

class MyClass
{
public:
    MyClass()
		{
			m_event = NULL;
		}
	~MyClass() {}

	void do_it();
	void print(const char* strMsg);
	
	void OnTimerEvent();

	int AskMessage(const char* title, const char* message);

	static std::string GetCurrentTime();

private:
	HANDLE			m_timer;
	HANDLE			m_event;
};

// Console application entryt point
int _tmain(int argc, _TCHAR* argv[])
{
	MyClass *theMyClass;
	theMyClass = new MyClass();
	theMyClass->do_it();
	delete theMyClass;

	return 0;
}

// Return the current time as a string
std::string MyClass::GetCurrentTime()
{
	char buff[20];
	time_t now = time(NULL);
	strftime(buff, 20, "%Y-%m-%d %H:%M:%S", localtime(&now));
	return buff;
}

// Output a message in the console
void MyClass::print(const char* strMsg)
{
	DWORD threadID = GetCurrentThreadId();

	std::string str = GetCurrentTime();
	str += " [Thread:";
	std::stringstream ss;
	ss << threadID;
	ss << " (0x";
	ss << std::hex << threadID;
	str += ss.str().c_str();
	str += ")] ";
	str += strMsg;

	std::cout << str << std::endl;
}

// Timer APC
VOID CALLBACK TimerCallback(LPVOID lpArgToCompletionRoutine, DWORD dwTimerLowValue, DWORD dwTimerHighValue)
{
	MyClass* thisObj = (MyClass*) lpArgToCompletionRoutine;
	if (thisObj)
		thisObj->OnTimerEvent();
}

void MyClass::OnTimerEvent()
{
//LARGE_INTEGER liTimer = { 0 };
//liTimer.QuadPart = - (__int64)(3*10000000);	// number of 100 nanoseconds to wait before the first signal
//CancelWaitableTimer(m_timer);
	print("Enter OnTimerEvent");
		
	switch (AskMessage("NX Question", "Exit ?"))
	{
	case IDYES:
		print("MessageBox NX response OK: Exit");

		// Signal event to exit main thread wait
		SetEvent(m_event);
		break;

	case IDNO: // continue.
		print("MessageBox NX response NO: Continue");

//SetWaitableTimer(m_timer, &liTimer, 3000, TimerCallback, this, FALSE);
		break;

	default:
		print("MessageBox NX response Unknown !");
		break;
	}

	print("Exit OnTimerEvent");
}

// Ask something in the APC
int MyClass::AskMessage(const char* title, const char* message)
{
	print("Ask MessageBox");

	int response;
	response = MessageBox(NULL, message, title, MB_YESNO);
//	std::cin >> response;
//	SleepEx(1000, TRUE);

	return response;
}

// Put in place an APC timer then wait for an event to exit
void MyClass::do_it()
{
	print("Start !");

	print("Create Waitable Timer.");
	m_timer = CreateWaitableTimer(NULL, TRUE, NULL);
	LARGE_INTEGER liTimer = { 0 };
	liTimer.QuadPart = - (__int64)(3*10000000);	// number of 100 nanoseconds to wait before the first signal
	
	print("Start Timer");
	if (SetWaitableTimer(m_timer, &liTimer, 3000, TimerCallback, this, FALSE))
	{
		m_event = CreateEvent(NULL,FALSE,FALSE,NULL);
	
		print("Start Waiting...");

		bool exitWait = false;
		while (!exitWait)
		{
			// Bug reproduced,
			switch (WaitForSingleObjectEx(m_event, INFINITE, TRUE))
			{
			case WAIT_ABANDONED:
				print("Wait Abandoned !");
				exitWait = true;
				break;
			case WAIT_IO_COMPLETION:
				print("Wait IO completion !");
				break;
			case WAIT_OBJECT_0:
				print("Wait Object is signaled");
				exitWait = true;
				break;
			case WAIT_TIMEOUT:
				print("Wait Timeout !");
				exitWait = true;
				break;
			case WAIT_FAILED:
				print("Wait Failed !");
				exitWait = true;
				break;
			default:
				break;
			}
		}
		
		print("End Waiting !");
	}	

	CancelWaitableTimer(m_timer);
	CloseHandle(m_timer);
	print("End Timer");

	print("End !");
}
Posted
Updated 19-Nov-15 23:58pm
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900