I'm trying to create a simple shell that supports pipes and file redirects. Here's the execute function I came up with so far:
void execute(std::vector<Command *> cmds)
{
int inp[2], out[2];
pipe(inp);
pipe(out);
int status, fd = 0;
for (auto cmd : cmds)
{
auto pid = fork();
if (pid == -1) {
throw std::runtime_error("Could not fork.");
} else if (pid == 0) {
dup2(inp[1], 1);
if (cmd->redirectout) {
fd = fileno(fopen(cmd->filename.c_str(), "w"));
dup2(1, fd);
}
dup2(out[0], 0);
if (cmd->redirectin) {
fd = fileno(fopen(cmd->filename.c_str(), "r"));
dup2(0, fd);
}
close(inp[0]);
close(inp[1]);
close(out[0]);
close(out[1]);
if(execvp(cmd->args_char[0], cmd->args_char.data()) < 0) {
std::cout << "Command not found." << std::endl;
exit(1);
}
} else {
dup2(out[0], inp[0]);
dup2(out[1], inp[1]);
close(inp[0]);
close(inp[1]);
close(out[0]);
close(out[1]);
while (wait(&status) != pid);
}
}
}
When I execute this the program is running but nothing happens. I've been working on this function for days but can't seem to understand the reason. I think the parent process is waiting forever for the child. Can somebody please help me with this?
Related
I'm developing a driver for a device with Qt. I have already done that many times and I have a code that I use every time. But, this time, when I open the QserialPort, it seems to work correctly, but it is not : I can write, the device receives commands, but I cannot receive on the soft : the signal QSerialPort::ReadyRead is never triggered.
When I open the serial port with Putty (just open it without sending anything) and close it just after, my Qt soft work perfectly when I reconnect it : I can now receive correctly...
Do you have an idea of what putty do of different/more than my soft when opening the port ?
(I have the same parameters and I'm on windows and Qt 5.15.2).
My code for opening :
_serial->setPortName(com);
_serial->setBaudRate(QSerialPort::Baud115200);
_serial->setDataBits(QSerialPort::Data8);
_serial->setParity(QSerialPort::NoParity);
_serial->setStopBits(QSerialPort::OneStop);
_serial->setFlowControl(QSerialPort::NoFlowControl);
if(!_serial->open(QIODevice::ReadWrite))
{
emit error(tr("Unable to open port"));
return;
}
_serial->clear();
My code for write (simple string like "hello") :
_serial->write("Hello");
My code for connect the signal :
connect(_serial, &QSerialPort::readyRead, this, &device::processCommand);
My code for read serial (processCommand()):
QString bufferData;
if (_serial->isOpen())
{
_datas.append(_serial->readAll());
bufferData = _datas.constData();
}
EDIT : The Qt exemple 'Terminal' do not works on windows with my device but works on ubuntu...
EDIT 2 : SOLUTION : I have finally find the solution, just add _serial->setDataTerminalReady(true); after opening the QSerialPort.
Thanks.
I ran into the same problem where the read signal was not detected in the virtual USB port. In the end I came to the conclusion that the QSerialPort class shouldn't.
I solved it using QThread and Win32 API.
#pragma once
#include <windows.h>
#include <QMutex>
#include <QThread>
#include <QWaitCondition>
#define SERIAL_RX_BUF_SIZE 2047
class SerialThread : public QThread
{
Q_OBJECT
public:
explicit SerialThread(QObject *parent = nullptr);
~SerialThread();
bool startThread(const QString& portName);
void stopThread();
void request(const QString& command);
signals:
void response(char* text);
void timeout();
private:
void run() override;
bool writeCommand(const QString& command);
QString m_portName;
QString m_command;
QMutex m_mutex;
QWaitCondition m_wait;
volatile bool m_quit = false;
HANDLE m_hComm;
char m_buf[SERIAL_RX_BUF_SIZE + 1];
};
#include "serial_thread.h"
#include <QDebug>
SerialThread::SerialThread(QObject *parent) :
QThread(parent)
{
memset(m_buf, 0, sizeof(m_buf));
}
SerialThread::~SerialThread()
{
}
bool SerialThread::startThread(const QString &portName)
{
const QMutexLocker locker(&m_mutex);
m_hComm = CreateFileA(portName.toStdString().c_str(), // PORT NAME
GENERIC_READ | GENERIC_WRITE, // READ/WRITE
0, // NO SHARING
NULL, // NO SECURITY
OPEN_EXISTING, // OPEN EXISTING PORT ONLY
0, // NON OVERLAPPED I/O
NULL); // NULL FOR COMM DEVICES
if (m_hComm == INVALID_HANDLE_VALUE)
{
return false;
}
m_portName = portName;
if (!SetCommMask(m_hComm, EV_RXCHAR | EV_ERR))
{
qCritical() << "SetCommMask failed";
CloseHandle(m_hComm);
return false;
}
COMMTIMEOUTS comm_timeouts;
if (!GetCommTimeouts(m_hComm, &comm_timeouts))
{
qCritical() << "GetCommTimeouts failed";
CloseHandle(m_hComm);
return false;
}
comm_timeouts.ReadIntervalTimeout = 1;
comm_timeouts.ReadTotalTimeoutMultiplier = 0;
comm_timeouts.ReadTotalTimeoutConstant = 500;
comm_timeouts.WriteTotalTimeoutMultiplier = 0;
comm_timeouts.WriteTotalTimeoutConstant = 0;
if (!SetCommTimeouts(m_hComm, &comm_timeouts))
{
qCritical() << "SetCommTimeouts failed";
CloseHandle(m_hComm);
return false;
}
start();
return true;
}
void SerialThread::stopThread()
{
m_mutex.lock();
m_quit = true;
m_mutex.unlock();
m_wait.wakeAll();
wait();
}
void SerialThread::request(const QString& command)
{
m_mutex.lock();
m_command = command;
m_mutex.unlock();
m_wait.wakeAll();
}
void SerialThread::run()
{
DWORD dwEvtMask, nRead;
while (!m_quit)
{
m_mutex.lock();
m_wait.wait(&m_mutex);
m_mutex.unlock();
{
const QMutexLocker locker(&m_mutex);
if (m_command.isEmpty())
{
continue;
}
if (!writeCommand(m_command))
{
continue;
}
if (WaitCommEvent(m_hComm, &dwEvtMask, NULL))
{
if (dwEvtMask & EV_ERR)
{
qCritical() << "Wait failed with error: " << GetLastError();
break;
}
if (dwEvtMask & EV_RXCHAR)
{
if (!ReadFile(m_hComm, &m_buf, SERIAL_RX_BUF_SIZE, &nRead, NULL))
{
qCritical() << "ReadFile error: " << GetLastError();
}
else
{
m_buf[nRead] = 0;
qDebug() << "Read: " << nRead;
emit response(m_buf);
}
}
}
else
{
DWORD dwRet = GetLastError();
if (ERROR_IO_PENDING == dwRet)
{
qDebug() << "RX timeout";
emit timeout();
}
else
{
qCritical() << "WaitCommEvent failed: " << dwRet;
}
}
m_command.clear();
}
}
CloseHandle(m_hComm);
m_quit = false;
}
bool SerialThread::writeCommand(const QString& command)
{
std::string s = command.toStdString();
DWORD n;
if (!WriteFile(m_hComm, s.data(), s.length(), &n, NULL))
{
qCritical() << "WriteFile error";
return false;
}
return true;
}
I'm developing server-client application which manages req/res topics and does fan-out of some messages. Messages sends out with WSASend in overlapped mode with provided Completion routine. Noticed that very next send with WSASend after WSARead triggers sender's completion routine. While the sends originated in the server w/o preceding WSARead doesn't trigger completion routine. Why does that happen?
bool CCommunicationServer::ManageReadMessage(UCHAR index)
{
OVERLAPPED_EX *over = m_readov[index];
DWORD bytes = 0, flags = 0;
if (WSARecv(over->socket, &(over->wsabuf), 1, &bytes, &flags, over, &CCommunicationServer::WorkerReadRoutine) == SOCKET_ERROR) {
bytes = WSAGetLastError();
if (bytes != WSA_IO_PENDING) {
LOG(ERROR) << std::endl << "WSARecv() failed w/err " << bytes;
shutdown(m_readov[index]->socket, SD_BOTH);
return FALSE;
}
}
return TRUE;
}
bool CCommunicationServer::ManageSendMessage(UCHAR index, char* msg, OVERLAPPED_EX *moreover)
{
OVERLAPPED_EX *over = moreover;
DWORD bytes = 0;
SOCKET socket = m_readov[index] != NULL ? m_readov[index]->socket : NULL;
if (!over) {
ScopedLock lock(&m_lock);
if (!msg) {
LOG(WARNING) << "Empty send! Ignoring!";
return FALSE;
} else if (m_readov[index] != NULL) {
LOG(DEBUG) << ++created << "\t:\t" << deleted << "\t\t\t\r";
over = new OVERLAPPED_EX(this, m_readov[index]->socket, index, msg);
} else {
return FALSE;
}
}
if (WSASend(socket, &(over->wsabuf), 1, &bytes, 0, (LPWSAOVERLAPPED)over, &CCommunicationServer::WorkerSendRoutine) == SOCKET_ERROR) {
bytes = bytes = WSAGetLastError();
if (bytes != WSA_IO_PENDING) {
LOG(ERROR) << std::endl << "WSASend() failed w/err " << bytes;
shutdown(socket, SD_BOTH);
LOG(DEBUG) << created << "\t:\t" << ++deleted << "\t\t\t\r";
delete over;
return FALSE;
}
}
return TRUE;
}
And here are Completion routines:
void CALLBACK CCommunicationServer::WorkerReadRoutine(DWORD Error, DWORD BytesTransferred, LPWSAOVERLAPPED Overlapped, DWORD InFlags)
{
OVERLAPPED_EX *over = (OVERLAPPED_EX*)Overlapped;
if (Error)
return;
if (BytesTransferred > 0) {
over->server->GetRequest(over);
}
over->server->ManageReadMessage(over->index);
}
void CALLBACK CCommunicationServer::WorkerSendRoutine(DWORD Error, DWORD BytesTransferred, LPWSAOVERLAPPED Overlapped, DWORD InFlags)
{
OVERLAPPED_EX *over = (OVERLAPPED_EX*)Overlapped;
if (Error || over->wsabuf.len == BytesTransferred) {
LOG(DEBUG) << over->server->created << "\t:\t" << ++over->server->deleted << "\t\t\t\r";
delete over;
} else {
over->wsabuf.buf += BytesTransferred;
over->wsabuf.len -= BytesTransferred;
over->server->ManageSendMessage(over->index, NULL, over);
}
}
The variables created and deleted shows how many OVERLAPPED_EX structures were created and then released to avoid memory leakage.
I have code like this:
void function()
{
auto isOk=task(1);
if(!isOk)
{
return;
}
// more code here
auto isOk=task(2);
if(!isOk)
{
return;
}
// more code here
auto isOk=task(3);
if(!isOk)
{
return;
}
// more code here
auto isOk=task(4);
if(!isOk)
{
return;
}
// more code here
auto isOk=task(5);
if(!isOk)
{
return;
}
// more code here
auto isOk=task(6);
if(!isOk)
{
return;
}
// more code here
auto isOk=task(7);
if(!isOk)
{
return;
}
// more code here
auto isOk=task(8);
if(!isOk)
{
return;
}
// more code here
auto isOk=task(9);
if(!isOk)
{
return;
}
}
It should be noted that I can not put them in a loop (My code is similar to this but not exactly this code)
The if block is very ugly and I may be bale to write it as follow:
#define TASK(x) {if(!task(x)) return;}
void function()
{
TASK(1);
// more code here
TASK(2);
// more code here
TASK(3);
// more code here
TASK(4);
// more code here
TASK(5);
// more code here
TASK(6);
// more code here
TASK(7);
// more code here
TASK(8);
// more code here
TASK(9);
}
My question is:
Is there any better way to do this when I am using C++11?
The problem with this code is:
I can not debug it easily.
The macro is not inside a namespace and maybe conflict with other macros.
Update 1
As most of the answer here tries to solve the problem in the specific code, when I am looking for the general solution, I am asking specifc questions related to this code:
1- Can I use lambda to mimic the macro?
2- Can I use a constexpr to mimic a macro?
3- Any other way to mimic a MACRO in a compiler friendly way (with the same result as a macro) so I can easily debug them?
void function() {
if (!task(1)) return;
// code here
if (!task(2)) return;
// more code here
if (!task(3)) return;
// more code here
}
This is small and tight and no ugly bulky blocks.
If task(1) is much larger, you can put return; on the next line indented.
Instead of using a plain return, you could choose to use exceptions instead, which not only leave the current function, but all functions until they find a catch block.
Something like this:
void tryTask(int i){
auto isOk=task(i);
if(!isOk)
{
throw std::runtime_error("Task failed: Nr. "+to_string(i));
}
}
function()
{
tryTask(1);
// more code here
tryTask(2);
// more code here
tryTask(3);
...
}
This however lets your function throw an exception instead of just returning if one of the tasks failed. If this is not what you want, surround it either inside the function with a try-catch block or call it from a second function like this:
void callfunction(){
try{
function();
} catch (std::exception& e) {
//do whatever happens if the function failed, or nothing
}
}
If you have control about the task() function, you might also decide to throw the exception directly inside this function instead of returning a bool.
If you want to make sure you only catch your own exceptions, write a small class for this taking only the information you need for handling the exception (if you don't need any, an empty class will do the job) and throw/catch an instance of your class instead.
Here's a quick and dirty approach with lambdas.
Assuming this is your task function:
#include <iostream>
/** Returns 0 on success; any other returned value is a failure */
int task(int arg)
{
std::cout << "Called task " << arg << std::endl;
return arg < 3 ? 0 : 1;
}
Invoke the tasks in a chain as follows:
#include <iostream>
int main()
{
int result = Chain::start()
.and_then([]() -> int {return task(1);})
.and_then([]() -> int {return task(2);})
.and_then([]() -> int {return task(3);})
.and_then([]() -> int {return task(4);})
.and_then([]() -> int {return task(5);})
.and_then([]() -> int {return task(6);})
.and_then([]() -> int {return task(7);})
.and_then([]() -> int {return task(8);})
.and_then([]() -> int {return task(9);})
.result();
std::cout << "Chain result: " << result << std::endl;
return result;
}
Because the task returns success only when called with an argument value less than 3, the invocation chain stops as expected after the 3rd step:
$ ./monad
Called task 1
Called task 2
Called task 3
Chain result: 1
This is the implementation of the Chain class:
class Chain
{
public:
const int kSuccess = 0;
Chain() {_result = kSuccess;}
static Chain start() { return Chain(); }
Chain& and_then(std::function<int()> nextfn) {
if(_result == 0) {
_result = nextfn();
}
return *this;
}
int result() { return _result; }
private:
int _result;
};
I know, it looks ugly and it's non-generic. But if this is the general direction you were thinking of, let me know and we can evolve it.
I would put code to execute btw calling task into a vector and then run a loop:
const size_t steps = 9;
using ops = std::function<void()>;
std::vector<ops> vops(steps);
steps[0] = [] { /* some code here to execute after task 0 */ };
...
for( size_t i = 0; i < steps; ++i ) {
if( !task(i) ) return;
if( vops[i] ) (vops[i])();
}
You can use an integer sequence.
// No task to call without an integer.
bool function(std::index_sequence<>) { return true; }
template<std::size_t I, std::size_t... S>
bool function(std::index_sequence<I, S...>) {
return [](){
auto isOk = task(I)
if (!isOk) return false;
// some code
return true;
// it will call function with the rest of the sequence only if the lambda return true.
}() && function(std::index_sequence<S...>{});
}
void function() {
// this call with a integer sequence from 0 to 9
function(std::make_index_sequence<10>{});
}
This code will expand just as if you'd write it by hands.
If the code between calls of task is different for each step, you can use a tuple.
auto afterTask = std::make_tuple(
[](){ std::cout << "after task 0" << std::endl; },
[](){ std::cout << "after task 1" << std::endl; },
[](){ std::cout << "after task 2" << std::endl; },
[](){ std::cout << "after task 3" << std::endl; },
[](){ std::cout << "after task 4" << std::endl; },
[](){ std::cout << "after task 5" << std::endl; },
[](){ std::cout << "after task 6" << std::endl; },
[](){ std::cout << "after task 7" << std::endl; },
[](){ std::cout << "after task 8" << std::endl; },
[](){ std::cout << "after task 9" << std::endl; }
);
And then change the definition of function with:
template<std::size_t I, std::size_t... S>
bool function(std::index_sequence<I, S...>) {
return task(I) &&
(static_cast<void>(std::get<I>(afterTask)()), true) &&
function(std::index_sequence<S...>{});
}
I'm getting memory leaks in avcodec_find_encoder. Although I'm cleaning the resources properly
still I'm not able to get rid of the leak. By successive commenting the code I found that memory leaks happen only after the call of avcodec_find_encoder(). I've tried my code with different video files and I found that memory leaks blocks are always same. Also if I open only audio or video then I get just one memory leaks block.
Below is the part of Init and Clean-up code from the application.
Note that this is just part of code which contains initialization and resource release.
AVFormatContext *m_informat;
AVFormatContext *m_outformat;
AVStream *m_in_vid_strm, *m_out_vid_strm;
AVStream *m_in_aud_strm, *m_out_aud_strm;
int VideoClipper::Init(const wxString& filename)
{
int ret = 0;
char errbuf[64];
av_register_all();
if ((ret = avformat_open_input( &m_informat, filename.mb_str(), 0, 0)) != 0 )
{
av_strerror(ret,errbuf,sizeof(errbuf));
PRINT_VAL("Not able to Open file;; ", errbuf)
ret = -1;
return ret;
}
else
{
PRINT_MSG("Opened File ")
}
if ((ret = avformat_find_stream_info(m_informat, 0))< 0 )
{
av_strerror(ret,errbuf,sizeof(errbuf));
PRINT_VAL("Not Able to find stream info:: ", errbuf)
ret = -1;
return ret;
}
else
{
PRINT_MSG("Got stream Info ")
}
for(unsigned int i = 0; i<m_informat->nb_streams; i++)
{
if(m_informat->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
PRINT_MSG("Found Video Stream ")
m_in_vid_strm_idx = i;
m_in_vid_strm = m_informat->streams[i];
}
if(m_informat->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
{
PRINT_MSG("Found Audio Stream ")
m_in_aud_strm_idx = i;
m_in_aud_strm = m_informat->streams[i];
}
}
AVOutputFormat *outfmt = NULL;
std::string outfile = std::string(filename) + "clip_out.avi";
outfmt = av_guess_format(NULL,outfile.c_str(),NULL);
if(outfmt == NULL)
{
ret = -1;
return ret;
}
else
{
m_outformat = avformat_alloc_context();
if(m_outformat)
{
m_outformat->oformat = outfmt;
_snprintf(m_outformat->filename, sizeof(m_outformat->filename), "%s", outfile.c_str());
}
else
{
ret = -1;
return ret;
}
}
AVCodec *out_vid_codec,*out_aud_codec;
out_vid_codec = out_aud_codec = NULL;
if(outfmt->video_codec != AV_CODEC_ID_NONE && m_in_vid_strm != NULL)
{
out_vid_codec = avcodec_find_encoder(outfmt->video_codec);
if(NULL == out_vid_codec)
{
PRINT_MSG("Could Not Find Vid Encoder")
ret = -1;
return ret;
}
else
{
PRINT_MSG("Found Out Vid Encoder ")
m_out_vid_strm = avformat_new_stream(m_outformat, out_vid_codec);
if(NULL == m_out_vid_strm)
{
PRINT_MSG("Failed to Allocate Output Vid Strm ")
ret = -1;
return ret;
}
else
{
PRINT_MSG("Allocated Video Stream ")
if(avcodec_copy_context(m_out_vid_strm->codec, m_informat->streams[m_in_vid_strm_idx]->codec) != 0)
{
PRINT_MSG("Failed to Copy Context ")
ret = -1;
return ret;
}
}
}
}
if(outfmt->audio_codec != AV_CODEC_ID_NONE && m_in_aud_strm != NULL)
{
out_aud_codec = avcodec_find_encoder(outfmt->audio_codec);
if(NULL == out_aud_codec)
{
PRINT_MSG("Could Not Find Out Aud Encoder ")
ret = -1;
return ret;
}
else
{
PRINT_MSG("Found Out Aud Encoder ")
m_out_aud_strm = avformat_new_stream(m_outformat, out_aud_codec);
if(NULL == m_out_aud_strm)
{
PRINT_MSG("Failed to Allocate Out Vid Strm ")
ret = -1;
return ret;
}
else
{
if(avcodec_copy_context(m_out_aud_strm->codec, m_informat->streams[m_in_aud_strm_idx]->codec) != 0)
{
PRINT_MSG("Failed to Copy Context ")
ret = -1;
return ret;
}
}
}
}
if (!(outfmt->flags & AVFMT_NOFILE))
{
if (avio_open2(&m_outformat->pb, outfile.c_str(), AVIO_FLAG_WRITE,NULL, NULL) < 0)
{
PRINT_VAL("Could Not Open File ", outfile)
ret = -1;
return ret;
}
}
/* Write the stream header, if any. */
if (avformat_write_header(m_outformat, NULL) < 0)
{
PRINT_VAL("Error Occurred While Writing Header ", outfile)
ret = -1;
return ret;
}
else
{
PRINT_MSG("Written Output header ")
m_init_done = true;
}
return ret;
}
Here is the Clean-up part
void VideoClipper::ReleaseResource(void)
{
if(m_in_aud_strm && m_in_aud_strm->codec)
{
avcodec_close(m_in_aud_strm->codec);
PRINT_MSG("Closed Input Audio Codec ")
}
if(m_in_vid_strm && m_in_vid_strm->codec)
{
avcodec_close(m_in_vid_strm->codec);
PRINT_MSG("Closed Input Video Codec ")
}
if(m_informat)
{
avformat_close_input(&m_informat);
PRINT_MSG("Freed Input Format Contex ")
}
if(m_out_aud_strm && m_out_aud_strm->codec)
{
avcodec_close(m_out_aud_strm->codec);
PRINT_MSG("Closed Output Audio Codec ")
}
if(m_out_vid_strm && m_out_vid_strm->codec)
{
avcodec_close(m_out_vid_strm->codec);
PRINT_MSG("Closed Output Audio Codec ")
}
if(m_outformat)
{
avformat_close_input(&m_outformat);
m_outformat = NULL;
PRINT_MSG("Closed Output Format ")
}
}
Memory Leaks message
Detected memory leaks!
Dumping objects ->
{13691} normal block at 0x01046A60, 4479 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
{13685} normal block at 0x01043FD0, 10831 bytes long.
Data: < ? > CD CD CD CD CD CD CD CD D0 3F 04 01 ED ED ED ED
Object dump complete.
I'm using latest version of ffmpeg on Visual Studio 2012.
Please suggest where I'm missing.
Thanks
Pradeep
There are lots of thing that matters here
first you need to close io
if (!(fmt->flags & AVFMT_NOFILE))
{
/* Close the output file. */
avio_close(ctx->oc->pb);
}
you should also call
avformat_free_context(ctx->oc);
There is always 24 bytes memory leakage at my system due to allocation pthread_mutex in libavcodec/utils.c of ffmpeg, and there is no way to free that memory.atleast till I or someone fix the code.
The program runs fine for a few minutes and then ReadFile starts failing with error code ERROR_WORKING_SET_QUOTA.
I'm using ReadFile with overlapped I/O like so:
while (continueReading)
{
BOOL bSuccess = ReadFile(deviceHandle, pReadBuf, length,
&bytesRead, readOverlappedPtr);
waitVal = WaitForMultipleObjects(
(sizeof(eventsToWaitFor)/sizeof(eventsToWaitFor[0])),
eventsToWaitFor, FALSE, INFINITE);
if (waitVal == WAIT_OBJECT_0) {
// do stuff
} else if (waitVal == WAIT_OBJECT_0 + 1) {
// do stuff
} else if (waitVal == WAIT_OBJECT_0 + 2) {
// complete the read
bSuccess = GetOverlappedResult(deviceHandle, &readOverlapped,
&bytesRead, FALSE);
if (!bSuccess) {
errorCode = GetLastError();
printf("ReadFile error=%d\n", errorCode);
}
}
}
Why am I getting this error?
The problem is that ReadFile is getting called more times than GetOverlappedResult. Causing the process to run out of resources for dealing with all the outstanding reads.
Additionally, we should check the result of ReadFile and ensure the result is ERROR_IO_PENDING, if it isn't and ReadFile returned FALSE then there is another problem.
Ensure that GetOverlappedResult is called once for each successful call to ReadFile. Like so:
BOOL bPerformRead = TRUE;
while (continueReading)
{
BOOL bSuccess = TRUE;
// only perform the read if the last one has finished
if (bPerformRead) {
bSuccess = ReadFile(deviceHandle, pReadBuf, length,
&bytesRead, readOverlappedPtr);
if (!bSuccess) {
errorCode = GetLastError();
if (errorCode != ERROR_IO_PENDING) {
printf("ReadFile error=%d\n", errorCode);
return;
}
} else {
// read completed right away
continue;
}
// we can't perform another read until this one finishes
bPerformRead = FALSE;
}
waitVal = WaitForMultipleObjects(
(sizeof(eventsToWaitFor)/sizeof(eventsToWaitFor[0])),
eventsToWaitFor, FALSE, INFINITE);
if (waitVal == WAIT_OBJECT_0) {
// do stuff
} else if (waitVal == WAIT_OBJECT_0 + 1) {
// do stuff
} else if (waitVal == WAIT_OBJECT_0 + 2) {
// complete the read
bSuccess = GetOverlappedResult(deviceHandle, &readOverlapped,
&bytesRead, FALSE);
// the read is finished, we can read again
bPerformRead = TRUE;
if (!bSuccess) {
errorCode = GetLastError();
printf("GetOverlappedResult from ReadFile error=%d\n", errorCode);
}
}
}