1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // Copyright (C) 2016 Intel Corporation. |
3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
4 | |
5 | #ifndef QCORE_UNIX_P_H |
6 | #define QCORE_UNIX_P_H |
7 | |
8 | // |
9 | // W A R N I N G |
10 | // ------------- |
11 | // |
12 | // This file is not part of the Qt API. It exists for the convenience |
13 | // of Qt code on Unix. This header file may change from version to |
14 | // version without notice, or even be removed. |
15 | // |
16 | // We mean it. |
17 | // |
18 | |
19 | #include "qplatformdefs.h" |
20 | #include <QtCore/private/qglobal_p.h> |
21 | #include "qatomic.h" |
22 | #include "qbytearray.h" |
23 | |
24 | #ifndef Q_OS_UNIX |
25 | # error "qcore_unix_p.h included on a non-Unix system" |
26 | #endif |
27 | |
28 | #include <string.h> |
29 | #include <sys/types.h> |
30 | #include <sys/stat.h> |
31 | #include <unistd.h> |
32 | |
33 | #if !defined (Q_OS_VXWORKS) |
34 | # if !defined(Q_OS_HPUX) || defined(__ia64) |
35 | # include <sys/select.h> |
36 | # endif |
37 | # include <sys/time.h> |
38 | #else |
39 | # include <selectLib.h> |
40 | #endif |
41 | |
42 | #include <chrono> |
43 | #include <sys/wait.h> |
44 | #include <errno.h> |
45 | #include <fcntl.h> |
46 | |
47 | #if !defined(QT_POSIX_IPC) && !defined(QT_NO_SHAREDMEMORY) && !defined(Q_OS_ANDROID) |
48 | # include <sys/ipc.h> |
49 | #endif |
50 | |
51 | #if defined(Q_OS_VXWORKS) |
52 | # include <ioLib.h> |
53 | #endif |
54 | |
55 | #ifdef QT_NO_NATIVE_POLL |
56 | # include "qpoll_p.h" |
57 | #else |
58 | # include <poll.h> |
59 | #endif |
60 | |
61 | struct sockaddr; |
62 | |
63 | #define EINTR_LOOP(var, cmd) \ |
64 | do { \ |
65 | var = cmd; \ |
66 | } while (var == -1 && errno == EINTR) |
67 | |
68 | QT_BEGIN_NAMESPACE |
69 | |
70 | Q_DECLARE_TYPEINFO(pollfd, Q_PRIMITIVE_TYPE); |
71 | |
72 | static constexpr auto OneSecAsNsecs = std::chrono::nanoseconds(std::chrono::seconds{ 1 }).count(); |
73 | |
74 | inline timespec durationToTimespec(std::chrono::nanoseconds timeout) noexcept |
75 | { |
76 | using namespace std::chrono; |
77 | const seconds secs = duration_cast<seconds>(d: timeout); |
78 | const nanoseconds frac = timeout - secs; |
79 | struct timespec ts; |
80 | ts.tv_sec = secs.count(); |
81 | ts.tv_nsec = frac.count(); |
82 | return ts; |
83 | } |
84 | |
85 | template <typename Duration> |
86 | inline Duration timespecToChrono(timespec ts) noexcept |
87 | { |
88 | using namespace std::chrono; |
89 | return duration_cast<Duration>(seconds{ts.tv_sec} + nanoseconds{ts.tv_nsec}); |
90 | } |
91 | |
92 | inline std::chrono::milliseconds timespecToChronoMs(timespec ts) noexcept |
93 | { |
94 | return timespecToChrono<std::chrono::milliseconds>(ts); |
95 | } |
96 | |
97 | // Internal operator functions for timespecs |
98 | constexpr inline timespec &normalizedTimespec(timespec &t) |
99 | { |
100 | while (t.tv_nsec >= OneSecAsNsecs) { |
101 | ++t.tv_sec; |
102 | t.tv_nsec -= OneSecAsNsecs; |
103 | } |
104 | while (t.tv_nsec < 0) { |
105 | --t.tv_sec; |
106 | t.tv_nsec += OneSecAsNsecs; |
107 | } |
108 | return t; |
109 | } |
110 | constexpr inline bool operator<(const timespec &t1, const timespec &t2) |
111 | { return t1.tv_sec < t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec < t2.tv_nsec); } |
112 | constexpr inline bool operator==(const timespec &t1, const timespec &t2) |
113 | { return t1.tv_sec == t2.tv_sec && t1.tv_nsec == t2.tv_nsec; } |
114 | constexpr inline bool operator!=(const timespec &t1, const timespec &t2) |
115 | { return !(t1 == t2); } |
116 | constexpr inline timespec &operator+=(timespec &t1, const timespec &t2) |
117 | { |
118 | t1.tv_sec += t2.tv_sec; |
119 | t1.tv_nsec += t2.tv_nsec; |
120 | return normalizedTimespec(t&: t1); |
121 | } |
122 | constexpr inline timespec operator+(const timespec &t1, const timespec &t2) |
123 | { |
124 | timespec tmp = {}; |
125 | tmp.tv_sec = t1.tv_sec + t2.tv_sec; |
126 | tmp.tv_nsec = t1.tv_nsec + t2.tv_nsec; |
127 | return normalizedTimespec(t&: tmp); |
128 | } |
129 | constexpr inline timespec operator-(const timespec &t1, const timespec &t2) |
130 | { |
131 | timespec tmp = {}; |
132 | tmp.tv_sec = t1.tv_sec - (t2.tv_sec - 1); |
133 | tmp.tv_nsec = t1.tv_nsec - (t2.tv_nsec + OneSecAsNsecs); |
134 | return normalizedTimespec(t&: tmp); |
135 | } |
136 | constexpr inline timespec operator*(const timespec &t1, int mul) |
137 | { |
138 | timespec tmp = {}; |
139 | tmp.tv_sec = t1.tv_sec * mul; |
140 | tmp.tv_nsec = t1.tv_nsec * mul; |
141 | return normalizedTimespec(t&: tmp); |
142 | } |
143 | inline timeval timespecToTimeval(timespec ts) |
144 | { |
145 | timeval tv; |
146 | tv.tv_sec = ts.tv_sec; |
147 | tv.tv_usec = ts.tv_nsec / 1000; |
148 | return tv; |
149 | } |
150 | |
151 | inline timespec &operator+=(timespec &t1, std::chrono::milliseconds msecs) |
152 | { |
153 | t1 += durationToTimespec(timeout: msecs); |
154 | return t1; |
155 | } |
156 | |
157 | inline timespec &operator+=(timespec &t1, int ms) |
158 | { |
159 | t1 += std::chrono::milliseconds{ms}; |
160 | return t1; |
161 | } |
162 | |
163 | inline timespec operator+(const timespec &t1, std::chrono::milliseconds msecs) |
164 | { |
165 | timespec tmp = t1; |
166 | tmp += msecs; |
167 | return tmp; |
168 | } |
169 | |
170 | inline timespec operator+(const timespec &t1, int ms) |
171 | { |
172 | return t1 + std::chrono::milliseconds{ms}; |
173 | } |
174 | |
175 | inline timespec qAbsTimespec(timespec ts) |
176 | { |
177 | if (ts.tv_sec < 0) { |
178 | ts.tv_sec = -ts.tv_sec - 1; |
179 | ts.tv_nsec -= OneSecAsNsecs; |
180 | } |
181 | if (ts.tv_sec == 0 && ts.tv_nsec < 0) { |
182 | ts.tv_nsec = -ts.tv_nsec; |
183 | } |
184 | return normalizedTimespec(t&: ts); |
185 | } |
186 | |
187 | inline void qt_ignore_sigpipe() |
188 | { |
189 | // Set to ignore SIGPIPE once only. |
190 | Q_CONSTINIT static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0); |
191 | if (!atom.loadRelaxed()) { |
192 | // More than one thread could turn off SIGPIPE at the same time |
193 | // But that's acceptable because they all would be doing the same |
194 | // action |
195 | struct sigaction noaction; |
196 | memset(s: &noaction, c: 0, n: sizeof(noaction)); |
197 | noaction.sa_handler = SIG_IGN; |
198 | ::sigaction(SIGPIPE, act: &noaction, oact: nullptr); |
199 | atom.storeRelaxed(newValue: 1); |
200 | } |
201 | } |
202 | |
203 | #if defined(Q_PROCESSOR_X86_32) && defined(__GLIBC__) |
204 | # if !__GLIBC_PREREQ(2, 22) |
205 | Q_CORE_EXPORT int qt_open64(const char *pathname, int flags, mode_t); |
206 | # undef QT_OPEN |
207 | # define QT_OPEN qt_open64 |
208 | # endif |
209 | #endif |
210 | |
211 | // don't call QT_OPEN or ::open |
212 | // call qt_safe_open |
213 | static inline int qt_safe_open(const char *pathname, int flags, mode_t mode = 0777) |
214 | { |
215 | #ifdef O_CLOEXEC |
216 | flags |= O_CLOEXEC; |
217 | #endif |
218 | int fd; |
219 | EINTR_LOOP(fd, QT_OPEN(pathname, flags, mode)); |
220 | |
221 | #ifndef O_CLOEXEC |
222 | if (fd != -1) |
223 | ::fcntl(fd, F_SETFD, FD_CLOEXEC); |
224 | #endif |
225 | |
226 | return fd; |
227 | } |
228 | #undef QT_OPEN |
229 | #define QT_OPEN qt_safe_open |
230 | |
231 | #ifndef Q_OS_VXWORKS // no POSIX pipes in VxWorks |
232 | // don't call ::pipe |
233 | // call qt_safe_pipe |
234 | static inline int qt_safe_pipe(int pipefd[2], int flags = 0) |
235 | { |
236 | Q_ASSERT((flags & ~O_NONBLOCK) == 0); |
237 | |
238 | #ifdef QT_THREADSAFE_CLOEXEC |
239 | // use pipe2 |
240 | flags |= O_CLOEXEC; |
241 | return ::pipe2(pipedes: pipefd, flags: flags); // pipe2 is documented not to return EINTR |
242 | #else |
243 | int ret = ::pipe(pipefd); |
244 | if (ret == -1) |
245 | return -1; |
246 | |
247 | ::fcntl(pipefd[0], F_SETFD, FD_CLOEXEC); |
248 | ::fcntl(pipefd[1], F_SETFD, FD_CLOEXEC); |
249 | |
250 | // set non-block too? |
251 | if (flags & O_NONBLOCK) { |
252 | ::fcntl(pipefd[0], F_SETFL, ::fcntl(pipefd[0], F_GETFL) | O_NONBLOCK); |
253 | ::fcntl(pipefd[1], F_SETFL, ::fcntl(pipefd[1], F_GETFL) | O_NONBLOCK); |
254 | } |
255 | |
256 | return 0; |
257 | #endif |
258 | } |
259 | |
260 | #endif // Q_OS_VXWORKS |
261 | |
262 | // don't call dup or fcntl(F_DUPFD) |
263 | static inline int qt_safe_dup(int oldfd, int atleast = 0, int flags = FD_CLOEXEC) |
264 | { |
265 | Q_ASSERT(flags == FD_CLOEXEC || flags == 0); |
266 | |
267 | #ifdef F_DUPFD_CLOEXEC |
268 | int cmd = F_DUPFD; |
269 | if (flags & FD_CLOEXEC) |
270 | cmd = F_DUPFD_CLOEXEC; |
271 | return ::fcntl(fd: oldfd, cmd: cmd, atleast); |
272 | #else |
273 | // use F_DUPFD |
274 | int ret = ::fcntl(oldfd, F_DUPFD, atleast); |
275 | |
276 | if (flags && ret != -1) |
277 | ::fcntl(ret, F_SETFD, flags); |
278 | return ret; |
279 | #endif |
280 | } |
281 | |
282 | // don't call dup2 |
283 | // call qt_safe_dup2 |
284 | static inline int qt_safe_dup2(int oldfd, int newfd, int flags = FD_CLOEXEC) |
285 | { |
286 | Q_ASSERT(flags == FD_CLOEXEC || flags == 0); |
287 | |
288 | int ret; |
289 | #ifdef QT_THREADSAFE_CLOEXEC |
290 | // use dup3 |
291 | EINTR_LOOP(ret, ::dup3(oldfd, newfd, flags ? O_CLOEXEC : 0)); |
292 | return ret; |
293 | #else |
294 | EINTR_LOOP(ret, ::dup2(oldfd, newfd)); |
295 | if (ret == -1) |
296 | return -1; |
297 | |
298 | if (flags) |
299 | ::fcntl(newfd, F_SETFD, flags); |
300 | return 0; |
301 | #endif |
302 | } |
303 | |
304 | static inline qint64 qt_safe_read(int fd, void *data, qint64 maxlen) |
305 | { |
306 | qint64 ret = 0; |
307 | EINTR_LOOP(ret, QT_READ(fd, data, maxlen)); |
308 | return ret; |
309 | } |
310 | #undef QT_READ |
311 | #define QT_READ qt_safe_read |
312 | |
313 | static inline qint64 qt_safe_write(int fd, const void *data, qint64 len) |
314 | { |
315 | qint64 ret = 0; |
316 | EINTR_LOOP(ret, QT_WRITE(fd, data, len)); |
317 | return ret; |
318 | } |
319 | #undef QT_WRITE |
320 | #define QT_WRITE qt_safe_write |
321 | |
322 | static inline qint64 qt_safe_write_nosignal(int fd, const void *data, qint64 len) |
323 | { |
324 | qt_ignore_sigpipe(); |
325 | return qt_safe_write(fd, data, len); |
326 | } |
327 | |
328 | static inline int qt_safe_close(int fd) |
329 | { |
330 | int ret; |
331 | EINTR_LOOP(ret, QT_CLOSE(fd)); |
332 | return ret; |
333 | } |
334 | #undef QT_CLOSE |
335 | #define QT_CLOSE qt_safe_close |
336 | |
337 | // - VxWorks & iOS/tvOS/watchOS don't have processes |
338 | #if QT_CONFIG(process) |
339 | static inline int qt_safe_execve(const char *filename, char *const argv[], |
340 | char *const envp[]) |
341 | { |
342 | int ret; |
343 | EINTR_LOOP(ret, ::execve(filename, argv, envp)); |
344 | return ret; |
345 | } |
346 | |
347 | static inline int qt_safe_execv(const char *path, char *const argv[]) |
348 | { |
349 | int ret; |
350 | EINTR_LOOP(ret, ::execv(path, argv)); |
351 | return ret; |
352 | } |
353 | |
354 | static inline int qt_safe_execvp(const char *file, char *const argv[]) |
355 | { |
356 | int ret; |
357 | EINTR_LOOP(ret, ::execvp(file, argv)); |
358 | return ret; |
359 | } |
360 | |
361 | static inline pid_t qt_safe_waitpid(pid_t pid, int *status, int options) |
362 | { |
363 | int ret; |
364 | EINTR_LOOP(ret, ::waitpid(pid, status, options)); |
365 | return ret; |
366 | } |
367 | #endif // QT_CONFIG(process) |
368 | |
369 | #if !defined(_POSIX_MONOTONIC_CLOCK) |
370 | # define _POSIX_MONOTONIC_CLOCK -1 |
371 | #endif |
372 | |
373 | // in qelapsedtimer_mac.cpp or qtimestamp_unix.cpp |
374 | timespec qt_gettime() noexcept; |
375 | QByteArray qt_readlink(const char *path); |
376 | |
377 | /* non-static */ |
378 | inline bool qt_haveLinuxProcfs() |
379 | { |
380 | #ifdef Q_OS_LINUX |
381 | # ifdef QT_LINUX_ALWAYS_HAVE_PROCFS |
382 | return true; |
383 | # else |
384 | static const bool present = (access(name: "/proc/version" , F_OK) == 0); |
385 | return present; |
386 | # endif |
387 | #else |
388 | return false; |
389 | #endif |
390 | } |
391 | |
392 | Q_CORE_EXPORT int qt_safe_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts); |
393 | |
394 | static inline int qt_poll_msecs(struct pollfd *fds, nfds_t nfds, int timeout) |
395 | { |
396 | timespec ts, *pts = nullptr; |
397 | |
398 | if (timeout >= 0) { |
399 | ts.tv_sec = timeout / 1000; |
400 | ts.tv_nsec = (timeout % 1000) * 1000 * 1000; |
401 | pts = &ts; |
402 | } |
403 | |
404 | return qt_safe_poll(fds, nfds, timeout_ts: pts); |
405 | } |
406 | |
407 | static inline struct pollfd qt_make_pollfd(int fd, short events) |
408 | { |
409 | struct pollfd pfd = { .fd: fd, .events: events, .revents: 0 }; |
410 | return pfd; |
411 | } |
412 | |
413 | // according to X/OPEN we have to define semun ourselves |
414 | // we use prefix as on some systems sem.h will have it |
415 | struct semid_ds; |
416 | union qt_semun { |
417 | int val; /* value for SETVAL */ |
418 | struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ |
419 | unsigned short *array; /* array for GETALL, SETALL */ |
420 | }; |
421 | |
422 | QT_END_NAMESPACE |
423 | |
424 | #endif |
425 | |