xref: /freebsd/cddl/usr.sbin/zfsd/callout.h (revision 52832d772e9db31d7b35bf4d3e4b23d01718bad4)
17a0c41d5SAlan Somers /*-
27a0c41d5SAlan Somers  * Copyright (c) 2011, 2012, 2013 Spectra Logic Corporation
37a0c41d5SAlan Somers  * All rights reserved.
47a0c41d5SAlan Somers  *
57a0c41d5SAlan Somers  * Redistribution and use in source and binary forms, with or without
67a0c41d5SAlan Somers  * modification, are permitted provided that the following conditions
77a0c41d5SAlan Somers  * are met:
87a0c41d5SAlan Somers  * 1. Redistributions of source code must retain the above copyright
97a0c41d5SAlan Somers  *    notice, this list of conditions, and the following disclaimer,
107a0c41d5SAlan Somers  *    without modification.
117a0c41d5SAlan Somers  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
127a0c41d5SAlan Somers  *    substantially similar to the "NO WARRANTY" disclaimer below
137a0c41d5SAlan Somers  *    ("Disclaimer") and any redistribution must be conditioned upon
147a0c41d5SAlan Somers  *    including a substantially similar Disclaimer requirement for further
157a0c41d5SAlan Somers  *    binary redistribution.
167a0c41d5SAlan Somers  *
177a0c41d5SAlan Somers  * NO WARRANTY
187a0c41d5SAlan Somers  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
197a0c41d5SAlan Somers  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
207a0c41d5SAlan Somers  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
217a0c41d5SAlan Somers  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
227a0c41d5SAlan Somers  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
237a0c41d5SAlan Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
247a0c41d5SAlan Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
257a0c41d5SAlan Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
267a0c41d5SAlan Somers  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
277a0c41d5SAlan Somers  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
287a0c41d5SAlan Somers  * POSSIBILITY OF SUCH DAMAGES.
297a0c41d5SAlan Somers  *
307a0c41d5SAlan Somers  * Authors: Justin T. Gibbs     (Spectra Logic Corporation)
317a0c41d5SAlan Somers  *
327a0c41d5SAlan Somers  * $FreeBSD$
337a0c41d5SAlan Somers  */
347a0c41d5SAlan Somers 
357a0c41d5SAlan Somers /**
367a0c41d5SAlan Somers  * \file callout.h
377a0c41d5SAlan Somers  *
387a0c41d5SAlan Somers  * \brief Interface for timer based callback services.
397a0c41d5SAlan Somers  *
407a0c41d5SAlan Somers  * Header requirements:
417a0c41d5SAlan Somers  *
427a0c41d5SAlan Somers  *     #include <sys/time.h>
437a0c41d5SAlan Somers  *
447a0c41d5SAlan Somers  *     #include <list>
457a0c41d5SAlan Somers  */
467a0c41d5SAlan Somers 
477a0c41d5SAlan Somers #ifndef _CALLOUT_H_
487a0c41d5SAlan Somers #define _CALLOUT_H_
497a0c41d5SAlan Somers 
507a0c41d5SAlan Somers /**
517a0c41d5SAlan Somers  * \brief Type of the function callback from a Callout.
527a0c41d5SAlan Somers  */
537a0c41d5SAlan Somers typedef void CalloutFunc_t(void *);
547a0c41d5SAlan Somers 
557a0c41d5SAlan Somers /**
567a0c41d5SAlan Somers  * \brief Interface to a schedulable one-shot timer with the granularity
577a0c41d5SAlan Somers  *        of the system clock (see setitimer(2)).
587a0c41d5SAlan Somers  *
597a0c41d5SAlan Somers  * Determination of callback expiration is triggered by the SIGALRM
607a0c41d5SAlan Somers  * signal.  Callout callbacks are always delivered from Zfsd's event
617a0c41d5SAlan Somers  * processing loop.
627a0c41d5SAlan Somers  *
637a0c41d5SAlan Somers  * Periodic actions can be triggered via the Callout mechanisms by
647a0c41d5SAlan Somers  * resetting the Callout from within its callback.
657a0c41d5SAlan Somers  */
667a0c41d5SAlan Somers class Callout
677a0c41d5SAlan Somers {
687a0c41d5SAlan Somers public:
697a0c41d5SAlan Somers 
707a0c41d5SAlan Somers 	/**
717a0c41d5SAlan Somers 	 * Initialize the Callout subsystem.
727a0c41d5SAlan Somers 	 */
737a0c41d5SAlan Somers 	static void Init();
747a0c41d5SAlan Somers 
757a0c41d5SAlan Somers 	/**
767a0c41d5SAlan Somers 	 * Function called (via SIGALRM) when our interval
777a0c41d5SAlan Somers 	 * timer expires.
787a0c41d5SAlan Somers 	 */
797a0c41d5SAlan Somers 	static void AlarmSignalHandler(int);
807a0c41d5SAlan Somers 
817a0c41d5SAlan Somers 	/**
827a0c41d5SAlan Somers 	 * Execute callbacks for all callouts that have the same
837a0c41d5SAlan Somers 	 * expiration time as the first callout in the list.
847a0c41d5SAlan Somers 	 */
857a0c41d5SAlan Somers 	static void ExpireCallouts();
867a0c41d5SAlan Somers 
877a0c41d5SAlan Somers 	/** Constructor. */
887a0c41d5SAlan Somers 	Callout();
897a0c41d5SAlan Somers 
907a0c41d5SAlan Somers 	/**
917a0c41d5SAlan Somers 	 * Returns true if callout has not been stopped,
927a0c41d5SAlan Somers 	 * or deactivated since the last time the callout was
937a0c41d5SAlan Somers 	 * reset.
947a0c41d5SAlan Somers 	 */
957a0c41d5SAlan Somers 	bool IsActive() const;
967a0c41d5SAlan Somers 
977a0c41d5SAlan Somers 	/**
987a0c41d5SAlan Somers 	 * Returns true if callout is still waiting to expire.
997a0c41d5SAlan Somers 	 */
1007a0c41d5SAlan Somers 	bool IsPending() const;
1017a0c41d5SAlan Somers 
1027a0c41d5SAlan Somers 	/**
1037a0c41d5SAlan Somers 	 * Disestablish a callout.
1047a0c41d5SAlan Somers 	 */
1057a0c41d5SAlan Somers 	bool Stop();
1067a0c41d5SAlan Somers 
1077a0c41d5SAlan Somers 	/**
1087a0c41d5SAlan Somers 	 * \brief Establish or change a timeout.
1097a0c41d5SAlan Somers 	 *
1107a0c41d5SAlan Somers 	 * \param interval  Timeval indicating the time which must elapse
1117a0c41d5SAlan Somers 	 *                  before this callout fires.
112*52832d77SPedro F. Giffuni 	 * \param func      Pointer to the callback function
1137a0c41d5SAlan Somers 	 * \param arg       Argument pointer to pass to callback function
1147a0c41d5SAlan Somers 	 *
1157a0c41d5SAlan Somers 	 * \return  Cancellation status.
1167a0c41d5SAlan Somers 	 *             true:  The previous callback was pending and therefore
1177a0c41d5SAlan Somers 	 *                    was cancelled.
1187a0c41d5SAlan Somers 	 *             false: The callout was not pending at the time of this
1197a0c41d5SAlan Somers 	 *                    reset request.
1207a0c41d5SAlan Somers 	 *          In all cases, a new callout is established.
1217a0c41d5SAlan Somers 	 */
1227a0c41d5SAlan Somers 	bool  Reset(const timeval &interval, CalloutFunc_t *func, void *arg);
1237a0c41d5SAlan Somers 
1247a0c41d5SAlan Somers 	/**
1257a0c41d5SAlan Somers 	 * \brief Calculate the remaining time until this Callout's timer
1267a0c41d5SAlan Somers 	 *        expires.
1277a0c41d5SAlan Somers 	 *
1287a0c41d5SAlan Somers 	 * The return value will be slightly greater than the actual time to
1297a0c41d5SAlan Somers 	 * expiry.
1307a0c41d5SAlan Somers 	 *
1317a0c41d5SAlan Somers 	 * If the callout is not pending, returns INT_MAX.
1327a0c41d5SAlan Somers 	 */
1337a0c41d5SAlan Somers 	timeval TimeRemaining() const;
1347a0c41d5SAlan Somers 
1357a0c41d5SAlan Somers private:
1367a0c41d5SAlan Somers 	/**
1377a0c41d5SAlan Somers 	 * All active callouts sorted by expiration time.  The callout
1387a0c41d5SAlan Somers 	 * with the nearest expiration time is at the head of the list.
1397a0c41d5SAlan Somers 	 */
1407a0c41d5SAlan Somers 	static std::list<Callout *> s_activeCallouts;
1417a0c41d5SAlan Somers 
1427a0c41d5SAlan Somers 	/**
1437a0c41d5SAlan Somers 	 * The interval timer has expired.  This variable is set from
1447a0c41d5SAlan Somers 	 * signal handler context and tested from Zfsd::EventLoop()
1457a0c41d5SAlan Somers 	 * context via ExpireCallouts().
1467a0c41d5SAlan Somers 	 */
1477a0c41d5SAlan Somers 	static bool                 s_alarmFired;
1487a0c41d5SAlan Somers 
1497a0c41d5SAlan Somers 	/**
1507a0c41d5SAlan Somers 	 * Time, relative to others in the active list, until
1517a0c41d5SAlan Somers 	 * this callout is fired.
1527a0c41d5SAlan Somers 	 */
1537a0c41d5SAlan Somers 	timeval                     m_interval;
1547a0c41d5SAlan Somers 
1557a0c41d5SAlan Somers 	/** Callback function argument. */
1567a0c41d5SAlan Somers 	void                       *m_arg;
1577a0c41d5SAlan Somers 
1587a0c41d5SAlan Somers 	/**
1597a0c41d5SAlan Somers 	 * The callback function associated with this timer
1607a0c41d5SAlan Somers 	 * entry.
1617a0c41d5SAlan Somers 	 */
1627a0c41d5SAlan Somers 	CalloutFunc_t              *m_func;
1637a0c41d5SAlan Somers 
1647a0c41d5SAlan Somers 	/** State of this callout. */
1657a0c41d5SAlan Somers 	bool                        m_pending;
1667a0c41d5SAlan Somers };
1677a0c41d5SAlan Somers 
1687a0c41d5SAlan Somers //- Callout public const methods ----------------------------------------------
1697a0c41d5SAlan Somers inline bool
1707a0c41d5SAlan Somers Callout::IsPending() const
1717a0c41d5SAlan Somers {
1727a0c41d5SAlan Somers 	return (m_pending);
1737a0c41d5SAlan Somers }
1747a0c41d5SAlan Somers 
1757a0c41d5SAlan Somers //- Callout public methods ----------------------------------------------------
1767a0c41d5SAlan Somers inline
1777a0c41d5SAlan Somers Callout::Callout()
1787a0c41d5SAlan Somers  : m_arg(0),
1797a0c41d5SAlan Somers    m_func(NULL),
1807a0c41d5SAlan Somers    m_pending(false)
1817a0c41d5SAlan Somers {
1827a0c41d5SAlan Somers 	timerclear(&m_interval);
1837a0c41d5SAlan Somers }
1847a0c41d5SAlan Somers 
1857a0c41d5SAlan Somers #endif /* CALLOUT_H_ */
186