1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/private/qglobal_p.h>
#include <QtCore/qbasicatomic.h>
#include "qcore_unix_p.h"
#include <stdlib.h>
#ifdef __GLIBC__
# include <sys/syscall.h>
# include <pthread.h>
# include <unistd.h>
#endif
#ifdef Q_OS_DARWIN
#include <mach/mach_time.h>
#endif
QT_BEGIN_NAMESPACE
void qt_ignore_sigpipe() noexcept // noexcept: sigaction(2) is not a Posix Cancellation Point
{
// Set to ignore SIGPIPE once only.
Q_CONSTINIT static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0);
if (!atom.loadRelaxed()) {
// More than one thread could turn off SIGPIPE at the same time
// But that's acceptable because they all would be doing the same
// action
struct sigaction noaction = {};
noaction.sa_handler = SIG_IGN;
::sigaction(SIGPIPE, &noaction, nullptr);
atom.storeRelaxed(1);
}
}
QByteArray qt_readlink(const char *path)
{
#ifndef PATH_MAX
// suitably large value that won't consume too much memory
# define PATH_MAX 1024*1024
#endif
QByteArray buf(256, Qt::Uninitialized);
ssize_t len = ::readlink(path, buf.data(), buf.size());
while (len == buf.size()) {
// readlink(2) will fill our buffer and not necessarily terminate with NUL;
if (buf.size() >= PATH_MAX) {
errno = ENAMETOOLONG;
return QByteArray();
}
// double the size and try again
buf.resize(buf.size() * 2);
len = ::readlink(path, buf.data(), buf.size());
}
if (len == -1)
return QByteArray();
buf.resize(len);
return buf;
}
#if defined(Q_PROCESSOR_X86_32) && defined(__GLIBC__)
# if !__GLIBC_PREREQ(2, 22)
// glibc prior to release 2.22 had a bug that suppresses the third argument to
// open() / open64() / openat(), causing file creation with O_TMPFILE to have
// the wrong permissions. So we bypass the glibc implementation and go straight
// for the syscall. See
// https://sourceware.org/git/?p=glibc.git;a=commit;h=65f6f938cd562a614a68e15d0581a34b177ec29d
int qt_open64(const char *pathname, int flags, mode_t mode)
{
return syscall(SYS_open, pathname, flags | O_LARGEFILE, mode);
}
# endif
#endif
#ifndef QT_BOOTSTRAPPED
#if QT_CONFIG(poll_pollts)
# define ppoll pollts
#endif
[[maybe_unused]]
static inline int timespecToMillisecs(const struct timespec *ts)
{
using namespace std::chrono;
if (!ts)
return -1;
auto ms = ceil<milliseconds>(timespecToChrono<nanoseconds>(*ts));
return int(ms.count());
}
// defined in qpoll.cpp
int qt_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts);
static inline int qt_ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts)
{
#if QT_CONFIG(poll_ppoll) || QT_CONFIG(poll_pollts)
return ::ppoll(fds, nfds, timeout_ts, nullptr);
#elif QT_CONFIG(poll_poll)
return ::poll(fds, nfds, timespecToMillisecs(timeout_ts));
#elif QT_CONFIG(poll_select)
return qt_poll(fds, nfds, timeout_ts);
#else
// configure.json reports an error when everything is not available
#endif
}
/*!
\internal
Behaves as close to POSIX poll(2) as practical but may be implemented
using select(2) where necessary. In that case, returns -1 and sets errno
to EINVAL if passed any descriptor greater than or equal to FD_SETSIZE.
*/
int qt_safe_poll(struct pollfd *fds, nfds_t nfds, QDeadlineTimer deadline)
{
if (deadline.isForever()) {
// no timeout -> block forever
int ret;
QT_EINTR_LOOP(ret, qt_ppoll(fds, nfds, nullptr));
return ret;
}
using namespace std::chrono;
nanoseconds remaining = deadline.remainingTimeAsDuration();
// loop and recalculate the timeout as needed
do {
timespec ts = durationToTimespec(remaining);
const int ret = qt_ppoll(fds, nfds, &ts);
if (ret != -1 || errno != EINTR)
return ret;
remaining = deadline.remainingTimeAsDuration();
} while (remaining > 0ns);
return 0;
}
#endif // QT_BOOTSTRAPPED
QT_END_NAMESPACE
|