00001 /* 00002 * Phusion Passenger - http://www.modrails.com/ 00003 * Copyright (c) 2010 Phusion 00004 * 00005 * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui. 00006 * 00007 * Permission is hereby granted, free of charge, to any person obtaining a copy 00008 * of this software and associated documentation files (the "Software"), to deal 00009 * in the Software without restriction, including without limitation the rights 00010 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00011 * copies of the Software, and to permit persons to whom the Software is 00012 * furnished to do so, subject to the following conditions: 00013 * 00014 * The above copyright notice and this permission notice shall be included in 00015 * all copies or substantial portions of the Software. 00016 * 00017 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00018 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00019 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00020 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00021 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00022 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00023 * THE SOFTWARE. 00024 */ 00025 #ifndef _PASSENGER_FILE_DESCRIPTOR_H_ 00026 #define _PASSENGER_FILE_DESCRIPTOR_H_ 00027 00028 #include <boost/shared_ptr.hpp> 00029 #include <oxt/system_calls.hpp> 00030 00031 #include <unistd.h> 00032 #include <cerrno> 00033 00034 #include "MessageChannel.h" 00035 #include "Exceptions.h" 00036 00037 namespace Passenger { 00038 00039 using namespace boost; 00040 using namespace oxt; 00041 00042 00043 /** 00044 * Wrapper class around a file descriptor integer, for RAII behavior. 00045 * 00046 * A FileDescriptor object behaves just like an int, so that you can pass it to 00047 * system calls such as read(). It performs reference counting. When the last 00048 * copy of a FileDescriptor has been destroyed, the underlying file descriptor 00049 * will be automatically closed. In this case, any close() system call errors 00050 * are silently ignored. If you are interested in whether the close() system 00051 * call succeeded, then you should call FileDescriptor::close(). 00052 * 00053 * This class is *not* thread-safe. It is safe to call system calls on the 00054 * underlying file descriptor from multiple threads, but it's not safe to 00055 * call FileDescriptor::close() from multiple threads if all those 00056 * FileDescriptor objects point to the same underlying file descriptor. 00057 */ 00058 class FileDescriptor { 00059 private: 00060 struct SharedData { 00061 int fd; 00062 00063 SharedData(int fd) { 00064 this->fd = fd; 00065 } 00066 00067 ~SharedData() { 00068 if (fd != -1) { 00069 this_thread::disable_syscall_interruption dsi; 00070 syscalls::close(fd); 00071 } 00072 } 00073 00074 void close() { 00075 if (fd != -1) { 00076 this_thread::disable_syscall_interruption dsi; 00077 int theFd = fd; 00078 fd = -1; 00079 if (syscalls::close(theFd) == -1 && errno != ENOTCONN) { 00080 int e = errno; 00081 throw SystemException("Cannot close file descriptor", e); 00082 } 00083 } 00084 } 00085 }; 00086 00087 /** Shared pointer for reference counting on this file descriptor */ 00088 shared_ptr<SharedData> data; 00089 00090 public: 00091 /** 00092 * Creates a new empty FileDescriptor instance that has no underlying 00093 * file descriptor. 00094 * 00095 * @post *this == -1 00096 */ 00097 FileDescriptor() { } 00098 00099 /** 00100 * Creates a new FileDescriptor instance with the given fd as a handle. 00101 * 00102 * @post *this == fd 00103 */ 00104 FileDescriptor(int fd) { 00105 data.reset(new SharedData(fd)); 00106 } 00107 00108 /** 00109 * Close the underlying file descriptor. If it was already closed, then 00110 * nothing will happen. 00111 * 00112 * @throws SystemException Something went wrong while closing 00113 * the file descriptor. 00114 * @post *this == -1 00115 */ 00116 void close() { 00117 if (data != NULL) { 00118 data->close(); 00119 } 00120 } 00121 00122 /** 00123 * Overloads the integer cast operator so that it will return the underlying 00124 * file descriptor handle as an integer. 00125 * 00126 * Returns -1 if FileDescriptor::close() was called. 00127 */ 00128 operator int () const { 00129 if (data == NULL) { 00130 return -1; 00131 } else { 00132 return data->fd; 00133 } 00134 } 00135 }; 00136 00137 /** 00138 * A synchronization mechanism that's implemented with file descriptors, 00139 * and as such can be used in combination with select() and friends. 00140 * 00141 * One can wait for an event on an EventFd by select()ing it on read events. 00142 * Another thread can signal the EventFd by calling notify(). 00143 */ 00144 class EventFd { 00145 private: 00146 int reader; 00147 int writer; 00148 00149 public: 00150 EventFd() { 00151 int fds[2]; 00152 00153 if (syscalls::pipe(fds) == -1) { 00154 int e = errno; 00155 throw SystemException("Cannot create a pipe", e); 00156 } 00157 reader = fds[0]; 00158 writer = fds[1]; 00159 } 00160 00161 ~EventFd() { 00162 this_thread::disable_syscall_interruption dsi; 00163 syscalls::close(reader); 00164 syscalls::close(writer); 00165 } 00166 00167 void notify() { 00168 MessageChannel(writer).writeRaw("x", 1); 00169 } 00170 00171 int fd() const { 00172 return reader; 00173 } 00174 }; 00175 00176 } // namespace Passenger 00177 00178 #endif /* _PASSENGER_FILE_DESCRIPTOR_H_ */