LogCabin
|
00001 /* Copyright (c) 2011-2014 Stanford University 00002 * Copyright (c) 2014-2015 Diego Ongaro 00003 * 00004 * Permission to use, copy, modify, and distribute this software for any 00005 * purpose with or without fee is hereby granted, provided that the above 00006 * copyright notice and this permission notice appear in all copies. 00007 * 00008 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES 00009 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 00010 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR 00011 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 00012 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 00013 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 00014 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 00015 */ 00016 00017 #include <mutex> 00018 00019 #ifndef LOGCABIN_EVENT_FILE_H 00020 #define LOGCABIN_EVENT_FILE_H 00021 00022 namespace LogCabin { 00023 namespace Event { 00024 00025 // forward declaration 00026 class Loop; 00027 00028 /** 00029 * A File is called by the Event::Loop when a file becomes readable or 00030 * writable. The client should inherit from this and implement the 00031 * handleFileEvent() method for when the file becomes readable or writable. 00032 * 00033 * File objects can be created from any thread, but they will always fire on 00034 * the thread running the Event::Loop. 00035 */ 00036 class File { 00037 public: 00038 00039 /** 00040 * Registers a File handler to be monitored by the Event::Loop. Once this 00041 * is constructed, the Event::Loop will call the File's event handler 00042 * appropriately. 00043 * 00044 * This object must be destroyed or disableForever() called BEFORE the File 00045 * object can be destroyed safely. 00046 * 00047 * Details: That Monitor objects have distinct lifetimes from File objects 00048 * is the key reason why they exist. The registration functionality 00049 * used to be integrated in File itself, but that posed a problem on 00050 * destruction. Suppose class MyFile derives from File. ~File() is called 00051 * after MyFile::handleFileEvent() is no longer safe to call (since MyFile 00052 * members are already destroyed). So ~File() is too late to block the 00053 * Event::Loop; it needs to happen before all this. See also 00054 * https://github.com/logcabin/logcabin/issues/82 00055 */ 00056 class Monitor { 00057 public: 00058 /** 00059 * Constructor; begins monitoring events on a file. 00060 * \param eventLoop 00061 * Event::Loop that will monitor the File object. 00062 * \param file 00063 * The file to monitor for events. 00064 * \param fileEvents 00065 * The files handler will be invoked when any of the events 00066 * specified by this parameter occur (OR-ed combination of 00067 * EPOLL_EVENTS values). If this is 0 then the file handler starts 00068 * off inactive; it will not trigger until setEvents() has been 00069 * called (except possibly for errors such as EPOLLHUP; these 00070 * events are always active). 00071 */ 00072 Monitor(Event::Loop& eventLoop, File& file, uint32_t fileEvents); 00073 00074 /** 00075 * Destructor; disables monitoring the file. See disableForever(). 00076 */ 00077 virtual ~Monitor(); 00078 00079 /** 00080 * Stop monitoring this file. To guarantee that the event loop thread 00081 * is no longer operating on the File, this method takes an 00082 * Event::Loop::Lock internally. Once this returns, it is safe to 00083 * destroy the File object, and it is guaranteed that the event loop 00084 * thread is no longer operating on the File (unless the caller is 00085 * running in the context of the File's event handler). 00086 */ 00087 void disableForever(); 00088 00089 /** 00090 * Specify the events of interest for the file. 00091 * This method is safe to call concurrently with file events 00092 * triggering and disableForever. If called outside an event handler 00093 * and no Event::Loop::Lock is taken, this may have a short delay while 00094 * active handlers continue to be called. 00095 * \param events 00096 * Indicates the conditions under which this object should be 00097 * invoked (OR-ed combination of EPOLL_EVENTS values). If this is 00098 * 0 then the file handler is set to inactive; it will not trigger 00099 * until setEvents() has been called (except possibly for errors 00100 * such as EPOLLHUP; these events are always active). 00101 */ 00102 void setEvents(uint32_t events); 00103 00104 /** 00105 * Event::Loop that will monitor the file. 00106 */ 00107 Event::Loop& eventLoop; 00108 00109 private: 00110 /** 00111 * Protects #file from concurrent access/modification. 00112 */ 00113 std::mutex mutex; 00114 00115 /** 00116 * Pointer to file being monitored, or NULL if disableForever() has 00117 * been called. 00118 */ 00119 File* file; 00120 00121 // Monitor is not copyable. 00122 Monitor(const Monitor&) = delete; 00123 Monitor& operator=(const Monitor&) = delete; 00124 }; 00125 00126 /** 00127 * Specifies who is in charge of closing the file descriptor. 00128 */ 00129 enum Ownership { 00130 /** 00131 * The File destructor will close() fd. 00132 */ 00133 CLOSE_ON_DESTROY, 00134 /** 00135 * The caller will be in charge of closing fd. The File destructor will 00136 * not close() fd. 00137 */ 00138 CALLER_CLOSES_FD, 00139 }; 00140 00141 /** 00142 * Construct a file event handler. After this is constructed, you'll want 00143 * to create an Event::File::Monitor for it. 00144 * \param fd 00145 * A file descriptor of a valid open file to monitor. Unless release() 00146 * is called first, this File object will close the file descriptor 00147 * when it is destroyed. 00148 * \param ownership 00149 * Specifies who is in charge of closing fd. Default: this class will 00150 * close fd in the destructor. 00151 */ 00152 explicit File(int fd, Ownership ownership = CLOSE_ON_DESTROY); 00153 00154 /** 00155 * Destructor. Closes the file descriptor if ownership is set to 00156 * CLOSE_ON_DESTROY. 00157 */ 00158 virtual ~File(); 00159 00160 /** 00161 * This method is overridden by a subclass and invoked when a file event 00162 * occurs. This method will be invoked by the main event loop on 00163 * whatever thread is running the Event::Loop. 00164 * 00165 * If the event still exists when this method returns (e.g., the file is 00166 * readable but the method did not read the data), then the method will be 00167 * invoked again (unless flags such as EPOLLONESHOT or EPOLLET are used). 00168 * 00169 * \param events 00170 * Indicates whether the file is readable or writable or both (OR'ed 00171 * combination of EPOLL_EVENTS values). 00172 */ 00173 virtual void handleFileEvent(uint32_t events) = 0; 00174 00175 /** 00176 * The file descriptor to monitor. 00177 */ 00178 const int fd; 00179 00180 /** 00181 * See Ownership. 00182 */ 00183 const Ownership ownership; 00184 00185 // File is not copyable. 00186 File(const File&) = delete; 00187 File& operator=(const File&) = delete; 00188 }; 00189 00190 } // namespace LogCabin::Event 00191 } // namespace LogCabin 00192 00193 #endif /* LOGCABIN_EVENT_FILE_H */