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