| 1 |
/**************************************************************************** |
| 2 |
** |
| 3 |
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). |
| 4 |
** All rights reserved. |
| 5 |
** Contact: Nokia Corporation (qt-info@nokia.com) |
| 6 |
** |
| 7 |
** This file is part of the QtCore module of the Qt Toolkit. |
| 8 |
** |
| 9 |
** $QT_BEGIN_LICENSE:LGPL$ |
| 10 |
** GNU Lesser General Public License Usage |
| 11 |
** This file may be used under the terms of the GNU Lesser General Public |
| 12 |
** License version 2.1 as published by the Free Software Foundation and |
| 13 |
** appearing in the file LICENSE.LGPL included in the packaging of this |
| 14 |
** file. Please review the following information to ensure the GNU Lesser |
| 15 |
** General Public License version 2.1 requirements will be met: |
| 16 |
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| 17 |
** |
| 18 |
** In addition, as a special exception, Nokia gives you certain additional |
| 19 |
** rights. These rights are described in the Nokia Qt LGPL Exception |
| 20 |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| 21 |
** |
| 22 |
** GNU General Public License Usage |
| 23 |
** Alternatively, this file may be used under the terms of the GNU General |
| 24 |
** Public License version 3.0 as published by the Free Software Foundation |
| 25 |
** and appearing in the file LICENSE.GPL included in the packaging of this |
| 26 |
** file. Please review the following information to ensure the GNU General |
| 27 |
** Public License version 3.0 requirements will be met: |
| 28 |
** http://www.gnu.org/copyleft/gpl.html. |
| 29 |
** |
| 30 |
** Other Usage |
| 31 |
** Alternatively, this file may be used in accordance with the terms and |
| 32 |
** conditions contained in a signed written agreement between you and Nokia. |
| 33 |
** |
| 34 |
** |
| 35 |
** |
| 36 |
** |
| 37 |
** |
| 38 |
** $QT_END_LICENSE$ |
| 39 |
** |
| 40 |
****************************************************************************/ |
| 41 |
|
| 42 |
#ifndef QCORE_UNIX_P_H |
| 43 |
#define QCORE_UNIX_P_H |
| 44 |
|
| 45 |
// |
| 46 |
// W A R N I N G |
| 47 |
// ------------- |
| 48 |
// |
| 49 |
// This file is not part of the Qt API. It exists for the convenience |
| 50 |
// of Qt code on Unix. This header file may change from version to |
| 51 |
// version without notice, or even be removed. |
| 52 |
// |
| 53 |
// We mean it. |
| 54 |
// |
| 55 |
|
| 56 |
#include "qplatformdefs.h" |
| 57 |
|
| 58 |
#ifndef Q_OS_UNIX |
| 59 |
# error "qcore_unix_p.h included on a non-Unix system" |
| 60 |
#endif |
| 61 |
|
| 62 |
#include <sys/types.h> |
| 63 |
#include <sys/stat.h> |
| 64 |
#include <unistd.h> |
| 65 |
|
| 66 |
#include <sys/wait.h> |
| 67 |
#include <errno.h> |
| 68 |
#include <fcntl.h> |
| 69 |
|
| 70 |
#if defined(Q_OS_VXWORKS) |
| 71 |
# include <ioLib.h> |
| 72 |
#endif |
| 73 |
|
| 74 |
struct sockaddr; |
| 75 |
|
| 76 |
#if defined(Q_OS_LINUX) && defined(O_CLOEXEC) |
| 77 |
# define QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC 1 |
| 78 |
QT_BEGIN_NAMESPACE |
| 79 |
namespace QtLibcSupplement { |
| 80 |
inline int accept4(int, sockaddr *, QT_SOCKLEN_T *, int) |
| 81 |
{ errno = ENOSYS; return -1; } |
| 82 |
inline int dup3(int, int, int) |
| 83 |
{ errno = ENOSYS; return -1; } |
| 84 |
inline int pipe2(int [], int ) |
| 85 |
{ errno = ENOSYS; return -1; } |
| 86 |
} |
| 87 |
QT_END_NAMESPACE |
| 88 |
using namespace QT_PREPEND_NAMESPACE(QtLibcSupplement); |
| 89 |
|
| 90 |
#else |
| 91 |
# define QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC 0 |
| 92 |
#endif |
| 93 |
|
| 94 |
#define EINTR_LOOP(var, cmd) \ |
| 95 |
do { \ |
| 96 |
var = cmd; \ |
| 97 |
} while (var == -1 && errno == EINTR) |
| 98 |
|
| 99 |
QT_BEGIN_NAMESPACE |
| 100 |
|
| 101 |
// Internal operator functions for timevals |
| 102 |
inline timeval &normalizedTimeval(timeval &t) |
| 103 |
{ |
| 104 |
while (t.tv_usec > 1000000l) { |
| 105 |
++t.tv_sec; |
| 106 |
t.tv_usec -= 1000000l; |
| 107 |
} |
| 108 |
while (t.tv_usec < 0l) { |
| 109 |
--t.tv_sec; |
| 110 |
t.tv_usec += 1000000l; |
| 111 |
} |
| 112 |
return t; |
| 113 |
} |
| 114 |
inline bool operator<(const timeval &t1, const timeval &t2) |
| 115 |
{ return t1.tv_sec < t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_usec < t2.tv_usec); } |
| 116 |
inline bool operator==(const timeval &t1, const timeval &t2) |
| 117 |
{ return t1.tv_sec == t2.tv_sec && t1.tv_usec == t2.tv_usec; } |
| 118 |
inline timeval &operator+=(timeval &t1, const timeval &t2) |
| 119 |
{ |
| 120 |
t1.tv_sec += t2.tv_sec; |
| 121 |
t1.tv_usec += t2.tv_usec; |
| 122 |
return normalizedTimeval(t1); |
| 123 |
} |
| 124 |
inline timeval operator+(const timeval &t1, const timeval &t2) |
| 125 |
{ |
| 126 |
timeval tmp; |
| 127 |
tmp.tv_sec = t1.tv_sec + t2.tv_sec; |
| 128 |
tmp.tv_usec = t1.tv_usec + t2.tv_usec; |
| 129 |
return normalizedTimeval(tmp); |
| 130 |
} |
| 131 |
inline timeval operator-(const timeval &t1, const timeval &t2) |
| 132 |
{ |
| 133 |
timeval tmp; |
| 134 |
tmp.tv_sec = t1.tv_sec - (t2.tv_sec - 1); |
| 135 |
tmp.tv_usec = t1.tv_usec - (t2.tv_usec + 1000000); |
| 136 |
return normalizedTimeval(tmp); |
| 137 |
} |
| 138 |
inline timeval operator*(const timeval &t1, int mul) |
| 139 |
{ |
| 140 |
timeval tmp; |
| 141 |
tmp.tv_sec = t1.tv_sec * mul; |
| 142 |
tmp.tv_usec = t1.tv_usec * mul; |
| 143 |
return normalizedTimeval(tmp); |
| 144 |
} |
| 145 |
|
| 146 |
// don't call QT_OPEN or ::open |
| 147 |
// call qt_safe_open |
| 148 |
static inline int qt_safe_open(const char *pathname, int flags, mode_t mode = 0777) |
| 149 |
{ |
| 150 |
#ifdef O_CLOEXEC |
| 151 |
flags |= O_CLOEXEC; |
| 152 |
#endif |
| 153 |
register int fd; |
| 154 |
EINTR_LOOP(fd, QT_OPEN(pathname, flags, mode)); |
| 155 |
|
| 156 |
// unknown flags are ignored, so we have no way of verifying if |
| 157 |
// O_CLOEXEC was accepted |
| 158 |
if (fd != -1) |
| 159 |
::fcntl(fd, F_SETFD, FD_CLOEXEC); |
| 160 |
return fd; |
| 161 |
} |
| 162 |
#undef QT_OPEN |
| 163 |
#define QT_OPEN qt_safe_open |
| 164 |
|
| 165 |
#ifndef Q_OS_VXWORKS // no POSIX pipes in VxWorks |
| 166 |
// don't call ::pipe |
| 167 |
// call qt_safe_pipe |
| 168 |
static inline int qt_safe_pipe(int pipefd[2], int flags = 0) |
| 169 |
{ |
| 170 |
#ifdef O_CLOEXEC |
| 171 |
Q_ASSERT((flags & ~(O_CLOEXEC | O_NONBLOCK)) == 0); |
| 172 |
#else |
| 173 |
Q_ASSERT((flags & ~O_NONBLOCK) == 0); |
| 174 |
#endif |
| 175 |
|
| 176 |
register int ret; |
| 177 |
#if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC && defined(O_CLOEXEC) |
| 178 |
// use pipe2 |
| 179 |
flags |= O_CLOEXEC; |
| 180 |
ret = ::pipe2(pipefd, flags); // pipe2 is Linux-specific and is documented not to return EINTR |
| 181 |
if (ret == 0 || errno != ENOSYS) |
| 182 |
return ret; |
| 183 |
#endif |
| 184 |
|
| 185 |
ret = ::pipe(pipefd); |
| 186 |
if (ret == -1) |
| 187 |
return -1; |
| 188 |
|
| 189 |
::fcntl(pipefd[0], F_SETFD, FD_CLOEXEC); |
| 190 |
::fcntl(pipefd[1], F_SETFD, FD_CLOEXEC); |
| 191 |
|
| 192 |
// set non-block too? |
| 193 |
if (flags & O_NONBLOCK) { |
| 194 |
::fcntl(pipefd[0], F_SETFL, ::fcntl(pipefd[0], F_GETFL) | O_NONBLOCK); |
| 195 |
::fcntl(pipefd[1], F_SETFL, ::fcntl(pipefd[1], F_GETFL) | O_NONBLOCK); |
| 196 |
} |
| 197 |
|
| 198 |
return 0; |
| 199 |
} |
| 200 |
|
| 201 |
#endif // Q_OS_VXWORKS |
| 202 |
|
| 203 |
// don't call dup or fcntl(F_DUPFD) |
| 204 |
static inline int qt_safe_dup(int oldfd, int atleast = 0, int flags = FD_CLOEXEC) |
| 205 |
{ |
| 206 |
Q_ASSERT(flags == FD_CLOEXEC || flags == 0); |
| 207 |
|
| 208 |
register int ret; |
| 209 |
#ifdef F_DUPFD_CLOEXEC |
| 210 |
// use this fcntl |
| 211 |
if (flags & FD_CLOEXEC) { |
| 212 |
ret = ::fcntl(oldfd, F_DUPFD_CLOEXEC, atleast); |
| 213 |
if (ret != -1 || errno != EINVAL) |
| 214 |
return ret; |
| 215 |
} |
| 216 |
#endif |
| 217 |
|
| 218 |
// use F_DUPFD |
| 219 |
ret = ::fcntl(oldfd, F_DUPFD, atleast); |
| 220 |
|
| 221 |
if (flags && ret != -1) |
| 222 |
::fcntl(ret, F_SETFD, flags); |
| 223 |
return ret; |
| 224 |
} |
| 225 |
|
| 226 |
// don't call dup2 |
| 227 |
// call qt_safe_dup2 |
| 228 |
static inline int qt_safe_dup2(int oldfd, int newfd, int flags = FD_CLOEXEC) |
| 229 |
{ |
| 230 |
Q_ASSERT(flags == FD_CLOEXEC || flags == 0); |
| 231 |
|
| 232 |
register int ret; |
| 233 |
#if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC && defined(O_CLOEXEC) |
| 234 |
// use dup3 |
| 235 |
if (flags & FD_CLOEXEC) { |
| 236 |
EINTR_LOOP(ret, ::dup3(oldfd, newfd, O_CLOEXEC)); |
| 237 |
if (ret == 0 || errno != ENOSYS) |
| 238 |
return ret; |
| 239 |
} |
| 240 |
#endif |
| 241 |
EINTR_LOOP(ret, ::dup2(oldfd, newfd)); |
| 242 |
if (ret == -1) |
| 243 |
return -1; |
| 244 |
|
| 245 |
if (flags) |
| 246 |
::fcntl(newfd, F_SETFD, flags); |
| 247 |
return 0; |
| 248 |
} |
| 249 |
|
| 250 |
static inline qint64 qt_safe_read(int fd, void *data, qint64 maxlen) |
| 251 |
{ |
| 252 |
qint64 ret = 0; |
| 253 |
EINTR_LOOP(ret, QT_READ(fd, data, maxlen)); |
| 254 |
return ret; |
| 255 |
} |
| 256 |
#undef QT_READ |
| 257 |
#define QT_READ qt_safe_read |
| 258 |
|
| 259 |
static inline qint64 qt_safe_write(int fd, const void *data, qint64 len) |
| 260 |
{ |
| 261 |
qint64 ret = 0; |
| 262 |
EINTR_LOOP(ret, QT_WRITE(fd, data, len)); |
| 263 |
return ret; |
| 264 |
} |
| 265 |
#undef QT_WRITE |
| 266 |
#define QT_WRITE qt_safe_write |
| 267 |
|
| 268 |
static inline int qt_safe_close(int fd) |
| 269 |
{ |
| 270 |
register int ret; |
| 271 |
EINTR_LOOP(ret, QT_CLOSE(fd)); |
| 272 |
return ret; |
| 273 |
} |
| 274 |
#undef QT_CLOSE |
| 275 |
#define QT_CLOSE qt_safe_close |
| 276 |
|
| 277 |
// - Open C does not (yet?) implement these on Symbian OS |
| 278 |
// - VxWorks doesn't have processes |
| 279 |
#if !defined(Q_OS_SYMBIAN) && !defined(Q_OS_VXWORKS) |
| 280 |
static inline int qt_safe_execve(const char *filename, char *const argv[], |
| 281 |
char *const envp[]) |
| 282 |
{ |
| 283 |
register int ret; |
| 284 |
EINTR_LOOP(ret, ::execve(filename, argv, envp)); |
| 285 |
return ret; |
| 286 |
} |
| 287 |
|
| 288 |
static inline int qt_safe_execv(const char *path, char *const argv[]) |
| 289 |
{ |
| 290 |
register int ret; |
| 291 |
EINTR_LOOP(ret, ::execv(path, argv)); |
| 292 |
return ret; |
| 293 |
} |
| 294 |
|
| 295 |
static inline int qt_safe_execvp(const char *file, char *const argv[]) |
| 296 |
{ |
| 297 |
register int ret; |
| 298 |
EINTR_LOOP(ret, ::execvp(file, argv)); |
| 299 |
return ret; |
| 300 |
} |
| 301 |
#endif |
| 302 |
|
| 303 |
#ifndef Q_OS_VXWORKS // no processes on VxWorks |
| 304 |
static inline pid_t qt_safe_waitpid(pid_t pid, int *status, int options) |
| 305 |
{ |
| 306 |
register int ret; |
| 307 |
EINTR_LOOP(ret, ::waitpid(pid, status, options)); |
| 308 |
return ret; |
| 309 |
} |
| 310 |
|
| 311 |
#endif // Q_OS_VXWORKS |
| 312 |
|
| 313 |
#if !defined(_POSIX_MONOTONIC_CLOCK) |
| 314 |
# define _POSIX_MONOTONIC_CLOCK -1 |
| 315 |
#endif |
| 316 |
|
| 317 |
timeval qt_gettime(); // in qelapsedtimer_mac.cpp or qtimestamp_unix.cpp |
| 318 |
|
| 319 |
Q_CORE_EXPORT int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept, |
| 320 |
const struct timeval *tv); |
| 321 |
|
| 322 |
// according to X/OPEN we have to define semun ourselves |
| 323 |
// we use prefix as on some systems sem.h will have it |
| 324 |
struct semid_ds; |
| 325 |
union qt_semun { |
| 326 |
int val; /* value for SETVAL */ |
| 327 |
struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ |
| 328 |
unsigned short *array; /* array for GETALL, SETALL */ |
| 329 |
}; |
| 330 |
|
| 331 |
QT_END_NAMESPACE |
| 332 |
|
| 333 |
#endif |