Qt 6.x
The Qt SDK
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
qcore_unix.cpp
Go to the documentation of this file.
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#include <QtCore/private/qglobal_p.h>
6#include "qcore_unix_p.h"
7#include "qelapsedtimer.h"
8
9#include <stdlib.h>
10
11#ifdef __GLIBC__
12# include <sys/syscall.h>
13# include <pthread.h>
14# include <unistd.h>
15#endif
16
17#ifdef Q_OS_DARWIN
18#include <mach/mach_time.h>
19#endif
20
22
24{
25#ifndef PATH_MAX
26 // suitably large value that won't consume too much memory
27# define PATH_MAX 1024*1024
28#endif
29
31
32 ssize_t len = ::readlink(path, buf.data(), buf.size());
33 while (len == buf.size()) {
34 // readlink(2) will fill our buffer and not necessarily terminate with NUL;
35 if (buf.size() >= PATH_MAX) {
36 errno = ENAMETOOLONG;
37 return QByteArray();
38 }
39
40 // double the size and try again
41 buf.resize(buf.size() * 2);
42 len = ::readlink(path, buf.data(), buf.size());
43 }
44
45 if (len == -1)
46 return QByteArray();
47
48 buf.resize(len);
49 return buf;
50}
51
52#if defined(Q_PROCESSOR_X86_32) && defined(__GLIBC__)
53# if !__GLIBC_PREREQ(2, 22)
54// glibc prior to release 2.22 had a bug that suppresses the third argument to
55// open() / open64() / openat(), causing file creation with O_TMPFILE to have
56// the wrong permissions. So we bypass the glibc implementation and go straight
57// for the syscall. See
58// https://sourceware.org/git/?p=glibc.git;a=commit;h=65f6f938cd562a614a68e15d0581a34b177ec29d
59int qt_open64(const char *pathname, int flags, mode_t mode)
60{
61 return syscall(SYS_open, pathname, flags | O_LARGEFILE, mode);
62}
63# endif
64#endif
65
66#ifndef QT_BOOTSTRAPPED
67
68static inline void do_gettime(qint64 *sec, qint64 *frac)
69{
70 timespec ts;
71 clockid_t clk = CLOCK_REALTIME;
72#if defined(CLOCK_MONOTONIC_RAW)
73 clk = CLOCK_MONOTONIC_RAW;
74#elif defined(CLOCK_MONOTONIC)
75 clk = CLOCK_MONOTONIC;
76#endif
77
78 clock_gettime(clk, &ts);
79 *sec = ts.tv_sec;
80 *frac = ts.tv_nsec;
81}
82
83// also used in qeventdispatcher_unix.cpp
84struct timespec qt_gettime() noexcept
85{
86 qint64 sec, frac;
87 do_gettime(&sec, &frac);
88
89 timespec tv;
90 tv.tv_sec = sec;
91 tv.tv_nsec = frac;
92
93 return tv;
94}
95
96#if QT_CONFIG(poll_pollts)
97# define ppoll pollts
98#endif
99
100static inline bool time_update(struct timespec *tv, const struct timespec &start,
101 const struct timespec &timeout)
102{
103 // clock source is (hopefully) monotonic, so we can recalculate how much timeout is left;
104 // if it isn't monotonic, we'll simply hope that it hasn't jumped, because we have no alternative
105 struct timespec now = qt_gettime();
106 *tv = timeout + start - now;
107 return tv->tv_sec >= 0;
108}
109
110#if QT_CONFIG(poll_poll)
111static inline int timespecToMillisecs(const struct timespec *ts)
112{
113 return (ts == NULL) ? -1 :
114 (ts->tv_sec * 1000) + (ts->tv_nsec / 1000000);
115}
116#endif
117
118// defined in qpoll.cpp
119int qt_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts);
120
121static inline int qt_ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts)
122{
123#if QT_CONFIG(poll_ppoll) || QT_CONFIG(poll_pollts)
124 return ::ppoll(fds, nfds, timeout_ts, nullptr);
125#elif QT_CONFIG(poll_poll)
126 return ::poll(fds, nfds, timespecToMillisecs(timeout_ts));
127#elif QT_CONFIG(poll_select)
128 return qt_poll(fds, nfds, timeout_ts);
129#else
130 // configure.json reports an error when everything is not available
131#endif
132}
133
134
142int qt_safe_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts)
143{
144 if (!timeout_ts) {
145 // no timeout -> block forever
146 int ret;
147 EINTR_LOOP(ret, qt_ppoll(fds, nfds, nullptr));
148 return ret;
149 }
150
151 timespec start = qt_gettime();
152 timespec timeout = *timeout_ts;
153
154 // loop and recalculate the timeout as needed
155 forever {
156 const int ret = qt_ppoll(fds, nfds, &timeout);
157 if (ret != -1 || errno != EINTR)
158 return ret;
159
160 // recalculate the timeout
161 if (!time_update(&timeout, start, *timeout_ts)) {
162 // timeout during update
163 // or clock reset, fake timeout error
164 return 0;
165 }
166 }
167}
168
169#endif // QT_BOOTSTRAPPED
170
\inmodule QtCore
Definition qbytearray.h:57
EGLint EGLint EGLint EGLint int int int int * fds
Combined button and popup list for selecting options.
constexpr Initialization Uninitialized
int qt_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts)
Definition qpoll.cpp:136
QT_BEGIN_NAMESPACE QByteArray qt_readlink(const char *path)
static void do_gettime(qint64 *sec, qint64 *frac)
struct timespec qt_gettime() noexcept
static int qt_ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts)
#define PATH_MAX
int qt_safe_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts)
static bool time_update(struct timespec *tv, const struct timespec &start, const struct timespec &timeout)
#define EINTR_LOOP(var, cmd)
#define forever
Definition qforeach.h:78
return ret
GLenum mode
GLbitfield GLuint64 timeout
[4]
GLenum GLuint GLenum GLsizei const GLchar * buf
GLbitfield flags
GLuint start
GLenum GLsizei len
GLsizei const GLchar *const * path
long long qint64
Definition qtypes.h:55