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