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 >= 0) { 00069 this_thread::disable_syscall_interruption dsi; 00070 syscalls::close(fd); 00071 } 00072 } 00073 00074 void close() { 00075 if (fd >= 0) { 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 if (fd >= 0) { 00106 /* Make sure that the 'new' operator doesn't overwrite 00107 * errno so that we can write code like this: 00108 * 00109 * FileDescriptor fd = open(...); 00110 * if (fd == -1) { 00111 * print_error(errno); 00112 * } 00113 */ 00114 int e = errno; 00115 data.reset(new SharedData(fd)); 00116 errno = e; 00117 } 00118 } 00119 00120 /** 00121 * Close the underlying file descriptor. If it was already closed, then 00122 * nothing will happen. If there are multiple copies of this FileDescriptor 00123 * then the underlying file descriptor will be closed for every one of them. 00124 * 00125 * @throws SystemException Something went wrong while closing 00126 * the file descriptor. 00127 * @post *this == -1 00128 */ 00129 void close() { 00130 if (data != NULL) { 00131 data->close(); 00132 data.reset(); 00133 } 00134 } 00135 00136 /** 00137 * Overloads the integer cast operator so that it will return the underlying 00138 * file descriptor handle as an integer. 00139 * 00140 * Returns -1 if FileDescriptor::close() was called. 00141 */ 00142 operator int () const { 00143 if (data == NULL) { 00144 return -1; 00145 } else { 00146 return data->fd; 00147 } 00148 } 00149 00150 FileDescriptor &operator=(int fd) { 00151 /* Make sure that the 'new' and 'delete' operators don't 00152 * overwrite errno so that we can write code like this: 00153 * 00154 * FileDescriptor fd; 00155 * fd = open(...); 00156 * if (fd == -1) { 00157 * print_error(errno); 00158 * } 00159 */ 00160 int e = errno; 00161 if (fd >= 0) { 00162 data.reset(new SharedData(fd)); 00163 } else { 00164 data.reset(); 00165 } 00166 errno = e; 00167 return *this; 00168 } 00169 00170 FileDescriptor &operator=(const FileDescriptor &other) { 00171 /* Make sure that the 'delete' operator implicitly invoked by 00172 * shared_ptr doesn't overwrite errno so that we can write code 00173 * like this: 00174 * 00175 * FileDescriptor fd; 00176 * fd = other_file_descriptor_object; 00177 * if (fd == -1) { 00178 * print_error(errno); 00179 * } 00180 */ 00181 int e = errno; 00182 data = other.data; 00183 errno = e; 00184 return *this; 00185 } 00186 }; 00187 00188 /** 00189 * A synchronization mechanism that's implemented with file descriptors, 00190 * and as such can be used in combination with select() and friends. 00191 * 00192 * One can wait for an event on an EventFd by select()ing it on read events. 00193 * Another thread can signal the EventFd by calling notify(). 00194 */ 00195 class EventFd { 00196 private: 00197 int reader; 00198 int writer; 00199 00200 public: 00201 EventFd() { 00202 int fds[2]; 00203 00204 if (syscalls::pipe(fds) == -1) { 00205 int e = errno; 00206 throw SystemException("Cannot create a pipe", e); 00207 } 00208 reader = fds[0]; 00209 writer = fds[1]; 00210 } 00211 00212 ~EventFd() { 00213 this_thread::disable_syscall_interruption dsi; 00214 syscalls::close(reader); 00215 syscalls::close(writer); 00216 } 00217 00218 void notify() { 00219 MessageChannel(writer).writeRaw("x", 1); 00220 } 00221 00222 int fd() const { 00223 return reader; 00224 } 00225 }; 00226 00227 } // namespace Passenger 00228 00229 #endif /* _PASSENGER_FILE_DESCRIPTOR_H_ */