Passenger: FileDescriptor.h Source File

- Main Page
- Modules
- Namespaces
- Classes
- Files

- File List

# FileDescriptor.h

    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_ */