What is the purpose of WSA_WAIT_EVENT_0 in overlapped IO? - c

All my experience in networking has been on linux so I'm an absolute beginner at windows networking. This is probably a stupid question but I can't seem to find the answer anywhere. Consider the following code snippet:
DWORD Index = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE, WSA_INFINITE, FALSE);
WSAResetEvent( EventArray[Index - WSA_WAIT_EVENT_0]);
Every time an event is selected from the EventArray WSA_WAIT_EVENT_0 is subtracted from the index but WSA_WAIT_EVENT_0 is defined in winsock2.h as being equal to zero.
Why is code cluttered with this seemingly needless subtraction? Obviously the compiler will optimize it out but still don't understand why it's there.

The fact that WSA_WAIT_EVENT_0 is defined as 0 is irrelevant (it is just an alias for WAIT_OBJECT_0 from the WaitFor(Single|Multiple)Object(s)() API, which is also defined as 0 - WSAWaitForMultipleEvents() is itself just a wrapper for WaitForMultipleObjectsEx(), though Microsoft reserves the right to change the implementation in the future without breaking existing user code).
WSAWaitForMultipleEvents() can operate on multiple events at a time, and its return value will be one of the following possibilities:
WSA_WAIT_EVENT_0 .. (WSA_WAIT_EVENT_0 + cEvents - 1)
A specific event object was signaled.
WSA_WAIT_IO_COMPLETION
One or more alertable I/O completion routines were executed.
WSA_WAIT_TIMEOUT
A timeout occurred.
WSA_WAIT_FAILED
The function failed.
Typically, code should be looking at the return value and act accordingly, eg:
DWORD ReturnValue = WSAWaitForMultipleEvents(...);
if ((ReturnValue >= WSA_WAIT_EVENT_0) && (ReturnValue < (WSA_WAIT_EVENT_0 + EventTotal))
{
DWORD Index = ReturnValue - WSA_WAIT_EVENT_0;
// handle event at Index as needed...
}
else if (ReturnValue == WSA_WAIT_IO_COMPLETION)
{
// handle I/O as needed...
}
else if (RetunValue == WSA_WAIT_TIMEOUT)
{
// handle timeout as needed...
}
else
{
// handle error as needed...
}
Which can be simplified given the fact that bAlertable is FALSE (no I/O routines can be called) and dwTimeout is WSA_INFINITE (no timeout can elapse), so there are only 2 possible outcomes - an event is signaled or an error occurred:
DWORD ReturnValue = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE, WSA_INFINITE, FALSE);
if (ReturnValue != WSA_WAIT_FAILED)
{
DWORD Index = ReturnValue - WSA_WAIT_EVENT_0;
WSAResetEvent(EventArray[Index]);
}
else
{
// handle error as needed...
}

The documentation says it will return WSA_WAIT_EVENT_0 if event 0 was signaled, WSA_WAIT_EVENT_0 + 1 if event 1 was signaled, and so on.
Sure, they set WSA_WAIT_EVENT_0 to 0 in this version of Windows, but what if it's 1 in the next version, or 100?

Related

FreeRTOS: xEventGroupWaitBits() crashes inside a loop with scheduler running

We have several tasks running on an STM32 MCU. In the main.c file we call all the init functions for the various threads. Currently there is one renewing xTimer to trigger a periodic callback (which, at present, does nothing except print a message that it was called). Declarations as follows, outside any function:
TimerHandle_t xMotorTimer;
StaticTimer_t xMotorTimerBuffer;
EventGroupHandle_t MotorEventGroupHandle;
In the init function for the thread:
xMotorTimer = xTimerCreateStatic("MotorTimer",
xTimerPeriod,
uxAutoReload,
( void * ) 0,
MotorTimerCallback,
&xMotorTimerBuffer);
xTimerStart(xMotorTimer, 100);
One thread starts an infinite loop that pauses on an xEventGroupWaitBits() to determine whether to enter an inner loop, which is then governed by its own state:
DeclareTask(MotorThread)
{
bool done = false;
EventBits_t event;
for (;;)
{
Packet * pkt = NULL;
event = xEventGroupWaitBits( MotorEventGroupHandle,
EVT_MOTOR_START | EVT_MOTOR_STOP, // EventBits_t uxBitsToWaitFor
pdTRUE, // BaseType_t xClearOnExit
pdFALSE, // BaseType_t xWaitForAllBits,
portMAX_DELAY //TickType_t xTicksToWait
);
if (event & EVT_MOTOR_STOP)
{
MotorStop(true);
}
if (event & EVT_MOTOR_START)
{
EnableMotor(MOTOR_ALL);
done = false;
while (!done && !abortTest)
{
xQueueReceive(motorQueue, &pkt, portMAX_DELAY);
if (pkt == NULL)
{
done = true;
} else {
done = MotorExecCmd(pkt);
done = ( uxQueueMessagesWaiting(motorQueue) == ( UBaseType_t ) 0);
FreePacket(pkt);
}
}
}
}
}
xEventGroupWaitBits() fires successfully once, the inner loop enters, then exits when the program state meets the expected conditions. The outer loop repeats as it should, but when it arrives again at the xEventGroupWaitBits() call, it crashes almost instantly. In fact, it crashes a few lines down into the wait function, at a call to uxTaskResetEventItemValue(). I can't even step the debugger into the function, as if calling a bad address. But if I check the disassembly, the memory address for the BL instruction hasn't changed since the previous loop, and that address is valid. The expected function is actually there.
I can prevent this chain of events happening altogether by not calling that xTimerStart() and leaving everything else as-is. Everything runs just fine, so it's definitely not xEventGroupWaitBits() (or at least not just that). We tried switching to xEventGroupGetBits() and adding a short osDelay to the loop just as an experiment. That also froze the whole system.
So, main question. Are we doing something FreeRTOS is not meant to do here, using xEventGroupWaitBits() with xTimers running? Or is there supposed to be something between xEventGroupWaitBits() calls, possibly some kind of state reset that we've overlooked? Reviewing the docs, I can't see it, but I could have missed a detail. The

Does WriteFile signal the event if it completes synchronously

Does the WriteFile function signal the event passed in via the lpOverlapped parameter if it completes synchronously and succeeds? Does it signal the event if it fails synchronously? I have opened the handle to a file with the FILE_FLAG_OVERLAPPED flag. I wasn't to able to figure this out from the documentation and couldn't repro this case easily in code.
first of all this question related not only to WriteFile but to any asynchronous I/O function - almost all functions which get pointer to an OVERLAPPED structure. because for all this functions IRP (I/O request packet) (look it definition in wdm.h) is allocated. hEvent handle from OVERLAPPED converted to object pointer and stored in PKEVENT UserEvent; member of IRP. the event is set (or not set) exactly when IRP is completed in IopCompleteRequest routine. the IRP completion function is common for all I/O api, so and rules (when completion fire) is related to all. unfortunately this is very bad documented. the win32 layer (compare NT layer) added additional ,very thin, issues here.
based on wrk src code, we can see that I/O Manager fire completion (was 3 types - event, apc and iocp (mutually exclusive)) for asynchronous io when
!NT_ERROR( irp->IoStatus.Status ) or irp->PendingReturned.
if we use native api, which direct return NTSTATUS - when (ULONG)status < 0xc0000000. but here was very problematic range 0x80000000 <= status < 0xc0000000 or NT_WARNING(status) when unclear - are completion (even set, apc or packet to iocp queue) will be set. this is because before allocate IRP I/O Manager do some basic checks and can return error from here. usually I/O Manager return errors from NT_ERROR(status) , which correct mean that will be no completion (event will be not set)), but exist and rarely exceptions. for example for ReadDirectoryChangesW (or ZwNotifyChangeDirectoryFile) the lpBuffer pointer must be DWORD-aligned (aligned exactly as FILE_NOTIFY_INFORMATION) otherwise I/O Manager return STATUS_DATATYPE_MISALIGNMENT (0x80000002) from NT_WARNING range. but will be no completion (event set) in this case, because function fail before allocate IRP. from another case, if we call FSCTL_FILESYSTEM_GET_STATISTICS with not large enough buffer - file system driver (not I/O Manager ) return STATUS_BUFFER_OVERFLOW (0x80000005). but because at this point IRP already allocated and code not from NT_ERROR range - will be event set.
so if error from I/O Manager (before IRP allocated) - will be no completion. otherwise if error from driver (to which passed IRP) completion will be if function return !NT_ERROR(status). as result if we get:
NT_SUCCESS(status) (the STATUS_PENDING (0x103) is part of this) - will
be
completion
NT_ERROR(status) will be no completion
NT_WARNING(status) - unclear, depend this error from I/O Manager
(no) or driver(yes)
but with win32 layer make situation more worse. because unclear how it interpret NT_WARNING(status) - most win32 api interpret this as error - return false and set last error (converted from status). but some api - for example ReadDirectoryChangesW interpret this as success code - return true and not set last error. as result if we call ReadDirectoryChangesW with bad aligned buffer (but valid other parameters) - it return.. true and not set any error. but api call is really fail. the ZwNotifyChangeDirectoryFile internal return STATUS_DATATYPE_MISALIGNMENT here.
from another side, if DeviceIoControl for FSCTL_FILESYSTEM_GET_STATISTICS fail (return false) with code ERROR_MORE_DATA (converted from STATUS_BUFFER_OVERFLOW) event(completion) will be set in this case.
also by win32 error code we can not understand - are initial status was NT_ERROR or NT_WARNING code - conversion (RtlNtStatusToDosError) status to win32 error lost this info
problem with NT_WARNING(status) range, begin from vista, can be resolved if we use IOCP completion (instead event) and set FILE_SKIP_COMPLETION_PORT_ON_SUCCESS on file - in this case I/O manager queue a completion entry to the port, when and only when STATUS_PENDING will be returned by native api call. for win32 layer this usually mean that api return false and last error is ERROR_IO_PENDING. exceptions - WriteFileEx, ReadFileEx which return true here. however this not help in case ReadDirectoryChangesW anyway (I assume that this is windows bug)
also read FILE_SKIP_SET_EVENT_ON_HANDLE section - this implicitly say when explicit event (from overlapped) set in case asynchronous function - when request returns with a success code, or the error returned is ERROR_IO_PENDING. but here question - what is success code ? true returned by win32 api ? not always, as visible from FSCTL_FILESYSTEM_GET_STATISTICS - the ERROR_MORE_DATA (STATUS_BUFFER_OVERFLOW) also success code. or STATUS_NO_MORE_FILES returned by NtQueryDirectoryFile also success code - event (apc or iocp completion) will be set. but same NtQueryDirectoryFile can return STATUS_DATATYPE_MISALIGNMENT, when FileInformation bad aligned - this is fail code, because returned from I/O Manager before allocate IRP
the NT_WARNING status in most case is success code (will be completion), but win32 layer in most case interpret it as fail code (return false).
code example for tests:
ULONG BOOL_TO_ERROR(BOOL fOk)
{
return fOk ? NOERROR : GetLastError();
}
void CheckEventState(HANDLE hEvent, ULONG err, NTSTATUS status = RtlGetLastNtStatus())
{
DbgPrint("error = %u(%x)", err, err ? status : STATUS_SUCCESS);
switch (WaitForSingleObject(hEvent, 0))
{
case WAIT_OBJECT_0:
DbgPrint("Signaled\n");
break;
case WAIT_TIMEOUT:
DbgPrint("NON signaled\n");
break;
default:
DbgPrint("error=%u\n", GetLastError());
}
#if 1
EVENT_BASIC_INFORMATION ebi;
if (0 <= ZwQueryEvent(hEvent, EventBasicInformation, &ebi, sizeof(ebi), 0))
{
DbgPrint("EventState = %x\n", ebi.EventState);
}
#endif
}
void demoIoEvent()
{
WCHAR sz[MAX_PATH];
GetSystemDirectoryW(sz, RTL_NUMBER_OF(sz));
HANDLE hFile = CreateFileW(sz, 0, FILE_SHARE_VALID_FLAGS, 0,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED|FILE_FLAG_BACKUP_SEMANTICS, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
FILESYSTEM_STATISTICS fs;
OVERLAPPED ov = {};
if (ov.hEvent = CreateEvent(0, TRUE, FALSE, 0))
{
FILE_NOTIFY_INFORMATION fni;
IO_STATUS_BLOCK iosb;
// STATUS_DATATYPE_MISALIGNMENT from I/O manager
// event will be not set
NTSTATUS status = ZwNotifyChangeDirectoryFile(hFile, ov.hEvent, 0, 0, &iosb,
(FILE_NOTIFY_INFORMATION*)(1 + (PBYTE)&fni), 1, FILE_NOTIFY_VALID_MASK, FALSE);
CheckEventState(ov.hEvent, ERROR_NOACCESS, status);
// windows bug ! ReadDirectoryChangesW return .. true and no last error
// but really api fail. event will be not set and no notifications
ULONG err = BOOL_TO_ERROR(ReadDirectoryChangesW(hFile,
(FILE_NOTIFY_INFORMATION*)(1 + (PBYTE)&fni), 1, 0, FILE_NOTIFY_VALID_MASK, 0, &ov, 0));
CheckEventState(ov.hEvent, err);
// fail with ERROR_INSUFFICIENT_BUFFER (STATUS_BUFFER_TOO_SMALL)
// NT_ERROR(c0000023) - event will be not set
err = BOOL_TO_ERROR(DeviceIoControl(hFile,
FSCTL_FILESYSTEM_GET_STATISTICS, 0, 0, 0, 0, 0, &ov));
CheckEventState(ov.hEvent, err);
// ERROR_MORE_DATA (STATUS_BUFFER_OVERFLOW)
// !NT_ERROR(80000005) - event will be set
// note - win 32 api return false and error != ERROR_IO_PENDING
err = BOOL_TO_ERROR(DeviceIoControl(hFile,
FSCTL_FILESYSTEM_GET_STATISTICS, 0, 0, &fs, sizeof(fs), 0, &ov));
CheckEventState(ov.hEvent, err);
if (err == ERROR_MORE_DATA)
{
SYSTEM_INFO si;
GetSystemInfo(&si);
ULONG cb = si.dwNumberOfProcessors * fs.SizeOfCompleteStructure;
union {
PVOID pv;
PBYTE pb;
PFILESYSTEM_STATISTICS pfs;
};
pv = alloca(cb);
// must be NOERROR(0) here
// !NT_ERROR(0) - event will be set
err = BOOL_TO_ERROR(DeviceIoControl(hFile, FSCTL_FILESYSTEM_GET_STATISTICS, 0, 0,
pv, cb, 0, &ov));
CheckEventState(ov.hEvent, err);
if (!err && GetOverlappedResult(hFile, &ov, &cb, FALSE))
{
do
{
// use pfs here
} while (pb += fs.SizeOfCompleteStructure, --si.dwNumberOfProcessors);
}
}
CloseHandle(ov.hEvent);
}
CloseHandle(hFile);
}
}
and output:
error = 998(80000002)NON signaled
EventState = 0
error = 0(0)NON signaled
EventState = 0
error = 122(c0000023)NON signaled
EventState = 0
error = 234(80000005)Signaled
EventState = 1
error = 0(0)Signaled
EventState = 1

Strange behaviour of Win32_NetworkAdapterConfiguration::EnableDHCP?

My application has ablities to turn network adaptors of or enable them for either DHCP or static configuration. IP configuration is done via WMI Win32_NetworkApapterConfiguration class and disabling/enabling adapters is done via SetupApi for some reasons. Starting at the point where the adapter was enabled, I noticed following (Windows 7 SP1, 32bit):
EnableDHCP method return with error 84 (IP not enabled). So I thought I need to wait that property the "IpEnabled" becomes true and polled it every second - but it always returned false (BTW: I monitored the value using WMIC and could see that it has actually became true).
Next - in order to avoid and inifinite loop - I changed my "poll 'IpEnabled == true' loop" to jump out after 10 trials, and do the remaining stuff. And see: EnableDHCP succeeded (ret == 0), and also IpEnabled suddely became true.
EDIT
Situation 1:
int ret;
// ...
// Returns error 84
ret = wmiExecMethod(clsName, "EnableDHCP", true, objPath);
// ...
Situation 2:
int ret;
// ...
// Will never get out of this
while (!wmiGetBool(pWMIObj, "IPEnabled"))
{
printf("Interface.IpEnabled=False\n");
Sleep(1000);
}
// ...
ret = wmiExecMethod(clsName, "EnableDHCP", true, objPath);
Situation 3:
int count = 10;
int ret;
// ...
// Will occur until count becomes 0
while (wmiGetBool(pWMIObj, "IPEnabled") && count--)
{
printf("Interface.IpEnabled=False - remaining trials: %d\n", count);
Sleep(1000);
}
// ...
// After this "delay", EnableDHCP returns 0 (SUCCESS)
ret = wmiExecMethod(clsName, "EnableDHCP", true, objPath);
// wmiGetBool(pWMIObj, "IPEnabled") now returns true too...
Do you have any ideas what is going wrong here? Thanks in before for help.
Best regards
Willi K.
The "real" problem behind this is that the Win32_NetworkApapterConfiguration::EnableDHCP method fails if the interface is not connected to a network (offline). The only way I found to configure the interface for DHCP is to modify the registry....

What will happen if I skip waiting[i] = false In the following snippet of code?

The code below is designed to solve critical section problem. Given that there are N processes that are modifying a common data-structure in their critical section.
These are the Data Structure Used:
boolean waiting[n];
boolean lock;
Here is the testAndSet() function that is assumed to execute atomically due to hardware support.
boolean TestAndSet(boolean *target)
{
boolean rv = *target;
*target = TRUE;
return rv;
}
// The following code ensures mutual-exclusion
do {
waiting[i] = TRUE;
key = TRUE;
while (waiting[i] && key)
key = TestAndSet(&lock);
waiting[i] = FALSE; //what if I skip this??
// critical section
j = ( i + 1) % n ;
while((j != i) && ! waiting[j])
{
j = (j + 1) % n ;
}
if (j == i)
lock = FALSE;
else
waiting[j] = FALSE;
//remainder section
}while (TRUE);
You really need to indent the line after the first while.
The stuff below the "// critical section" will unlock the next task waiting for access, or release the lock if nobody is waiting.
If you don't clear your waiting flag, then another task (presumably running the same code around their access to protected memory) who already had the lock will think you're still waiting and will clear your waiting flag for you to allow you to run (assuming you're sitting in the loop, checking TestAndSet, the only place your wait flag is true). And it keeps the lock flag set, since it's just passing the lock on to you effectively. But if your code has actually moved on from that point without setting the value false, then you can't get back to the TestAndSet without setting your waiting flag to True, and since lock is also left at true, then this task can't run, and other tasks aren't running because the next task in line wasn't given the go-ahead (or lock wasn't set to false), and the whole system is now gummed up.
If you skip the '... = FALSE' line that would mean that you are still waiting to acquire lock (critical section) in a first while loop (for specific i) and would break the logic of "round robin" access to critical section in the second while loop.
Eliminating that line would probably break the whole thing. The two lines immediately above it are a while loop which may terminate on one of two conditions - either waiting[i] becoming false, or key becoming false (or maybe both "simultaneously"). If the loop terminates due to key being false, then waiting[i] is presumably still true, so you would get into a condition where you both hold the lock and simultaneously think you are still waiting for the lock, which probably violates the preconditions for the subsequent while loop...
I think I got it. The whole confusion is created by do while() loop which encloses the whole code. Instead of this do while() thing, if These were like some function representing a process such as
function(int i)
{
waiting[i] = TRUE;
key = TRUE;
while (waiting[i] && key)
key = TestAndSet(&lock);
waiting[i] = FALSE; //what if I skip this??
// critical section
j = ( i + 1) % n ;
while((j != i) && ! waiting[j])
{
j = (j + 1) % n ;
}
if (j == i)
lock = FALSE;
else
waiting[j] = FALSE;
//remainder section
}
lets say a function is called with i = 3 (say process i3. for N = 5). And this process i3 is never executed again then not setting waiting[3]=false will end up in deadlock situation. As process i4 may think that process i3 wants to run thus it will end up by setting waiting[3] = false and not releasing the lock

InternetReadFileEx gives 10035 and 1008 errors

I am trying to write an Asyncronous Wininet application. I read the data in my callback function in case of INTERNET_STATUS_REQUEST_COMPLETE and I handle the ERROR_IO_PENDING errors as well. But after some data read from internet, InternetReadFileEx function gives me 10035=WSAEWOULDBLOCK (A non-blocking socket operation could not be completed immediately) error. After that error I call InternetReadFileEx again and this time it gives me 1008=ERROR_NO_TOKEN (An attempt was made to reference a token that does not exist.) error. I think my design is not correct, and I receive these error because of that.
Here is a snippet of my code:
case INTERNET_STATUS_REQUEST_COMPLETE:
{
BOOL bAllDone= FALSE;
DWORD lastError;
do
{
//Create INTERNET_BUFFERS
char m_pbReadBuffer[4096];
INTERNET_BUFFERS BuffersIn;
ZeroMemory(&BuffersIn, sizeof(INTERNET_BUFFERS));
BuffersIn.dwStructSize = sizeof(INTERNET_BUFFERS);
BuffersIn.lpvBuffer = m_pbReadBuffer;
BuffersIn.dwBufferLength = 4096;
InternetReadFileEx(ReqContext->File, &BuffersIn, IRF_ASYNC, 1);
//HERE I GOT THOSE 10035 and 1008 ERRORS
lastError = GetLastError();
if(lastError == 997) // handling ERROR_IO_PENDING
break;//break the while loop
//append it to my ISTREAM
(ReqContext->savedStream)->Write(BuffersIn.lpvBuffer, BuffersIn.dwBufferLength, NULL);
if (BuffersIn.dwBufferLength == 0)
bAllDone = TRUE;
}while(bAllDone == FALSE);
//delete[] m_pbReadBuffer;
if(bAllDone == TRUE && lastError== 0)
{
//these are for passing the ISTREAM to the function which calls "InternetOpenUrl"
LARGE_INTEGER loc;
loc.HighPart = 0;
loc.LowPart = 0;
ReqContext->savedStream->Seek(loc, STREAM_SEEK_SET, NULL);
ReqContext->savedCallback->OnUrlDownloaded(S_OK, ReqContext->savedStream); //Tell silverlight ISTREAM is ready
ReqContext->savedStream->Release();
ReqContext->savedCallback->Release();
InternetCloseHandle(ReqContext->File);
InternetSetStatusCallback(ReqContext->Connection, NULL);
InternetCloseHandle(ReqContext->Connection);
delete[] ReqContext;
}
}
break;
Can anyone give me a hand to correct that?
Thanks everyone helping...
GetLastError() is only meaningful if InternetReadFileEx() (or any other API, for that matter) actually fails with an error. Otherwise, you will be processing an error from an earlier API call, giving your code a false illusion that an error happened when it really may not have. You MUST pay attention to API return values, but you are currently ignoring the return value of InternetReadFileEx().
Worse than that, though, you are using InternetReadFileEx() in async mode but you are using a receiving buffer that is local to the INTERNET_STATUS_REQUEST_COMPLETE callback handler. If InternetReadFileEx() fails with an ERROR_IO_PENDING error, the read is performed in the background and INTERNET_STATUS_REQUEST_COMPLETE will be triggered when the read is complete. However, when that error occurs, you are breaking your loop (even though the read is still in progress) and that buffer will go out of scope before the read is finished. While the reading is still in progress, the receiving buffer is still on the stack and InternetReadFileEx() is still writing to it, but it may get re-used for other things at the same time because your code moved on to do other things and did not wait for the read to finish.
You need to re-think your approach. Either:
remove the IRF_ASYNC flag, since that is how the rest of your callback code is expecting InternetReadFileEx() to behave.
re-write the code to operate in async mode correctly. Dynamically allocate the receive buffer (or at least store it somewhere else that remains in scope during the async reading), don't call IStream::Write() unless you actually have data to write (only when InternetReadFileEx() returned TRUE right away, or you get an INTERNET_STATUS_REQUEST_COMPLETE event with a success code from an earlier InternetReadFileEx()/ERROR_IO_PENDING call), etc.
There are plenty of online examples and tutorials that show how to use InternetReadFileEx() in async mode. Search around.

Resources