1*7a0c41d5SAlan Somers /*- 2*7a0c41d5SAlan Somers * Copyright (c) 2011, 2012, 2013 Spectra Logic Corporation 3*7a0c41d5SAlan Somers * All rights reserved. 4*7a0c41d5SAlan Somers * 5*7a0c41d5SAlan Somers * Redistribution and use in source and binary forms, with or without 6*7a0c41d5SAlan Somers * modification, are permitted provided that the following conditions 7*7a0c41d5SAlan Somers * are met: 8*7a0c41d5SAlan Somers * 1. Redistributions of source code must retain the above copyright 9*7a0c41d5SAlan Somers * notice, this list of conditions, and the following disclaimer, 10*7a0c41d5SAlan Somers * without modification. 11*7a0c41d5SAlan Somers * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12*7a0c41d5SAlan Somers * substantially similar to the "NO WARRANTY" disclaimer below 13*7a0c41d5SAlan Somers * ("Disclaimer") and any redistribution must be conditioned upon 14*7a0c41d5SAlan Somers * including a substantially similar Disclaimer requirement for further 15*7a0c41d5SAlan Somers * binary redistribution. 16*7a0c41d5SAlan Somers * 17*7a0c41d5SAlan Somers * NO WARRANTY 18*7a0c41d5SAlan Somers * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19*7a0c41d5SAlan Somers * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20*7a0c41d5SAlan Somers * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21*7a0c41d5SAlan Somers * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22*7a0c41d5SAlan Somers * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23*7a0c41d5SAlan Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24*7a0c41d5SAlan Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25*7a0c41d5SAlan Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26*7a0c41d5SAlan Somers * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27*7a0c41d5SAlan Somers * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28*7a0c41d5SAlan Somers * POSSIBILITY OF SUCH DAMAGES. 29*7a0c41d5SAlan Somers * 30*7a0c41d5SAlan Somers * Authors: Justin T. Gibbs (Spectra Logic Corporation) 31*7a0c41d5SAlan Somers * 32*7a0c41d5SAlan Somers * $FreeBSD$ 33*7a0c41d5SAlan Somers */ 34*7a0c41d5SAlan Somers 35*7a0c41d5SAlan Somers /** 36*7a0c41d5SAlan Somers * \file callout.h 37*7a0c41d5SAlan Somers * 38*7a0c41d5SAlan Somers * \brief Interface for timer based callback services. 39*7a0c41d5SAlan Somers * 40*7a0c41d5SAlan Somers * Header requirements: 41*7a0c41d5SAlan Somers * 42*7a0c41d5SAlan Somers * #include <sys/time.h> 43*7a0c41d5SAlan Somers * 44*7a0c41d5SAlan Somers * #include <list> 45*7a0c41d5SAlan Somers */ 46*7a0c41d5SAlan Somers 47*7a0c41d5SAlan Somers #ifndef _CALLOUT_H_ 48*7a0c41d5SAlan Somers #define _CALLOUT_H_ 49*7a0c41d5SAlan Somers 50*7a0c41d5SAlan Somers /** 51*7a0c41d5SAlan Somers * \brief Type of the function callback from a Callout. 52*7a0c41d5SAlan Somers */ 53*7a0c41d5SAlan Somers typedef void CalloutFunc_t(void *); 54*7a0c41d5SAlan Somers 55*7a0c41d5SAlan Somers /** 56*7a0c41d5SAlan Somers * \brief Interface to a schedulable one-shot timer with the granularity 57*7a0c41d5SAlan Somers * of the system clock (see setitimer(2)). 58*7a0c41d5SAlan Somers * 59*7a0c41d5SAlan Somers * Determination of callback expiration is triggered by the SIGALRM 60*7a0c41d5SAlan Somers * signal. Callout callbacks are always delivered from Zfsd's event 61*7a0c41d5SAlan Somers * processing loop. 62*7a0c41d5SAlan Somers * 63*7a0c41d5SAlan Somers * Periodic actions can be triggered via the Callout mechanisms by 64*7a0c41d5SAlan Somers * resetting the Callout from within its callback. 65*7a0c41d5SAlan Somers */ 66*7a0c41d5SAlan Somers class Callout 67*7a0c41d5SAlan Somers { 68*7a0c41d5SAlan Somers public: 69*7a0c41d5SAlan Somers 70*7a0c41d5SAlan Somers /** 71*7a0c41d5SAlan Somers * Initialize the Callout subsystem. 72*7a0c41d5SAlan Somers */ 73*7a0c41d5SAlan Somers static void Init(); 74*7a0c41d5SAlan Somers 75*7a0c41d5SAlan Somers /** 76*7a0c41d5SAlan Somers * Function called (via SIGALRM) when our interval 77*7a0c41d5SAlan Somers * timer expires. 78*7a0c41d5SAlan Somers */ 79*7a0c41d5SAlan Somers static void AlarmSignalHandler(int); 80*7a0c41d5SAlan Somers 81*7a0c41d5SAlan Somers /** 82*7a0c41d5SAlan Somers * Execute callbacks for all callouts that have the same 83*7a0c41d5SAlan Somers * expiration time as the first callout in the list. 84*7a0c41d5SAlan Somers */ 85*7a0c41d5SAlan Somers static void ExpireCallouts(); 86*7a0c41d5SAlan Somers 87*7a0c41d5SAlan Somers /** Constructor. */ 88*7a0c41d5SAlan Somers Callout(); 89*7a0c41d5SAlan Somers 90*7a0c41d5SAlan Somers /** 91*7a0c41d5SAlan Somers * Returns true if callout has not been stopped, 92*7a0c41d5SAlan Somers * or deactivated since the last time the callout was 93*7a0c41d5SAlan Somers * reset. 94*7a0c41d5SAlan Somers */ 95*7a0c41d5SAlan Somers bool IsActive() const; 96*7a0c41d5SAlan Somers 97*7a0c41d5SAlan Somers /** 98*7a0c41d5SAlan Somers * Returns true if callout is still waiting to expire. 99*7a0c41d5SAlan Somers */ 100*7a0c41d5SAlan Somers bool IsPending() const; 101*7a0c41d5SAlan Somers 102*7a0c41d5SAlan Somers /** 103*7a0c41d5SAlan Somers * Disestablish a callout. 104*7a0c41d5SAlan Somers */ 105*7a0c41d5SAlan Somers bool Stop(); 106*7a0c41d5SAlan Somers 107*7a0c41d5SAlan Somers /** 108*7a0c41d5SAlan Somers * \brief Establish or change a timeout. 109*7a0c41d5SAlan Somers * 110*7a0c41d5SAlan Somers * \param interval Timeval indicating the time which must elapse 111*7a0c41d5SAlan Somers * before this callout fires. 112*7a0c41d5SAlan Somers * \param func Pointer to the callback funtion 113*7a0c41d5SAlan Somers * \param arg Argument pointer to pass to callback function 114*7a0c41d5SAlan Somers * 115*7a0c41d5SAlan Somers * \return Cancellation status. 116*7a0c41d5SAlan Somers * true: The previous callback was pending and therefore 117*7a0c41d5SAlan Somers * was cancelled. 118*7a0c41d5SAlan Somers * false: The callout was not pending at the time of this 119*7a0c41d5SAlan Somers * reset request. 120*7a0c41d5SAlan Somers * In all cases, a new callout is established. 121*7a0c41d5SAlan Somers */ 122*7a0c41d5SAlan Somers bool Reset(const timeval &interval, CalloutFunc_t *func, void *arg); 123*7a0c41d5SAlan Somers 124*7a0c41d5SAlan Somers /** 125*7a0c41d5SAlan Somers * \brief Calculate the remaining time until this Callout's timer 126*7a0c41d5SAlan Somers * expires. 127*7a0c41d5SAlan Somers * 128*7a0c41d5SAlan Somers * The return value will be slightly greater than the actual time to 129*7a0c41d5SAlan Somers * expiry. 130*7a0c41d5SAlan Somers * 131*7a0c41d5SAlan Somers * If the callout is not pending, returns INT_MAX. 132*7a0c41d5SAlan Somers */ 133*7a0c41d5SAlan Somers timeval TimeRemaining() const; 134*7a0c41d5SAlan Somers 135*7a0c41d5SAlan Somers private: 136*7a0c41d5SAlan Somers /** 137*7a0c41d5SAlan Somers * All active callouts sorted by expiration time. The callout 138*7a0c41d5SAlan Somers * with the nearest expiration time is at the head of the list. 139*7a0c41d5SAlan Somers */ 140*7a0c41d5SAlan Somers static std::list<Callout *> s_activeCallouts; 141*7a0c41d5SAlan Somers 142*7a0c41d5SAlan Somers /** 143*7a0c41d5SAlan Somers * The interval timer has expired. This variable is set from 144*7a0c41d5SAlan Somers * signal handler context and tested from Zfsd::EventLoop() 145*7a0c41d5SAlan Somers * context via ExpireCallouts(). 146*7a0c41d5SAlan Somers */ 147*7a0c41d5SAlan Somers static bool s_alarmFired; 148*7a0c41d5SAlan Somers 149*7a0c41d5SAlan Somers /** 150*7a0c41d5SAlan Somers * Time, relative to others in the active list, until 151*7a0c41d5SAlan Somers * this callout is fired. 152*7a0c41d5SAlan Somers */ 153*7a0c41d5SAlan Somers timeval m_interval; 154*7a0c41d5SAlan Somers 155*7a0c41d5SAlan Somers /** Callback function argument. */ 156*7a0c41d5SAlan Somers void *m_arg; 157*7a0c41d5SAlan Somers 158*7a0c41d5SAlan Somers /** 159*7a0c41d5SAlan Somers * The callback function associated with this timer 160*7a0c41d5SAlan Somers * entry. 161*7a0c41d5SAlan Somers */ 162*7a0c41d5SAlan Somers CalloutFunc_t *m_func; 163*7a0c41d5SAlan Somers 164*7a0c41d5SAlan Somers /** State of this callout. */ 165*7a0c41d5SAlan Somers bool m_pending; 166*7a0c41d5SAlan Somers }; 167*7a0c41d5SAlan Somers 168*7a0c41d5SAlan Somers //- Callout public const methods ---------------------------------------------- 169*7a0c41d5SAlan Somers inline bool 170*7a0c41d5SAlan Somers Callout::IsPending() const 171*7a0c41d5SAlan Somers { 172*7a0c41d5SAlan Somers return (m_pending); 173*7a0c41d5SAlan Somers } 174*7a0c41d5SAlan Somers 175*7a0c41d5SAlan Somers //- Callout public methods ---------------------------------------------------- 176*7a0c41d5SAlan Somers inline 177*7a0c41d5SAlan Somers Callout::Callout() 178*7a0c41d5SAlan Somers : m_arg(0), 179*7a0c41d5SAlan Somers m_func(NULL), 180*7a0c41d5SAlan Somers m_pending(false) 181*7a0c41d5SAlan Somers { 182*7a0c41d5SAlan Somers timerclear(&m_interval); 183*7a0c41d5SAlan Somers } 184*7a0c41d5SAlan Somers 185*7a0c41d5SAlan Somers #endif /* CALLOUT_H_ */ 186