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 <boost/make_shared.hpp> 00030 #include <oxt/system_calls.hpp> 00031 00032 #include <utility> 00033 #include <unistd.h> 00034 #include <cerrno> 00035 00036 #include <Exceptions.h> 00037 00038 namespace Passenger { 00039 00040 using namespace std; 00041 using namespace boost; 00042 using namespace oxt; 00043 00044 00045 void safelyClose(int fd); 00046 00047 00048 /** 00049 * Wrapper class around a file descriptor integer, for RAII behavior. 00050 * 00051 * A FileDescriptor object behaves just like an int, so that you can pass it to 00052 * system calls such as read(). It performs reference counting. When the last 00053 * copy of a FileDescriptor has been destroyed, the underlying file descriptor 00054 * will be automatically closed. In this case, any close() system call errors 00055 * are silently ignored. If you are interested in whether the close() system 00056 * call succeeded, then you should call FileDescriptor::close(). 00057 * 00058 * This class is *not* thread-safe. It is safe to call system calls on the 00059 * underlying file descriptor from multiple threads, but it's not safe to 00060 * call FileDescriptor::close() from multiple threads if all those 00061 * FileDescriptor objects point to the same underlying file descriptor. 00062 */ 00063 class FileDescriptor { 00064 private: 00065 struct SharedData { 00066 int fd; 00067 00068 SharedData(int fd) { 00069 this->fd = fd; 00070 } 00071 00072 ~SharedData() { 00073 if (fd >= 0) { 00074 this_thread::disable_syscall_interruption dsi; 00075 syscalls::close(fd); 00076 } 00077 } 00078 00079 void close(bool checkErrors = true) { 00080 if (fd >= 0) { 00081 this_thread::disable_syscall_interruption dsi; 00082 int theFd = fd; 00083 fd = -1; 00084 if (checkErrors) { 00085 safelyClose(theFd); 00086 } else { 00087 syscalls::close(fd); 00088 } 00089 } 00090 } 00091 00092 void detach() { 00093 fd = -1; 00094 } 00095 }; 00096 00097 /** Shared pointer for reference counting on this file descriptor */ 00098 shared_ptr<SharedData> data; 00099 00100 public: 00101 /** 00102 * Creates a new empty FileDescriptor instance that has no underlying 00103 * file descriptor. 00104 * 00105 * @post *this == -1 00106 */ 00107 FileDescriptor() { } 00108 00109 /** 00110 * Creates a new FileDescriptor instance with the given fd as a handle. 00111 * 00112 * @post *this == fd 00113 */ 00114 FileDescriptor(int fd) { 00115 if (fd >= 0) { 00116 /* Make sure that the 'new' operator doesn't overwrite 00117 * errno so that we can write code like this: 00118 * 00119 * FileDescriptor fd = open(...); 00120 * if (fd == -1) { 00121 * print_error(errno); 00122 * } 00123 */ 00124 int e = errno; 00125 data = make_shared<SharedData>(fd); 00126 errno = e; 00127 } 00128 } 00129 00130 /** 00131 * Close the underlying file descriptor. If it was already closed, then 00132 * nothing will happen. If there are multiple copies of this FileDescriptor 00133 * then the underlying file descriptor will be closed for every one of them. 00134 * 00135 * @params checkErrors Whether a SystemException should be thrown in case 00136 * closing the file descriptor fails. If false, errors 00137 * are silently ignored. 00138 * @throws SystemException Something went wrong while closing 00139 * the file descriptor. Only thrown if 00140 * checkErrors is true. 00141 * @post *this == -1 00142 */ 00143 void close(bool checkErrors = true) { 00144 if (data != NULL) { 00145 data->close(checkErrors); 00146 data.reset(); 00147 } 00148 } 00149 00150 /** 00151 * Detach from the underlying file descriptor without closing it. 00152 * This FileDescriptor and all copies will no longer affect the 00153 * underlying file descriptors. 00154 * 00155 * @return The underlying file descriptor, or -1 if already closed. 00156 * @post *this == -1 00157 */ 00158 int detach() { 00159 if (data != NULL) { 00160 int fd = data->fd; 00161 data->detach(); 00162 data.reset(); 00163 return fd; 00164 } else { 00165 return -1; 00166 } 00167 } 00168 00169 /** 00170 * Overloads the integer cast operator so that it will return the underlying 00171 * file descriptor handle as an integer. 00172 * 00173 * Returns -1 if FileDescriptor::close() was called. 00174 */ 00175 operator int () const { 00176 if (data == NULL) { 00177 return -1; 00178 } else { 00179 return data->fd; 00180 } 00181 } 00182 00183 FileDescriptor &operator=(int fd) { 00184 /* Make sure that the 'new' and 'delete' operators don't 00185 * overwrite errno so that we can write code like this: 00186 * 00187 * FileDescriptor fd; 00188 * fd = open(...); 00189 * if (fd == -1) { 00190 * print_error(errno); 00191 * } 00192 */ 00193 int e = errno; 00194 if (fd >= 0) { 00195 data = make_shared<SharedData>(fd); 00196 } else { 00197 data.reset(); 00198 } 00199 errno = e; 00200 return *this; 00201 } 00202 00203 FileDescriptor &operator=(const FileDescriptor &other) { 00204 /* Make sure that the 'delete' operator implicitly invoked by 00205 * shared_ptr doesn't overwrite errno so that we can write code 00206 * like this: 00207 * 00208 * FileDescriptor fd; 00209 * fd = other_file_descriptor_object; 00210 * if (fd == -1) { 00211 * print_error(errno); 00212 * } 00213 */ 00214 int e = errno; 00215 data = other.data; 00216 errno = e; 00217 return *this; 00218 } 00219 }; 00220 00221 /** 00222 * A structure containing two FileDescriptor objects. Behaves like a pair 00223 * and like a two-element array. 00224 */ 00225 class FileDescriptorPair: public pair<FileDescriptor, FileDescriptor> { 00226 public: 00227 FileDescriptorPair() { } 00228 00229 FileDescriptorPair(const FileDescriptor &a, const FileDescriptor &b) 00230 : pair<FileDescriptor, FileDescriptor>(a, b) 00231 { } 00232 00233 FileDescriptor &operator[](int index) { 00234 if (index == 0) { 00235 return first; 00236 } else if (index == 1) { 00237 return second; 00238 } else { 00239 throw ArgumentException("Index must be either 0 of 1"); 00240 } 00241 } 00242 }; 00243 00244 // Convenience aliases. 00245 typedef FileDescriptorPair Pipe; 00246 typedef FileDescriptorPair SocketPair; 00247 00248 /** 00249 * A synchronization mechanism that's implemented with file descriptors, 00250 * and as such can be used in combination with select() and friends. 00251 * 00252 * One can wait for an event on an EventFd by select()ing it on read events. 00253 * Another thread can signal the EventFd by calling notify(). 00254 */ 00255 class EventFd { 00256 private: 00257 int reader; 00258 int writer; 00259 00260 public: 00261 EventFd() { 00262 int fds[2]; 00263 00264 if (syscalls::pipe(fds) == -1) { 00265 int e = errno; 00266 throw SystemException("Cannot create a pipe", e); 00267 } 00268 reader = fds[0]; 00269 writer = fds[1]; 00270 } 00271 00272 ~EventFd() { 00273 this_thread::disable_syscall_interruption dsi; 00274 syscalls::close(reader); 00275 syscalls::close(writer); 00276 } 00277 00278 void notify() { 00279 ssize_t ret = syscalls::write(writer, "x", 1); 00280 if (ret == -1 && errno != EAGAIN) { 00281 int e = errno; 00282 throw SystemException("Cannot write notification data", e); 00283 } 00284 } 00285 00286 int fd() const { 00287 return reader; 00288 } 00289 }; 00290 00291 } // namespace Passenger 00292 00293 #endif /* _PASSENGER_FILE_DESCRIPTOR_H_ */