简体   繁体   English

如何确定ReadFile函数超时?

[英]How do I find out that ReadFile function timed-out?

When I do not set timeout settings via GetTimeout & SetTimeout after I connect my USB-UART converter to my laptop, the ReadFile becomes blocking. 将USB-UART转换器连接到笔记本电脑后,如果我未通过GetTimeout和SetTimeout设置超时设置,则ReadFile将被阻止。 However, once I set them via SetTimeOut, the ReadFile is not blocking anymore and returns true even if the given number of bytes were not read. 但是,一旦我通过SetTimeOut设置它们,即使没有读取给定的字节数,ReadFile也不再阻塞并且返回true。

When ReadFile returns true but the dwRead parameter says 0 since no data was going into my PC via serial port, I conclude that the ReadFile function must have timed out. 当ReadFile返回true,但dwRead参数为0时(因为没有数据通过串行端口进入我的PC),我得出结论说ReadFile函数必须已超时。 However, using GetLastError returns 0. How can I be verify in my C++ program that the ReadFile has actually timedout? 但是,使用GetLastError返回0。如何在C ++程序中验证ReadFile实际超时?

When using SetCommTimeouts() with ReadFile() , the COMMTIMEOUTS documentation says: SetCommTimeouts()ReadFile()COMMTIMEOUTS文档说:

ReadIntervalTimeout ReadIntervalTimeout
The maximum time allowed to elapse before the arrival of the next byte on the communications line, in milliseconds. 在通信线路上下一个字节到达之前允许经过的最长时间(以毫秒为单位)。 If the interval between the arrival of any two bytes exceeds this amount, the ReadFile operation is completed and any buffered data is returned . 如果任意两个字节到达之间的间隔超过此数量,则ReadFile操作完成,并返回所有缓冲的数据 A value of zero indicates that interval time-outs are not used. 零值表示未使用间隔超时。

If a timeout occurs, the read is complete ( ReadFile() returns TRUE), and the number of bytes that had been buffered before the timeout elapsed is reflected in your dwRead variable. 如果发生超时,则读取完成( ReadFile()返回TRUE),并且在dwRead变量中反映出超时之前已缓冲的字节数。 So, you will know if a timeout occurred if dwRead is less than the number of bytes you asked ReadFile() to read. 因此,如果dwRead 小于要求ReadFile()读取的字节数,您将知道是否发生超时。 If there was no buffered data, dwRead will be 0. If dwRead is equal to the number of bytes you asked for, there was no timeout since ReadFile() exited when the last requested byte was read. 如果没有缓冲的数据,则dwRead将为0。如果dwRead 等于您要求的字节数,则自从ReadFile()退出时开始读取最后一个请求的字节以来就没有超时。

most simplest and accurate way use NT api NtReadFile and check final status of operation. 最简单准确的方法是使用NT api NtReadFile并检查操作的最终状态。 timeout <=> iosb.Status == STATUS_TIMEOUT. 超时<=> iosb.Status == STATUS_TIMEOUT。 kernel32 api ReadFile - lost info for this status(STATUS_TIMEOUT), because it check only for STATUS_PENDING and 0 > status kernel32 api ReadFile-此状态(STATUS_TIMEOUT)的信息丢失,因为它仅检查STATUS_PENDING和0>状态

for synchronous work, can use code like this: 对于同步工作,可以使用如下代码:

void SyncTest(POBJECT_ATTRIBUTES poa)
{
    HANDLE hFile;
    IO_STATUS_BLOCK iosb;
    NTSTATUS status = NtOpenFile(&hFile, FILE_ALL_ACCESS, poa, &iosb, FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT);
    if (0 <= status)
    {
        SERIAL_TIMEOUTS st = { 4000, 1, 0, 1, 0 };
        status = NtDeviceIoControlFile(hFile, 0, 0, 0, &iosb, IOCTL_SERIAL_SET_TIMEOUTS, &st, sizeof(st), 0, 0);
        DbgPrint("time %x[%x,%p]\n", status, iosb.Status, iosb.Information);
        if (0 <= status)
        {
            UCHAR buf[256];
            status = NtReadFile(hFile, 0, 0, 0, &iosb, buf, sizeof(buf), 0, 0);
            DbgPrint("read %x [%x,%p]\n", status, iosb.Status, iosb.Information);
            //assert(status == iosb.Status);
            if (status == STATUS_TIMEOUT)
            {
                DbgPrint("timeout\n");
            }
        }
        NtClose(hFile);
    }
}

for asynchronous: 对于异步:

class __declspec(novtable) IoObject 
{
    friend class UserIrp;
protected:
    HANDLE _hFile;
private:
    LONG _dwRef;

protected:
    virtual ~IoObject()
    {
        if (_hFile) NtClose(_hFile);
    }
    virtual void OnIoComplete(NTSTATUS status, ULONG_PTR Information, ULONG code, PVOID pv) = 0;
public:

    NTSTATUS BindIoCompletion();

    void AddRef()
    {
        InterlockedIncrement(&_dwRef);
    }

    void Release()
    {
        if (!InterlockedDecrement(&_dwRef)) delete this;
    }

    IoObject()
    {
        _hFile = 0;
        _dwRef = 1;
    }
};

class UserIrp : public IO_STATUS_BLOCK
{
    friend IoObject;

    IoObject* _pObj;
    PVOID _pv;
    LONG _dwRef;
    ULONG _code;

    static VOID WINAPI OnComplete(NTSTATUS Status, ULONG_PTR Information, UserIrp* This)
    {
        This->_pObj->OnIoComplete(Status, Information, This->_code, This->_pv);
        This->Release();
    }

    ~UserIrp()
    {
        _pObj->Release();
    }

public:

    NTSTATUS CheckStatus(NTSTATUS status)
    {
        if (NT_ERROR(status))
        {
            OnComplete(status, Information, this);
        }

        return status;
    }

    void AddRef()
    {
        InterlockedIncrement(&_dwRef);
    }

    void Release()
    {
        if (!InterlockedDecrement(&_dwRef)) delete this;
    }

    UserIrp(IoObject* pObj, ULONG code, PVOID pv) : _pObj(pObj), _dwRef(1), _code(code), _pv(pv)
    {
        pObj->AddRef();
    }
};

NTSTATUS IoObject::BindIoCompletion()
{
    return RtlSetIoCompletionCallback(_hFile, (LPOVERLAPPED_COMPLETION_ROUTINE)UserIrp::OnComplete, 0);
}

class MySerial : public IoObject
{
    void OnIoComplete(NTSTATUS status, ULONG_PTR Information, ULONG code, PVOID pv)
    {
        DbgPrint("OnIoComplete(%x, %p, %.4s, %p)\n", status, Information, &code, pv);

        switch (code)
        {
        case 'time':
            if (0 <= status)
            {
                if (PUCHAR buf = new UCHAR[256])
                {
                    if (UserIrp* Irp = new UserIrp(this, 'read', buf))
                    {
                        static LARGE_INTEGER ByteOffset;
                        status = Irp->CheckStatus(NtReadFile(_hFile, 0, 0, Irp, Irp, buf, 256, &ByteOffset, 0));
                        DbgPrint("read begin = %x\n", status);
                        return ;
                    }
                    delete buf;
                }
            }
            break;
        case 'read':
            DbgPrint("read end(%x, %p)\n", status, Information);
            if (status == STATUS_TIMEOUT)
            {
                DbgPrint("timeout\n");
            }
            delete pv;
            break;
        }
    }

    virtual ~MySerial()
    {
        DbgPrint("--MySerial<%p>\n", this);
    }

public:

    MySerial()
    {
        DbgPrint("++MySerial<%p>\n", this);
    }

    NTSTATUS Open(POBJECT_ATTRIBUTES poa)
    {
        IO_STATUS_BLOCK iosb;
        return NtOpenFile(&_hFile, FILE_ALL_ACCESS, poa, &iosb, FILE_SHARE_VALID_FLAGS, 0);
    }

    NTSTATUS SetTimeouts(ULONG ms)
    {
        if (UserIrp* Irp = new UserIrp(this, 'time', 0))
        {
            SERIAL_TIMEOUTS st = { ms, 1, 0, 1, 0 };
            return Irp->CheckStatus(ZwDeviceIoControlFile(_hFile, 0, 0, Irp, Irp, IOCTL_SERIAL_SET_TIMEOUTS, &st, sizeof(st), 0, 0));
        }

        return STATUS_INSUFFICIENT_RESOURCES;
    }
};

void AsyncTest(POBJECT_ATTRIBUTES poa)
{
    if (MySerial* p = new MySerial)
    {
        if (0 <= p->Open(poa) && 0 <= p->BindIoCompletion())
        {
            NTSTATUS status = p->SetTimeouts(4000);
            DbgPrint("set timeout=%x\n", status);
        }
        p->Release();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM