tst_QFile: replicate the unixPipe test using FIFOs

Pipes are unnamed FIFOs, so they're basically the same.

The difference here is that open() blocks on opening a FIFO until both
ends of the FIFO are opened. This helps us in synchronizing the two
threads and thus ensuring that that the read() system call deep inside
QFile does, indeed, block.

We see this with strace -T on Linux:

[pid 662956] openat(AT_FDCWD, "/run/user/1000/tst_qfile_fifo.2575572361", O_RDONLY|O_CLOEXEC <unfinished ...>
... aux starts up ...
[pid 662957] prctl(PR_SET_NAME, "QThread") = 0 <0.000004>
[pid 662957] openat(AT_FDCWD, "/run/user/1000/tst_qfile_fifo.2575572361", O_WRONLY|O_CLOEXEC <unfinished ...>
[pid 662956] <... openat resumed>)      = 4 <0.000133>
[pid 662957] <... openat resumed>)      = 6 <0.000011>
[pid 662957] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=500000000},  <unfinished ...>
[pid 662956] read(4,  <unfinished ...>
[pid 662957] <... clock_nanosleep resumed>NULL) = 0 <0.500183>
[pid 662957] write(6, "\2", 1)          = 1 <0.000033>
[pid 662956] <... read resumed>"\2", 1) = 1 <0.500311>

Change-Id: I63b988479db546dabffcfffd1766d7a48819b149
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
(cherry picked from commit 01872d06d9a09c83f28b3ecebcb06f0ed81c5622)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Thiago Macieira 2023-06-08 17:53:29 -07:00 committed by Qt Cherry-pick Bot
parent 9432a7136f
commit bfd07607b2

View File

@ -13,6 +13,7 @@
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QRandomGenerator>
#include <QTemporaryDir>
#include <QTemporaryFile>
#include <QOperatingSystemVersion>
@ -227,6 +228,8 @@ private slots:
#ifdef Q_OS_UNIX
void unixPipe_data();
void unixPipe();
void unixFifo_data() { unixPipe_data(); }
void unixFifo();
void socketPair_data() { unixPipe_data(); }
void socketPair();
#endif
@ -2678,6 +2681,57 @@ void tst_QFile::unixPipe()
qt_safe_close(pipes[1]);
}
void tst_QFile::unixFifo()
{
QByteArray fifopath = []() -> QByteArray {
QByteArray dir = qgetenv("XDG_RUNTIME_DIR");
if (dir.isEmpty())
dir = QFile::encodeName(QDir::tempPath());
// try to create a FIFO
for (int attempts = 10; attempts; --attempts) {
QByteArray fifopath = dir + "/tst_qfile_fifo." +
QByteArray::number(QRandomGenerator::global()->generate());
int ret = mkfifo(fifopath, 0600);
if (ret == 0)
return fifopath;
}
qWarning("Failed to create a FIFO at %s; last error was %s",
dir.constData(), strerror(errno));
return {};
}();
if (fifopath.isEmpty())
return;
auto removeFifo = qScopeGuard([&fifopath] { unlink(fifopath); });
// with a FIFO, the two open() system calls synchronize
QScopedPointer<QThread> thr(QThread::create([&fifopath]() {
int fd = qt_safe_open(fifopath, O_WRONLY);
QTest::qSleep(500);
char c = 2;
qt_safe_write(fd, &c, 1);
qt_safe_close(fd);
}));
thr->start();
QFETCH(bool, useStdio);
QFile f;
if (useStdio) {
FILE *fh = fopen(fifopath, "rb");
QVERIFY(f.open(fh, QIODevice::ReadOnly | QIODevice::Unbuffered, QFileDevice::AutoCloseHandle));
} else {
f.setFileName(QFile::decodeName(fifopath));
QVERIFY(f.open(QIODevice::ReadOnly | QIODevice::Unbuffered));
}
char c = 0;
QCOMPARE(f.read(&c, 1), 1); // this ought to block
QCOMPARE(c, '\2');
thr->wait();
}
void tst_QFile::socketPair()
{
int pipes[2] = { -1, -1 };