KeSetSystemAffinityThread behavior - multithreading

Some questions about KeSetSystemAffinityThread function, since MSDN is quite laconic.
NOTE: I can't use the more complete KeSetSystemAffinityThreadEx because I must still support Windows XP.
1) How can I restore the previous affinity? The function does not return the old value, how can I obtain it?
2) Is it true that passing 0 to the function restores the default system affinity? I have found such assertion in some forums, but I can't find it in official MS documentation.
3) Is the new thread's system affinity mask maintained after a return to user mode, or is it restored to the default each time the thread enters in system mode?
4) What happens if previous system affinity mask is not restored?
(I'd rather post four different questions, but they seem to me too interdependent)

Use the undocumented KeRevertToUserAffinityThread(void) in WinXP. A quick search yields little information about the API but I found an implementation of the same function in ReastOS :
ReactOS KeRevertToUserAffinityThread
It is rather simple so I copy & paste it here:
VOID NTAPI KeRevertToUserAffinityThread ( VOID )
{
KIRQL OldIrql;
PKPRCB Prcb;
PKTHREAD NextThread, CurrentThread = KeGetCurrentThread();
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
ASSERT(CurrentThread->SystemAffinityActive != FALSE);
/* Lock the Dispatcher Database */
OldIrql = KiAcquireDispatcherLock();
/* Set the user affinity and processor and disable system affinity */
CurrentThread->Affinity = CurrentThread->UserAffinity;
CurrentThread->IdealProcessor = CurrentThread->UserIdealProcessor;
CurrentThread->SystemAffinityActive = FALSE;
/* Get the current PRCB and check if it doesn't match this affinity */
Prcb = KeGetCurrentPrcb();
if (!(Prcb->SetMember & CurrentThread->Affinity))
{
/* Lock the PRCB */
KiAcquirePrcbLock(Prcb);
/* Check if there's no next thread scheduled */
if (!Prcb->NextThread)
{
/* Select a new thread and set it on standby */
NextThread = KiSelectNextThread(Prcb);
NextThread->State = Standby;
Prcb->NextThread = NextThread;
}
/* Release the PRCB lock */
KiReleasePrcbLock(Prcb);
}
/* Unlock dispatcher database */
KiReleaseDispatcherLock(OldIrql);
}
Note the function takes no argument and just restore the affinity from some elements in the currrent KTHREAD struct. I guess this answer your question 1 & 2. Just call this function with no argument. I have done a test in 32bit WinXP and confirmed this. Question 4 is simple, your thread will continue to run using the processor affinity your've set.
I have no idea to your question 3. But most likely a switch between user and kernel mode has no effect on the current processor affinity in effect since this is something stored in the KTHREAD struct.

Related

Why does initscr() after a delwin() return undef?

Why does the delwin cause the second initscr to return nothing? I thought the endwin would reset to the state as it was before calling initscr.
use NCurses;
my $win = initscr();
addstr( 'AAA' );
nc_refresh();
sleep 2;
delwin( $win );
endwin();
...
my $new_win = initscr();
if ! $new_win.defined {
endwin();
dd $new_win; # NCurses::WINDOW $new_win = NCurses::WINDOW
die "win undefined"; # win undefined
}
addstr( 'BBB' );
nc_refresh();
sleep 2;
delwin( $new_win );
endwin;
What's actually happening is that initscr returns stdscr (the standard window). The delwin deleted it (and the pointer is part of a SCREEN structure which is duly updated), so a subsequent call to initscr (not having created a new screen with newterm) will return that NULL pointer. In principle, an application could reference curscr and newscr (two other windows created during initialization), but the Perl interface likely ignores those.
It helps to read the documentation however. Quoting the Differences section of the initscr manual page:
Differences
X/Open specifies that portable applications must not call initscr more
than once:
The portable way to use initscr is once only, using refresh (see
curs_refresh(3x)) to restore the screen after endwin.
This implementation allows using initscr after endwin.
Old versions of curses, e.g., BSD 4.4, may have returned a null pointer
from initscr when an error is detected, rather than exiting. It is
safe but redundant to check the return value of initscr in XSI Curses.

Using shared memory from different threads

I have a strange issue with multi-threading. I want to print a table view and therefore start a new thread which runs with a progress bar. Eventually this thread dies with memory errors for which I'm seeking the cause. Right now I got
malloc: * error for object 0x10000078c: Invalid signature for
pointer dequeued from free list
set a breakpoint in malloc_error_break to debug CaLister(27054,0x7fff73ea3300) malloc: error for object
0x60800043bcc0: Invalid pointer dequeued from free list
* set a breakpoint in malloc_error_break to debug
But most of the times (still it happens rarely!) it just stops with no specific (but definitely memory related) error. When I look from the debugger my data are nil. But they have not been touched since they are still being available for display in my table view.
Now the question: is there any precaution I need to take to access data being allocated in the main thread so I can safely access them from the detached thread?
Edit:
My print thread is dispatched like this (stripped code):
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) { self.performPrint (true) }
func performPrint (async:Bool) {
//First get the shared print info object so we know page sizes. The shared print info object acts like a global variable.
let sharedPrintInfo = NSPrintInfo.sharedPrintInfo()
let printObject = PSPrint ()
//Allocate a new instance of NSView into the variable printPageView
var frame = NSRect(x: 0, y: 0, width: sharedPrintInfo.paperSize.width-sharedPrintInfo.leftMargin-sharedPrintInfo.rightMargin, height: sharedPrintInfo.paperSize.height-sharedPrintInfo.topMargin-sharedPrintInfo.bottomMargin)
let basePrintPageView = PSPrintView(frame: frame)
var printPageView:PSPrintView
for pageNo in 1...paperDimensions.pages {
paperDimensions.pageNo = pageNo
printPageView = basePrintPageView.clone(pageNo)
//Set the option for the printView for what it should draw.
paperDimensions.pageNo = pageNo
//Finally append the view to the PSPrint Object.
printObject.printViews.append(printPageView)
}
dispatch_async(dispatch_get_main_queue()) {
printObject.printTheViews() //print all the views, each view being a 'page'.
}
}
Within
printPageView = basePrintPageView.clone(pageNo)
the access to my table view (where I get the data to be printed) returns nil sometimes.
Edit2: I just noticed that it's not the background thread which crashed, but the main thread :-/ Scratching my head even more but likely I have to close this question.

Ambient Light Sensor Interrupt Status register not getting updated

I'm using WinCE 7 Visual Studio 2008 and writing a driver code for ALS (MAX44009). I have written the following code for reading the interrupt status register and displaying messages when the interrupt has occurs. But, it works randomly for a few times only. For eg., when I close the sensor with my hand, I get the messages only few times, and then, it doesn't go into the data==1 condition even when it has to interrupt and continues to loop. The threshold timer is 0. The AlsRegRead function does an I2CRead. pAlsDrvInfo is the driver context. ADD_ALS_INT_STATUS is 0. DumpAlsRegistry function will print the content of all the registers except register 0x0.
while(1)
{
AlsRegRead(pAlsDrvInfo, ADD_ALS_INT_STATUS, &data, sizeof(UINT8));
if (data == 1)
{
DumpAlsRegistry(pAlsDrvInfo);
RETAILMSG(1,(L"Interrupt Received...\r\n"));
}
}
Please guide me where I'm making mistake.
I have found the reason behind this. Two issues had been behind this and both of them are equally important.
1) The sensor had been in a partially damaged state.
2) It requires some delay. So, I added Sleep(1000) at the start of the loop.
while(1)
{
Sleep(1000);
AlsRegRead(pAlsDrvInfo, ADD_ALS_INT_STATUS, &data, sizeof(UINT8));
if (data == 1)
{
DumpAlsRegistry(pAlsDrvInfo);
RETAILMSG(1,(L"Interrupt Received...\r\n"));
}
}
Thanks.

Freeing a BSTR using ::SysFreeString(). More Platform Dependant?

I am writing a COM Server which have a plenty of Interfaces and methods. And most of the methods have the BSTR as the parameters and as local parameters used for the return. A snippet looks like
Update 5:
The real code. This fetches from bunch of Data based on a specific condition the DB to populate an array of Object.
STDMETHODIMP CApplication::GetAllAddressByName(BSTR bstrParamName, VARIANT *vAdddresses)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
//check the Database server connection
COleSafeArray saAddress;
HRESULT hr;
// Prepare the SQL Strings dan Query the DB
long lRecCount = table.GetRecordCount();
if (lRecCount > 0)
{
//create one dimension safe array for putting details
saAddress.CreateOneDim(VT_DISPATCH,lRecCount);
IAddress *pIAddress = NULL;
//retrieve details
for(long iRet = table.MoveFirst(),iCount=0; !iRet; iRet = table.MoveNext(),iCount++)
{
CComObject<CAddress> *pAddress;
hr = CComObject<CAddress>::CreateInstance(&pAddress);
if (SUCCEEDED(hr))
{
BSTR bstrStreet = ::SysAllocString(table.m_pRecordData->Street);
pAddress->put_StreetName(bstrStreet);
BSTR bstrCity = ::SysAllocString(table.m_pRecordData->City);
pAddress->put_CityName(bstrCity);
}
hr = pAddress->QueryInterface(IID_IAddress, (void**)&pIAddress);
if(SUCCEEDED(hr))
{
saAddress.PutElement(&iCount,pIAddress);
}
}
*vAdddresses=saAddress.Detach();
}
table.Close();
return S_OK;
}
STDMETHODIMP CAddress::put_CityName(BSTR bstrCityName)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
// m_sCityName is of CComBSTR Type
m_sCityName.Empty();//free the old string
m_sCityName = ::SysAllocString(bstrCityName);//create the memory for the new string
return S_OK;
}
The problem lies in the Memory Freeing part. The code works very fine in any Win XP machines, but when comes to WIN2K8 R2 and WIN7 the code crashes and pointing to the ::SysFreeString() as the culprit. The MSDN is not adequate to the solution.
Can anyone please help in finding the right solution?
Thanks a lot in advance :)
Update 1:
I have tried using the CComBSTR as per the suggestion in the place of raw BSTR, initialized using direct CString's and excluded the SysFreeString(). But for my trouble, on getting out of scope the system is calling the SysFreeString() which again causes the crash :(
Update 2:
With the same CComBSTR i tried to allocate using the SysAllocString() , the problem remains same :(
Update 3:
I am tired of all the options and in peace I am having only question in mind
Is it necessary to free the BSTR through SysFreeString() which was
allocated using SysAllocString()/string.AllocSysString()?
Update 4:
I missed to provide the information about the crash. When I tried to debug the COM server crashed with a error saying
"Possible Heap Corruption"
. Please help me out of here.. :(
// Now All Things are packed in to the Object
obj.Name = bstrName;
obj.Name2 = bstrname2;
I don't quite understand what do you mean by saying that things are packed since you're just copying pointers to the strings, and at the moment when you call SysFreeString obj.Name and obj.Name2 will point to an invalid block of memory. Although this code is not safe, it looks like if the source of your problem is class CFoo. You should show us more details of your code
I suggest you to use a CComBSTR class which will take a responsibility for releasing the memory.
UPDATE
#include <atlbase.h>
using namespace ATL;
...
{
CComBSTR bstrname(_T("Some Name"));
CComBSTR bstrname2(_T("Another Name"));
// Here one may work with these variables if needed
...
// Copy the local values to the Obj's member Variable
bstrname.Copy(&obj.Name);
bstrname2.Copy(&obj.Name2);
}
UPDATE2
First of all one should free bstrCity and bstrStreetName with SysFreeString or use CComBSTR instead within this block:
if (SUCCEEDED(hr))
{
BSTR bstrStreet = ::SysAllocString(table.m_pRecordData->Street);
pAddress->put_StreetName(bstrStreet);
BSTR bstrCity = ::SysAllocString(table.m_pRecordData->City);
pAddress->put_CityName(bstrCity);
// SysFreeString(bstrStreet)
// SysFreeString(bstrCity)
}
Consider to amplify the loop's condition !iRet with iCount < lRecCount.
for(...; !iRet /* && (iCount < lRecCount) */; ...)
Also, here:
m_sCityName = ::SysAllocString(bstrCityName);
you allocate memory but never release it since internally CComBSTR& operator = (OLESTR ..) allocates a new storage itself. One should rewrite is as follows:
m_sCityName = bstrCityName;
Everything else, looks good for me
UPDATE3
Well, Heap corruption is often a consequence of writing some values outside of the allocated memory block. Say you allocate an array of length 5 and put some value to the 6th position
Finally I have found the real reason for the Heap Corruption that happened in the code.
The put_StreetName/put_CityName of the IAddress/CAddress is designed in a following way.
STDMETHODIMP CAddress::put_CityName(BSTR bstrCityName)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
m_sCityName.Empty();
TrimBSTR(bstrCityName);
m_sCityName = ::SysAllocString(bstrCityName);
return S_OK;
}
BSTR CAddress::TrimBSTR(BSTR bstrString)
{
CString sTmpStr(bstrString);
sTmpStr.TrimLeft();
sTmpStr.TrimRight();
SysReAllocString(&bstrString,sTmpStr); // The Devilish Line
}
The Devilish Line of code is the real culprit that caused the Memory to go hell.
What caused the trouble?
In this line of code, the BSTR string passed as a parameter is from another application and the real memory is in another realm. So the system is trying to reallocate teh string. Either succeed or not, the same is tried to cleared off from the memory in original application/realm, thus causing a crash.
What still unsolved?
Why the same piece of code doesn't crashed a single time in Win XP and
older systems? :(
Thanks for all who took their time to answer and solve my problem :)

question on Implementing IQueryCancelAutoPlay in a windows service

I am implementing IQueryCancelAutoPlay COM interface and registering it with the Running Objects Table from a Windows Service*.
My problem is that it never gets called when I insert a mass storage device (or any device really). Here's some more information:
My code for registering with the ROT:
Text::string clsIdString = Text::to_string(Com::CLSID_QCAListener);
// remove curly braces
clsIdString = clsIdString.substr(1, clsIdString.length() - 2);
// set registry key to make sure we get notifications from windows
Reg::SetValue(HKEY_LOCAL_MACHINE,
_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\CancelAutoplay\\CLSID"),
clsIdString, _T(""));
HRESULT result = S_OK;
// create class moniker ...
CComPtr<IMoniker> moniker;
result = CreateClassMoniker(Com::CLSID_QCAListener, &moniker);
if( !ValidateResult(result, "Error creating class moniker") )
return;
DBG << _T("Getting IRunningObjectTable pointer ...") << std::endl;
// get running oject table ...
CComPtr<IRunningObjectTable> runningObjectTable;
result = GetRunningObjectTable(0, &runningObjectTable);
if( !ValidateResult(result, "Error getting running object table") )
return;
// create an instance of the QCAListener class ...
Com::QCAListener * listenerInstance = new Com::QCAListener();
if(!ValidateResult( listenerInstance != 0,
"Error creating QueryCancelAutoplayListener"))
return;
// ... and set the pointer in the _qcaListener variable
CComPtr<IQueryCancelAutoPlay> qcaListener;
listenerInstance->QueryInterface(IID_IQueryCancelAutoPlay, reinterpret_cast<void**>(&qcaListener));
DBG << _T("Registering IQueryCancelAutoPlay with ROT ...") << std::endl;
result = runningObjectTable->Register(
ROTFLAGS_REGISTRATIONKEEPSALIVE,
listenerInstance,
moniker,
&_qcaRegistration);
ValidateResult(result, "Error registering QueryCancelAutoplayListener with the ROT");
runningObjectTable->Register returns S_OK, and at the end of the code block's execution the ref-count for listenerInstance is 1 (if I remove the call to runningObjectTable->Register completely, the ref-count remains 0 when qcaListener goes out of scope so this means an instance of my class remains active in the ROT).
More details: In development, my service runs with my account credentials (local administrator). Although this will probably change, it should work as it is with the current configuration.
Can anyone shed any light on this?
*- I know the documentation says I shouldn't implement IQueryCancelAutoPlay in a service but I need to do this for various reasons (business requirement, etc).
I figured it out (for those who stumble upon this answer when having a similar problem):
The service runs under a different window station and a different desktop. When the IQueryCalcelAutoPlay implementation is registered in the ROT this is done for a different desktop.
The current user's desktop shell (explorer) will not find this registration when a new USB device is inserted (as it is not registered with the current desktop).

Resources