Search code examples
windowsqtserial-portqtserialport

Why does QSerialPort::writeData start writes with a single-shot timer?


I'm trying to understand Qt's serial port module and I'm not too familiar with how Qt handles asynchronous I/O. On Windows, the QSerialPort::writeData method places the data to be written in a ring buffer and then starts a single-shot QTimer to actually perform the write when its timeout signal fires:

qint64 QSerialPortPrivate::writeData(const char *data, qint64 maxSize)
{
    Q_Q(QSerialPort);
    writeBuffer.append(data, maxSize);
    if (!writeBuffer.isEmpty() && !writeStarted) {
        if (!startAsyncWriteTimer) {
            startAsyncWriteTimer = new QTimer(q);
            QObjectPrivate::connect(startAsyncWriteTimer, &QTimer::timeout, this, &QSerialPortPrivate::_q_startAsyncWrite);
            startAsyncWriteTimer->setSingleShot(true);
        }
        if (!startAsyncWriteTimer->isActive())
            startAsyncWriteTimer->start();
    }
    return maxSize;
}

The readData method doesn't use a timer in this way, instead calling ReadFileEx directly.

What does the single-shot timer accomplish versus just calling WriteFileEx?


Solution

  • There is a special case for a QTimer with an interval of 0: this timer will fire once control returns to the event loop. The implementation on Unix/Linux does something similar, but not using a QTimer, instead having a subclass of QSocketNotifier that will get called when the port is able to be written to. Both of these implementations mean that you will buffer the data and write it out once you get back to the main event loop.

    There are two reasons that I can think of for doing this:

    • There is something different between the POSIX and Win32 serial APIs that require the code to be structured this way. As far as I am aware, this is not the case
    • What @Mike said in a comment: this will allow for data to be buffered before it is written

    The buffering seems like the most likely reason for this, as doing a syscall for each piece of data that you want to write would be a rather expensive operation.