System.h

00001 /*
00002  *  Phusion Passenger - http://www.modrails.com/
00003  *  Copyright (C) 2008  Phusion
00004  *
00005  *  Phusion Passenger is a trademark of Hongli Lai & Ninh Bui.
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; version 2 of the License.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License along
00017  *  with this program; if not, write to the Free Software Foundation, Inc.,
00018  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00019  */
00020 #ifndef _PASSENGER_SYSTEM_H_
00021 #define _PASSENGER_SYSTEM_H_
00022 
00023 #include <boost/thread.hpp>
00024 #include <boost/date_time/posix_time/posix_time_types.hpp>
00025 #include <sys/types.h>
00026 #include <sys/wait.h>
00027 #include <sys/socket.h>
00028 #include <pthread.h>
00029 #include <unistd.h>
00030 #include <signal.h>
00031 #include <cstdio>
00032 #include <ctime>
00033 #include <cassert>
00034 
00035 /**
00036  * Support for interruption of blocking system calls and C library calls.
00037  *
00038  * This file provides a framework for writing multithreading code that can
00039  * be interrupted, even when blocked on system calls or C library calls.
00040  *
00041  * One must first call Passenger::setupSysCallInterruptionSupport().
00042  * Then one may use the functions in Passenger::InterruptableCalls
00043  * as drop-in replacements for system calls or C library functions.
00044  * Thread::interrupt() and Thread::interruptAndJoin() should be used
00045  * for interrupting threads.
00046  *
00047  * By default, interruptions are caught.
00048  */
00049 
00050 // This is one of the things that Java is good at and C++ sucks at. Sigh...
00051 
00052 namespace Passenger {
00053 
00054         using namespace boost;
00055         
00056         static const int INTERRUPTION_SIGNAL = SIGINT;
00057         
00058         /**
00059          * Setup system call interruption support.
00060          * This function may only be called once. It installs a signal handler
00061          * for INTERRUPTION_SIGNAL, so one should not install a different signal
00062          * handler for that signal after calling this function.
00063          */
00064         void setupSyscallInterruptionSupport();
00065         
00066         /**
00067          * Thread class with system call interruption support.
00068          */
00069         class Thread: public thread {
00070         public:
00071                 template <class F>
00072                 explicit Thread(F f, unsigned int stackSize = 0)
00073                         : thread(f, stackSize) {}
00074                 
00075                 /**
00076                  * Interrupt the thread. This method behaves just like
00077                  * boost::thread::interrupt(), but will also respect the interruption
00078                  * points defined in Passenger::InterruptableCalls.
00079                  *
00080                  * Note that an interruption request may get lost, depending on the
00081                  * current execution point of the thread. Thus, one should call this
00082                  * method in a loop, until a certain goal condition has been fulfilled.
00083                  * interruptAndJoin() is a convenience method that implements this
00084                  * pattern.
00085                  */
00086                 void interrupt() {
00087                         int ret;
00088                         
00089                         thread::interrupt();
00090                         do {
00091                                 ret = pthread_kill(native_handle(),
00092                                         INTERRUPTION_SIGNAL);
00093                         } while (ret == EINTR);
00094                 }
00095                 
00096                 /**
00097                  * Keep interrupting the thread until it's done, then join it.
00098                  *
00099                  * @throws boost::thread_interrupted
00100                  */
00101                 void interruptAndJoin() {
00102                         bool done = false;
00103                         while (!done) {
00104                                 interrupt();
00105                                 done = timed_join(posix_time::millisec(10));
00106                         }
00107                 }
00108         };
00109         
00110         /**
00111          * System call and C library call wrappers with interruption support.
00112          * These functions are interruption points, i.e. they throw boost::thread_interrupted
00113          * whenever the calling thread is interrupted by Thread::interrupt() or
00114          * Thread::interruptAndJoin().
00115          */
00116         namespace InterruptableCalls {
00117                 ssize_t read(int fd, void *buf, size_t count);
00118                 ssize_t write(int fd, const void *buf, size_t count);
00119                 int close(int fd);
00120                 
00121                 int socketpair(int d, int type, int protocol, int sv[2]);
00122                 ssize_t recvmsg(int s, struct msghdr *msg, int flags);
00123                 ssize_t sendmsg(int s, const struct msghdr *msg, int flags);
00124                 int shutdown(int s, int how);
00125                 
00126                 FILE *fopen(const char *path, const char *mode);
00127                 int fclose(FILE *fp);
00128                 
00129                 time_t time(time_t *t);
00130                 int usleep(useconds_t usec);
00131                 int nanosleep(const struct timespec *req, struct timespec *rem);
00132                 
00133                 pid_t fork();
00134                 int kill(pid_t pid, int sig);
00135                 pid_t waitpid(pid_t pid, int *status, int options);
00136         }
00137 
00138 } // namespace Passenger
00139 
00140 namespace boost {
00141 namespace this_thread {
00142 
00143         /**
00144          * @intern
00145          */
00146         extern thread_specific_ptr<bool> _syscalls_interruptable;
00147         
00148         /**
00149          * Check whether system calls should be interruptable in
00150          * the calling thread.
00151          */
00152         bool syscalls_interruptable();
00153         
00154         class restore_syscall_interruption;
00155 
00156         /**
00157          * Create this struct on the stack to temporarily enable system
00158          * call interruption, until the object goes out of scope.
00159          */
00160         class enable_syscall_interruption {
00161         private:
00162                 bool lastValue;
00163         public:
00164                 enable_syscall_interruption() {
00165                         if (_syscalls_interruptable.get() == NULL) {
00166                                 lastValue = true;
00167                                 _syscalls_interruptable.reset(new bool(true));
00168                         } else {
00169                                 lastValue = *_syscalls_interruptable;
00170                                 *_syscalls_interruptable = true;
00171                         }
00172                 }
00173                 
00174                 ~enable_syscall_interruption() {
00175                         *_syscalls_interruptable = lastValue;
00176                 }
00177         };
00178         
00179         /**
00180          * Create this struct on the stack to temporarily disable system
00181          * call interruption, until the object goes out of scope.
00182          * While system call interruption is disabled, the functions in
00183          * InterruptableCalls will try until the return code is not EINTR.
00184          */
00185         class disable_syscall_interruption {
00186         private:
00187                 friend class restore_syscall_interruption;
00188                 bool lastValue;
00189         public:
00190                 disable_syscall_interruption() {
00191                         if (_syscalls_interruptable.get() == NULL) {
00192                                 lastValue = true;
00193                                 _syscalls_interruptable.reset(new bool(false));
00194                         } else {
00195                                 lastValue = *_syscalls_interruptable;
00196                                 *_syscalls_interruptable = false;
00197                         }
00198                 }
00199                 
00200                 ~disable_syscall_interruption() {
00201                         *_syscalls_interruptable = lastValue;
00202                 }
00203         };
00204         
00205         /**
00206          * Creating an object of this class on the stack will restore the
00207          * system call interruption state to what it was before.
00208          */
00209         class restore_syscall_interruption {
00210         private:
00211                 int lastValue;
00212         public:
00213                 restore_syscall_interruption(const disable_syscall_interruption &intr) {
00214                         assert(_syscalls_interruptable.get() != NULL);
00215                         lastValue = *_syscalls_interruptable;
00216                         *_syscalls_interruptable = intr.lastValue;
00217                 }
00218                 
00219                 ~restore_syscall_interruption() {
00220                         *_syscalls_interruptable = lastValue;
00221                 }
00222         };
00223 
00224 } // namespace this_thread
00225 } // namespace boost
00226 
00227 #endif /* _PASSENGER_SYSTEM_H_ */
00228 

Generated on Fri Jan 23 08:28:57 2009 for Passenger by  doxygen 1.4.7