/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include namespace folly { class EventBase; /** * The EventHandler class is used to asynchronously wait for events on a file * descriptor. * * Users that wish to wait on I/O events should derive from EventHandler and * implement the handlerReady() method. */ class EventHandler { public: enum EventFlags { NONE = 0, READ = EV_READ, WRITE = EV_WRITE, READ_WRITE = (READ | WRITE), PERSIST = EV_PERSIST, // Temporary flag until EPOLLPRI is upstream on libevent. #ifdef EV_PRI PRI = EV_PRI, #endif }; /** * Create a new EventHandler object. * * @param eventBase The EventBase to use to drive this event handler. * This may be nullptr, in which case the EventBase must be * set separately using initHandler() or attachEventBase() * before the handler can be registered. * @param fd The file descriptor that this EventHandler will * monitor. This may be -1, in which case the file * descriptor must be set separately using initHandler() or * changeHandlerFD() before the handler can be registered. */ explicit EventHandler( EventBase* eventBase = nullptr, NetworkSocket fd = NetworkSocket()); EventHandler(const EventHandler&) = delete; EventHandler& operator=(const EventHandler&) = delete; /** * EventHandler destructor. * * The event will be automatically unregistered if it is still registered. */ virtual ~EventHandler(); /** * handlerReady() is invoked when the handler is ready. * * @param events A bitset indicating the events that are ready. */ virtual void handlerReady(uint16_t events) noexcept = 0; /** * Register the handler. * * If the handler is already registered, the registration will be updated * to wait on the new set of events. * * @param events A bitset specifying the events to monitor. * If the PERSIST bit is set, the handler will remain * registered even after handlerReady() is called. * * @return Returns true if the handler was successfully registered, * or false if an error occurred. After an error, the handler is * always unregistered, even if it was already registered prior to * this call to registerHandler(). */ bool registerHandler(uint16_t events) { return registerImpl(events, false); } /** * Unregister the handler, if it is registered. */ void unregisterHandler(); /** * Returns true if the handler is currently registered. */ bool isHandlerRegistered() const { return event_.isEventRegistered(); } /** * Attach the handler to a EventBase. * * This may only be called if the handler is not currently attached to a * EventBase (either by using the default constructor, or by calling * detachEventBase()). * * This method must be invoked in the EventBase's thread. */ void attachEventBase(EventBase* eventBase); /** * Detach the handler from its EventBase. * * This may only be called when the handler is not currently registered. * Once detached, the handler may not be registered again until it is * re-attached to a EventBase by calling attachEventBase(). * * This method must be called from the current EventBase's thread. */ void detachEventBase(); /** * Change the file descriptor that this handler is associated with. * * This may only be called when the handler is not currently registered. */ void changeHandlerFD(NetworkSocket fd); /** * Attach the handler to a EventBase, and change the file descriptor. * * This method may only be called if the handler is not currently attached to * a EventBase. This is primarily intended to be used to initialize * EventHandler objects created using the default constructor. */ void initHandler(EventBase* eventBase, NetworkSocket fd); /** * Return the set of events that we're currently registered for. */ uint16_t getRegisteredEvents() const { return (isHandlerRegistered()) ? (uint16_t)(event_.eb_ev_events()) : 0u; } /** * Register the handler as an internal event. * * This event will not count as an active event for determining if the * EventBase loop has more events to process. The EventBase loop runs * only as long as there are active EventHandlers, however "internal" event * handlers are not counted. Therefore this event handler will not prevent * EventBase loop from exiting with no more work to do if there are no other * non-internal event handlers registered. * * This is intended to be used only in very rare cases by the internal * EventBase code. This API is not guaranteed to remain stable or portable * in the future. */ bool registerInternalHandler(uint16_t events) { return registerImpl(events, true); } bool isPending() const; private: bool registerImpl(uint16_t events, bool internal); void ensureNotRegistered(const char* fn); void setEventBase(EventBase* eventBase); static void libeventCallback(libevent_fd_t fd, short events, void* arg); EventBaseBackendBase::Event event_; EventBase* eventBase_; }; } // namespace folly