ext/oxt/system_calls.hpp in passenger-3.0.21 vs ext/oxt/system_calls.hpp in passenger-3.9.1.beta
- old
+ new
@@ -1,10 +1,10 @@
/*
* OXT - OS eXtensions for boosT
* Provides important functionality necessary for writing robust server software.
*
- * Copyright (c) 2010 Phusion
+ * Copyright (c) 2010-2012 Phusion
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
@@ -38,34 +38,41 @@
#include <signal.h>
#include <poll.h>
#include <cstdio>
#include <ctime>
#include <cassert>
+#include "macros.hpp"
/**
- * Support for interruption of blocking system calls and C library calls
+ * System call and C library call wrappers with extra features
*
- * This file provides a framework for writing multithreading code that can
- * be interrupted, even when blocked on system calls or C library calls.
+ * This file provides wrappers for many system calls and C library calls
+ * and adds the following features:
*
- * One must first call oxt::setup_syscall_interruption_support().
+ * - Interruption of blocking system calls and blocking C library calls.
+ * - Simulation of random failures.
+ *
+ * ## About system call interruption
+ *
+ * One must first call `oxt::setup_syscall_interruption_support()`.
* Then one may use the functions in oxt::syscalls as drop-in replacements
* for system calls or C library functions. These functions throw
* boost::thread_interrupted upon interruption, instead of returning an EINTR
* error.
*
- * Once setup_syscall_interruption_support() has been called, system call
+ * Once `setup_syscall_interruption_support()` has been called, system call
* interruption is enabled by default. You can enable or disable system call
* interruption in the current scope by creating instances of
* boost::this_thread::enable_syscall_interruption or
* boost::this_thread::disable_syscall_interruption, respectively. When system
* call interruption is disabled, the oxt::syscall wrapper functions will
* ignore interruption requests -- that is, they will never throw
* boost::thread_interrupted, nor will they return EINTR errors. This is similar
* to Boost thread interruption.
*
- * <h2>How to interrupt</h2>
+ * ### How to interrupt
+ *
* Generally, oxt::thread::interrupt() and oxt::thread::interrupt_and_join()
* should be used for interrupting threads. These methods will interrupt
* the thread at all Boost interruption points, as well as system calls that
* are caled through the oxt::syscalls namespace. Do *not* use
* boost::thread::interrupt, because that will not honor system calls as
@@ -87,38 +94,37 @@
* Note that sending a signal once may not interrupt the thread, because
* the thread may not be calling a system call at the time the signal was
* received. So one must keep sending signals periodically until the
* thread has quit.
*
- * @warning
- * After oxt::setup_syscall_interruption_support() is called, sending a signal
+ * **Warning**:
+ *
+ * After `oxt::setup_syscall_interruption_support()` is called, sending a signal
* will cause system calls to return with an EINTR error. The oxt::syscall
* functions will automatically take care of this, but if you're calling any
* system calls without using that namespace, then you should check for and
* take care of EINTR errors.
+ *
+ * ## About random simulation of failures
+ *
+ * Call `oxt::setup_random_failure_simulation()` to initialize random
+ * failure simulation.
*/
// This is one of the things that Java is good at and C++ sucks at. Sigh...
namespace oxt {
static const int INTERRUPTION_SIGNAL = SIGUSR1; // SIGUSR2 is reserved by Valgrind...
- /**
- * Setup system call interruption support.
- * This function may only be called once. It installs a signal handler
- * for INTERRUPTION_SIGNAL, so one should not install a different signal
- * handler for that signal after calling this function. It also resets
- * the process signal mask.
- *
- * @warning
- * After oxt::setup_syscall_interruption_support() is called, sending a signal
- * will cause system calls to return with an EINTR error. The oxt::syscall
- * functions will automatically take care of this, but if you're calling any
- * system calls without using that namespace, then you should check for and
- * take care of EINTR errors.
- */
+ struct ErrorChance {
+ double chance;
+ int errorCode;
+ };
+
void setup_syscall_interruption_support();
+
+ void setup_random_failure_simulation(const ErrorChance *errorChances, unsigned int n);
/**
* System call and C library call wrappers with interruption support.
* These functions are interruption points, i.e. they throw
* boost::thread_interrupted whenever the calling thread is interrupted
@@ -131,10 +137,12 @@
ssize_t write(int fd, const void *buf, size_t count);
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
int close(int fd);
int pipe(int filedes[2]);
int dup2(int filedes, int filedes2);
+ int mkdir(const char *pathname, mode_t mode);
+ int chown(const char *path, uid_t owner, gid_t group);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
int listen(int sockfd, int backlog);
@@ -153,10 +161,11 @@
FILE *fopen(const char *path, const char *mode);
size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);
int fclose(FILE *fp);
int unlink(const char *pathname);
int stat(const char *path, struct stat *buf);
+ int lstat(const char *path, struct stat *buf);
time_t time(time_t *t);
unsigned int sleep(unsigned int seconds);
int usleep(useconds_t usec);
int nanosleep(const struct timespec *req, struct timespec *rem);
@@ -173,12 +182,16 @@
namespace this_thread {
/**
* @intern
*/
- extern thread_specific_ptr<bool> _syscalls_interruptable;
-
+ #ifdef OXT_THREAD_LOCAL_KEYWORD_SUPPORTED
+ extern __thread bool _syscalls_interruptable;
+ #else
+ extern thread_specific_ptr<bool> _syscalls_interruptable;
+ #endif
+
/**
* Check whether system calls should be interruptable in
* the calling thread.
*/
bool syscalls_interruptable();
@@ -192,21 +205,30 @@
class enable_syscall_interruption {
private:
bool last_value;
public:
enable_syscall_interruption() {
- if (_syscalls_interruptable.get() == NULL) {
- last_value = true;
- _syscalls_interruptable.reset(new bool(true));
- } else {
- last_value = *_syscalls_interruptable;
- *_syscalls_interruptable = true;
- }
+ #ifdef OXT_THREAD_LOCAL_KEYWORD_SUPPORTED
+ last_value = _syscalls_interruptable;
+ _syscalls_interruptable = true;
+ #else
+ if (_syscalls_interruptable.get() == NULL) {
+ last_value = true;
+ _syscalls_interruptable.reset(new bool(true));
+ } else {
+ last_value = *_syscalls_interruptable;
+ *_syscalls_interruptable = true;
+ }
+ #endif
}
~enable_syscall_interruption() {
- *_syscalls_interruptable = last_value;
+ #ifdef OXT_THREAD_LOCAL_KEYWORD_SUPPORTED
+ _syscalls_interruptable = last_value;
+ #else
+ *_syscalls_interruptable = last_value;
+ #endif
}
};
/**
* Create this struct on the stack to temporarily disable system
@@ -218,21 +240,30 @@
private:
friend class restore_syscall_interruption;
bool last_value;
public:
disable_syscall_interruption() {
- if (_syscalls_interruptable.get() == NULL) {
- last_value = true;
- _syscalls_interruptable.reset(new bool(false));
- } else {
- last_value = *_syscalls_interruptable;
- *_syscalls_interruptable = false;
- }
+ #ifdef OXT_THREAD_LOCAL_KEYWORD_SUPPORTED
+ last_value = _syscalls_interruptable;
+ _syscalls_interruptable = false;
+ #else
+ if (_syscalls_interruptable.get() == NULL) {
+ last_value = true;
+ _syscalls_interruptable.reset(new bool(false));
+ } else {
+ last_value = *_syscalls_interruptable;
+ *_syscalls_interruptable = false;
+ }
+ #endif
}
~disable_syscall_interruption() {
- *_syscalls_interruptable = last_value;
+ #ifdef OXT_THREAD_LOCAL_KEYWORD_SUPPORTED
+ _syscalls_interruptable = last_value;
+ #else
+ *_syscalls_interruptable = last_value;
+ #endif
}
};
/**
* Creating an object of this class on the stack will restore the
@@ -241,16 +272,25 @@
class restore_syscall_interruption {
private:
int last_value;
public:
restore_syscall_interruption(const disable_syscall_interruption &intr) {
- assert(_syscalls_interruptable.get() != NULL);
- last_value = *_syscalls_interruptable;
- *_syscalls_interruptable = intr.last_value;
+ #ifdef OXT_THREAD_LOCAL_KEYWORD_SUPPORTED
+ last_value = _syscalls_interruptable;
+ _syscalls_interruptable = intr.last_value;
+ #else
+ assert(_syscalls_interruptable.get() != NULL);
+ last_value = *_syscalls_interruptable;
+ *_syscalls_interruptable = intr.last_value;
+ #endif
}
~restore_syscall_interruption() {
- *_syscalls_interruptable = last_value;
+ #ifdef OXT_THREAD_LOCAL_KEYWORD_SUPPORTED
+ _syscalls_interruptable = last_value;
+ #else
+ *_syscalls_interruptable = last_value;
+ #endif
}
};
} // namespace this_thread
} // namespace boost