Understanding DirectoryWatcher - windows

I've been trying to use and understand the DirectoryWatcher class from Microsoft's Cloud Mirror sample. It uses ReadDirectoryChangesW to monitor changes to a directory. I don't think it's reporting all changes, to be honest. In any event, I had a question about the key part of the code, which is as follows:
concurrency::task<void> DirectoryWatcher::ReadChangesAsync()
{
auto token = _cancellationTokenSource.get_token();
return concurrency::create_task([this, token]
{
while (true)
{
DWORD returned;
winrt::check_bool(ReadDirectoryChangesW(
_dir.get(),
_notify.get(),
c_bufferSize,
TRUE,
FILE_NOTIFY_CHANGE_ATTRIBUTES,
&returned,
&_overlapped,
nullptr));
DWORD transferred;
if (GetOverlappedResultEx(_dir.get(), &_overlapped, &transferred, 1000, FALSE))
{
std::list<std::wstring> result;
FILE_NOTIFY_INFORMATION* next = _notify.get();
while (next != nullptr)
{
std::wstring fullPath(_path);
fullPath.append(L"\\");
fullPath.append(std::wstring_view(next->FileName, next->FileNameLength / sizeof(wchar_t)));
result.push_back(fullPath);
if (next->NextEntryOffset)
{
next = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(reinterpret_cast<char*>(next) + next->NextEntryOffset);
}
else
{
next = nullptr;
}
}
_callback(result);
}
else if (GetLastError() != WAIT_TIMEOUT)
{
throw winrt::hresult_error(HRESULT_FROM_WIN32(GetLastError()));
}
else if (token.is_canceled())
{
wprintf(L"watcher cancel received\n");
concurrency::cancel_current_task();
return;
}
}
}, token);
}
After reviewing an answer to another question, here's what I don't understand about the code above: isn't the code potentially re-calling ReadDirectoryChangesW before the prior call has returned a result? Or is this code indeed correct? Thanks for any input.
Yes, I seem to have confirmed in my testing that there should be another while loop there around the call to GetOverlappedResultEx, similar to the sample code provided in that other answer. I think the notifications are firing properly with it.
Shouldn't there also be a call to CancelIo in there, too? Or is that not necessary for some reason?

Related

Omnet++ : changing the location of function didn't work as expected

I am actually trying to edit the etherhost2 function to send to several destinations and I reached a point where it is possible only for the first time.
In the original code the function is working properly by just moving the two functions sendBurstPackets() and scheduleNextPacket(simTime()) in if condition with destMACAddress = resolveDestMACAddress() those two functions are only called once.
Does that mean that destMacAddress is set once through the whole simulation?
Original Code
void EtherTrafGen::handleMessage(cMessage *msg)
{
if (!isNodeUp())
throw cRuntimeError("Application is not running");
if (msg->isSelfMessage()) {
if (msg->getKind() == START) {
destMACAddress = resolveDestMACAddress();
// if no dest address given, nothing to do
if (destMACAddress.isUnspecified())
return;
}
sendBurstPackets();
scheduleNextPacket(simTime());
}
else
receivePacket(check_and_cast<cPacket *>(msg));
}
My Changes
void EtherTrafGen::handleMessage(cMessage *msg)
{
if (!isNodeUp())
throw cRuntimeError("Application is not running");
if (msg->isSelfMessage()) {
if (msg->getKind() == START) {
if (!multipacket)
{
destMACAddress = resolveDestMACAddress();
sendBurstPackets();
scheduleNextPacket(simTime());
}
// if no dest address given, nothing to do
if (destMACAddress.isUnspecified())
return;
}
}
else
receivePacket(check_and_cast<cPacket *>(msg));
}
The first message is only true for that condition (msg->getKind() == START), which means the the mac is set once for each host through the whole simulation. Removing that condition made it work.
I am worried if there are other self messages that might be mistaken with that function. Would be better to have separate EtherHost app that only works for my simulation.
If there is an idea how to look at all self messages, I would appreciate if some one informed me.

alBufferData() sets AL_INVALID_OPERATION when using buffer ID obtained from alSourceUnqueueBuffers()

I am trying to stream audio data from disk using OpenAL's buffer queueing mechanism. I load and enqueue 4 buffers, start the source playing, and check in a regular intervals to refresh the queue. Everything looks like it's going splendidly, up until the first time I try to load data into a recycled buffer I got from alSourceUnqueueBuffers(). In this situation, alBufferData() always sets AL_INVALID_OPERATION, which according to the official v1.1 spec, it doesn't seem like it should be able to do.
I have searched extensively on Google and StackOverflow, and can't seem to find any reason why this would happen. The closest thing I found was someone with a possibly-related issue in an archived forum post, but details are few and responses are null. There was also this SO question with slightly different circumstances, but the only answer's suggestion does not help.
Possibly helpful: I know my context and device are configured correctly, because loading small wav files completely into a single buffer and playing them works fine. Through experimentation, I've also found that queueing 2 buffers, starting the source playing, and immediately loading and enqueueing the other two buffers throws no errors; it's only when I've unqueued a processed buffer that I run into trouble.
The relevant code:
static constexpr int MAX_BUFFER_COUNT = 4;
#define alCall(funcCall) {funcCall; SoundyOutport::CheckError(__FILE__, __LINE__, #funcCall) ? abort() : ((void)0); }
bool SoundyOutport::CheckError(const string &pFile, int pLine, const string &pfunc)
{
ALenum tErrCode = alGetError();
if(tErrCode != 0)
{
auto tMsg = alGetString(tErrCode);
Log::e(ro::TAG) << tMsg << " at " << pFile << "(" << pLine << "):\n"
<< "\tAL call " << pfunc << " failed." << end;
return true;
}
return false;
}
void SoundyOutport::EnqueueBuffer(const float* pData, int pFrames)
{
static int called = 0;
++called;
ALint tState;
alCall(alGetSourcei(mSourceId, AL_SOURCE_TYPE, &tState));
if(tState == AL_STATIC)
{
Stop();
// alCall(alSourcei(mSourceId, AL_BUFFER, NULL));
}
ALuint tBufId = AL_NONE;
int tQueuedBuffers = QueuedUpBuffers();
int tReady = ProcessedBuffers();
if(tQueuedBuffers < MAX_BUFFER_COUNT)
{
tBufId = mBufferIds[tQueuedBuffers];
}
else if(tReady > 0)
{
// the fifth time through, this code gets hit
alCall(alSourceUnqueueBuffers(mSourceId, 1, &tBufId));
// debug code: make sure these values go down by one
tQueuedBuffers = QueuedUpBuffers();
tReady = ProcessedBuffers();
}
else
{
return; // no update needed yet.
}
void* tConverted = convert(pData, pFrames);
// the fifth time through, we get AL_INVALID_OPERATION, and call abort()
alCall(alBufferData(tBufId, mFormat, tConverted, pFrames * mBitdepth/8, mSampleRate));
alCall(alSourceQueueBuffers(mSourceId, 1, &mBufferId));
if(mBitdepth == BITDEPTH_8)
{
delete (uint8_t*)tConverted;
}
else // if(mBitdepth == BITDEPTH_16)
{
delete (uint16_t*)tConverted;
}
}
void SoundyOutport::PlayBufferedStream()
{
if(!StreamingMode() || !QueuedUpBuffers())
{
Log::w(ro::TAG) << "Attempted to play an unbuffered stream" << end;
return;
}
alCall(alSourcei(mSourceId, AL_LOOPING, AL_FALSE)); // never loop streams
alCall(alSourcePlay(mSourceId));
}
int SoundyOutport::QueuedUpBuffers()
{
int tCount = 0;
alCall(alGetSourcei(mSourceId, AL_BUFFERS_QUEUED, &tCount));
return tCount;
}
int SoundyOutport::ProcessedBuffers()
{
int tCount = 0;
alCall(alGetSourcei(mSourceId, AL_BUFFERS_PROCESSED, &tCount));
return tCount;
}
void SoundyOutport::Stop()
{
if(Playing())
{
alCall(alSourceStop(mSourceId));
}
int tBuffers;
alCall(alGetSourcei(mSourceId, AL_BUFFERS_QUEUED, &tBuffers));
if(tBuffers)
{
ALuint tDummy[tBuffers];
alCall(alSourceUnqueueBuffers(mSourceId, tBuffers, tDummy));
}
alCall(alSourcei(mSourceId, AL_BUFFER, AL_NONE));
}
bool SoundyOutport::Playing()
{
ALint tPlaying;
alCall(alGetSourcei(mSourceId, AL_SOURCE_STATE, &tPlaying));
return tPlaying == AL_PLAYING;
}
bool SoundyOutport::StreamingMode()
{
ALint tState;
alCall(alGetSourcei(mSourceId, AL_SOURCE_TYPE, &tState));
return tState == AL_STREAMING;
}
bool SoundyOutport::StaticMode()
{
ALint tState;
alCall(alGetSourcei(mSourceId, AL_SOURCE_TYPE, &tState));
return tState == AL_STATIC;
}
And here's an annotated screen cap of what I see in my debugger when I hit the error:
I've tried a bunch of little tweaks and variations, and the result is always the same. I've wasted too many days trying to fix this. Please help :)
This error occurs when you trying to fill buffer with data, when the buffer is still queued to the source.
Also this code is wrong.
if(tQueuedBuffers < MAX_BUFFER_COUNT)
{
tBufId = mBufferIds[tQueuedBuffers];
}
else if(tReady > 0)
{
// the fifth time through, this code gets hit
alCall(alSourceUnqueueBuffers(mSourceId, 1, &tBufId));
// debug code: make sure these values go down by one
tQueuedBuffers = QueuedUpBuffers();
tReady = ProcessedBuffers();
}
else
{
return; // no update needed yet.
}
You can fill buffer with data only if it unqueued from source. But your first if block gets tBufId that queued to the source. Rewrite code like so
if(tReady > 0)
{
// the fifth time through, this code gets hit
alCall(alSourceUnqueueBuffers(mSourceId, 1, &tBufId));
// debug code: make sure these values go down by one
tQueuedBuffers = QueuedUpBuffers();
tReady = ProcessedBuffers();
}
else
{
return; // no update needed yet.
}

hp webos, pdk plugin defunct in hybrid app.

I have been trying to call a pdk plugin from the mojo hybrid app and have also tried the same with enyo app. In both cases my pdk plugin is shown as , Interesting thing is in case of enyo, i received the plugin_ready response which is sent after the plugin registration is complete.
in the web-os site, they mentioned that it is the issue with pdk plugin that makes it look defunct.
but i could not find a method to resolve it.
This is how my plugin looks,
PDL_bool powerCall(PDL_JSParameters *params) {
runsine();
char *reply = "Done";
PDL_JSReply(params, reply);
return PDL_TRUE;
}
int main(){
int result = SDL_Init(SDL_INIT_VIDEO);
PDL_Init(0);
PDL_RegisterJSHandler("pawar", powerCall);
PDL_JSRegistrationComplete();
PDL_CallJS("ready", NULL, 0); // this is for enyo
PDL_Quit();
SDL_Quit();
return 0;
}
please suggest me how to solve this issue. i know its a very simple task and am frustrated that its taking this long.
Thanks
Shankar
In your plugin you should enter an event loop after you call the "ready" function, and before you call the PDL_Quit() and SDL_Quit(). Not having an event loop causes the plugin process to quit right away.
Here is an example based on the "simple" app that ships with the PDK:
int main(){
int result = SDL_Init(SDL_INIT_VIDEO);
PDL_Init(0);
PDL_RegisterJSHandler("pawar", powerCall);
PDL_JSRegistrationComplete();
PDL_CallJS("ready", NULL, 0); // this is for enyo
atexit(SDL_Quit);
atexit(PDL_Quit);
SDL_Event Event;
bool paused = false;
while (1) {
bool gotEvent;
if (paused) {
SDL_WaitEvent(&Event);
gotEvent = true;
}
else {
gotEvent = SDL_PollEvent(&Event);
}
while (gotEvent) {
switch (Event.type) {
case SDL_ACTIVEEVENT:
if (Event.active.state == SDL_APPACTIVE) {
paused = !Event.active.gain;
}
break;
case SDL_QUIT:
// We exit anytime we get a request to quit the app
// all shutdown code is registered via atexit() so this is clean.
exit(0);
break;
// handle any other events interesting to your plugin here
default:
break;
}
gotEvent = SDL_PollEvent(&Event);
}
}
return 0;
}

call async_resolve.cancel(),but the callback handler of async_resolve doesn't return boost::asio::error::operation_aborted

i used boost asio to process http request and answer,to avoid async_resolve doesn't invoke its callback handler,i set a timeout,just like this:
void resolve()
{
resolver_.async_resolve(query,strand_.wrap(boost::bind(&connection::handle_resolve,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::iterator)));
int cancel_num = timer_.expires_from_now(boost::posix_time::seconds(resolve_timeout_));
timer_.async_wait(strand_.wrap(boost::bind(&connection::handle_resolve_timeout,
shared_from_this(),
boost::asio::placeholders::error)));
}
void connection::handle_resolve_timeout(const boost::system::error_code& err)
{
if (err != boost::asio::error::operation_aborted)
{
resolver_.cancel();
}
}
void connection::handle_resolve(const boost::system::error_code& err,
boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
{
timer_.cancel();
if(!err)
{
boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
socket_.async_connect(endpoint,strand_.wrap(boost::bind(&connection::handle_connect,
shared_from_this(),
boost::asio::placeholders::error,
++endpoint_iterator)));
//to distinct the type of timeout ,0:connect timeout,1:read timeout
int flag = 0;
int cancel_num = timer_.expires_from_now(boost::posix_time::seconds(connect_timeout_));
timer_.async_wait(strand_.wrap(boost::bind(&connection::handle_timeout,
shared_from_this(),
boost::asio::placeholders::error,
flag)));
}
else if(err != boost::asio::error::operation_aborted)
{
status_ = resolve_error;
check_.do_finish(shared_from_this());
}
else
{
FASTCHECK_INFO("resolve is canceled\n");
}
}
when resolve timeout ,i found the handle_resolve_timeout is invoked,but the handle_resolve doesn't return boost::asio::error::operation_aborted,why,i am puzzled,can someone can explain it for me?
According to the discussion on boost-users mailing list, resolver::cancel() is only able to cancel pending, queued resolve requests, not the one that's currently executing.
As a delayed follow up to #Cubbi's answer, this bug was also raised on the Boost issue tracker a few months after this question's thread. The Asio resolver API is slightly confusing because it suggests that any async_resolve() operation can be cancelled on demand. I had the same problem myself. It also turns out that in the Asio implementation, calls to async_resolve() makes a synchronous system call to getaddrinfo() behind the scenes. I discuss this interesting behavior in a recent codecast.

Determining object types in Qt

I have a series of QTextEdits and QLineEdits connected to a slot through a QSignalMapper(which emits a textChanged(QWidget*) signal). When the connected slot is called (pasted below), I need to be able to differentiate between the two so I know whether to call the text() or toPlainText() function. What's the easiest way to determine the subclass type of a QWidget?
void MainWindow::changed(QWidget *sender)
{
QTextEdit *temp = qobject_cast<QTextEdit *>(sender);
QString currentText = temp->toPlainText(); // or temp->text() if its
// a QLineEdit...
if(currentText.compare(""))
{
...
}
else
{
...
}
}
I was considering using try-catch but Qt doesn't seem to have very extensive support for Exceptions... Any ideas?
Actually, your solution is already almost there. In fact, qobject_cast will return NULL if it can't perform the cast. So try it on one of the classes, if it's NULL, try it on the other:
QString text;
QTextEdit *textEdit = qobject_cast<QTextEdit*>(sender);
QLineEdit *lineEdit = qobject_cast<QLineEdit*>(sender);
if (textEdit) {
text = textEdit->toPlainText();
} else if (lineEdit) {
text = lineEdit->text();
} else {
// Return an error
}
You can also use sender->metaObject()->className() so you won't make unnecesary casts. Specially if you have a lot of classes to test. The code will be like this:
QString text;
QString senderClass = sender->metaObject()->className();
if (senderClass == "QTextEdit") {
QTextEdit *textEdit = qobject_cast<QTextEdit*>(sender);
text = textEdit->toPlainText();
} else if (senderClass == "QLineEdit") {
QLineEdit *lineEdit = qobject_cast<QLineEdit*>(sender);
text = lineEdit->text();
} else {
// Return an error
}
I know is an old question but I leave this answer just in case it would be useful for somebody...

Resources