3 * Copyright 2016-2018 The nlfaultinjection Authors.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
21 * Header file for the fault-injection utilities.
22 * This module provides an object to manager a set of fault IDs,
23 * and a macro to simplify the insertion of fault code in
27 #ifndef FAULT_INJECTION_H_
28 #define FAULT_INJECTION_H_
36 namespace FaultInjection {
38 typedef struct _Record Record;
39 typedef struct _Callback Callback;
41 typedef uint32_t Identifier;
43 typedef const char *Name;
46 kMaxFaultArgs = 8 /**< The max number of arguments that can be stored in a fault */
50 * A fault-injection callback function.
51 * A function of this type can be attached to a fault ID, and will be invoked every time
52 * FaultInjectionMgr::CheckFault is called on the fault ID.
53 * The main purpose of registering a callback is to be able to turn on lower-level faults from
54 * higher level events; e.g., "fail in SendMessage for the next WDM ViewRequest."
55 * The callback can also be used to let the application decide if the fault is supposed to be
56 * triggered at each invocation. If the callback returns true, the fault is triggered.
58 * @param[in] aFaultID The fault ID
59 * @param[in] aFaultRecord Pointer to the Record for aFaultID;
60 * This allows the callback to check how the fault is configured
61 * before taking action.
62 * @param[in] aContext The pointer stored by the application in the Callback
64 * @return true if the fault is to be triggered. false if this callback does not want to
65 * force the fault to be triggered.
67 typedef bool (*CallbackFn)(Identifier aId, Record *aFaultRecord, void *aContext);
70 * A linked-list node to hold a callback function to be attached to a fault ID.
71 * The application can store a pointer in the mContext member.
75 CallbackFn mCallBackFn; /**< Callback function pointer */
76 void *mContext; /**< Pointer for the application to store a context for mCallbackFn */
77 Callback *mNext; /**< Linked list next pointer */
81 * Structure that stores the configuration of a given fault ID.
82 * The module defining the fault-injection API needs to provide an array of Record
83 * and pass it to its Manager instance via the Init method.
87 uint16_t mNumCallsToSkip; /**< The number of times this fault should not trigger before it
89 uint16_t mNumCallsToFail; /**< The number of times this fault should fail, before disabling
91 uint8_t mPercentage; /**< A number between 0 and 100 that indicates the percentage of
92 times the fault should be triggered */
93 uint8_t mReboot; /**< This fault should reboot the system */
95 uint8_t mLengthOfArguments; /**< The length of the array pointed to by mArguments */
97 uint8_t mNumArguments; /**< The number of items currently stored in the array pointed to by mArguments */
99 Callback *mCallbackList; /**< A list of callbacks */
101 uint32_t mNumTimesChecked; /**< The number of times the fault location was executed */
104 int32_t *mArguments; /**< A pointer to an array of integers to store extra arguments; this array is meant to
105 be populated by either of the following:
106 - the ParseFaultInjectionStr, so the values are available at the fault injection site
107 and when the fault is injected.
108 - the logic around the fault injection site, to save useful values that can then
109 be logged by a callback installed by the application, and so made available for use
110 in subsequent test runs as arguments to the injected code.
111 For example, the values can be exact arguments to be passed in, or ranges to be
112 iterated on (like the length of a byte array to be fuzzed). */
116 * The module that provides a fault-injection API needs to provide an instance of Manager,
117 * and initialize it with an array of Record.
123 static const bool kMutexDoNotTake = false;
124 static const bool kMutexTake = true;
126 int32_t Init(size_t inNumFaults, Record *inFaultArray, Name inManagerName, const Name *inFaultNames);
128 int32_t FailRandomlyAtFault(Identifier inId, uint8_t inPercentage = 10);
130 int32_t FailAtFault(Identifier inId,
131 uint32_t inNumCallsToSkip,
132 uint32_t inNumCallsToFail);
133 int32_t FailAtFault(Identifier inId,
134 uint32_t inNumCallsToSkip,
135 uint32_t inNumCallsToFail,
138 int32_t RebootAtFault(Identifier inId);
140 int32_t StoreArgsAtFault(Identifier inId, uint16_t inNumArgs, int32_t *inArgs);
142 int32_t InsertCallbackAtFault(Identifier inId, Callback *inCallBack);
144 int32_t RemoveCallbackAtFault(Identifier inId, Callback *inCallBack);
145 int32_t RemoveCallbackAtFault(Identifier inId, Callback *inCallBack, bool inTakeMutex);
147 bool CheckFault(Identifier inId);
148 bool CheckFault(Identifier inId, bool inTakeMutex);
149 bool CheckFault(Identifier inId, uint16_t &outNumArgs, int32_t *&outArgs);
150 bool CheckFault(Identifier inId, uint16_t &outNumArgs, int32_t *&outArgs, bool inTakeMutex);
153 * Get the number of fault IDs defined by the Manager.
155 * @return the number of fault IDs defined by the Manager.
157 size_t GetNumFaults(void) const
163 * Get the name of the Manager. Every Manager object is initialized with a name,
164 * so that faults can be configured using human-readable strings.
166 * @return The Manager's name, as a pointer to a const null-terminated string.
168 Name GetName(void) const
174 * Get a pointer to the array of fault names.
176 * @return A pointer to a const char pointer. The array length
177 * is the number of faults defined by the Manager; see GetNumFaults.
179 const Name *GetFaultNames(void) const
184 const Record *GetFaultRecords(void) const
186 return mFaultRecords;
189 void ResetFaultCounters(void);
191 int32_t ResetFaultConfigurations(void);
192 int32_t ResetFaultConfigurations(Identifier inId);
195 * Pointer to a function to be called when entering or exiting a critical section
197 typedef void (*LockCbFn)(void *inLockContext);
200 * On multithreaded systems, the Manager's data structures need to be protected with
201 * a mutex; a common example is the case of the system being configured by one thread (calling
202 * ParseFaultInjectionStr, ResetFaultConfigurations etc) while another thread runs the
203 * code in which faults are injected.
204 * The application is supposed to provide two function pointers, one to enter the
205 * critical section and one to exit it.
206 * The application can decide to use the same mutex for all Managers, or to protect different
207 * Managers with different mutexes.
208 * In case the platform does not support re-entrant mutexes, the application's callbacks installed
209 * at the fault injection points must use the inTakeMutex argument to the Manager's method to
210 * avoid taking the same mutes twice.
212 * @param[in] inLock The callback to take the mutex
213 * @param[in] inUnlock The callback to release the mutex
214 * @param[in] inLockContext a void pointer to the mutex context, which is passed to the
217 void SetLockCallbacks(LockCbFn inLock, LockCbFn inUnlock, void *inLockContext)
221 mLockContext = inLockContext;
231 Record *mFaultRecords;
233 const Name *mFaultNames;
240 * The type of a function that returns a reference to a Manager
241 * The module is expected to provide such a function so that
242 * it can be added to an array of GetManagerFn instances and passed to
243 * ParseFaultInjectionStr.
245 typedef Manager &(*GetManagerFn)(void);
248 * A callback for the application to implement support for restarting
251 typedef void (*RebootCallbackFn)(void);
254 * A callback to inform the application that a Manager has decided to inject a fault.
255 * The main use of this type of callback is to print a log statement.
257 typedef void (*PostInjectionCallbackFn)(Manager *aManager, Identifier aId, Record *aFaultRecord);
260 * A table of callbacks used by all managers.
262 typedef struct _GlobalCallbackTable {
263 RebootCallbackFn mRebootCb; /**< See RebootCallbackFn */
264 PostInjectionCallbackFn mPostInjectionCb; /**< See PostInjectionCallbackFn */
265 } GlobalCallbackTable;
268 * A structure to hold global state that is used
271 typedef struct _GlobalContext {
272 GlobalCallbackTable mCbTable; /**< A table of callbacks */
275 void SetGlobalContext(GlobalContext *inGlobalContext);
277 bool ParseFaultInjectionStr(char *inStr, const GetManagerFn *inArray, size_t inArraySize);
280 * A structure to store an array of GetManagerFn arrays, used by ParseFaultInjectionStr.
281 * The main purpose of this is to pass a collection of static tables owned of GetManagerFn owned
282 * by separate modules to ParseFaultInjectionStr.
284 typedef struct _ManagerTable {
285 const GetManagerFn *mArray; /**< A pointer to an array of GetManagerFn */
286 size_t mNumItems; /**< The length of mArray */
288 bool ParseFaultInjectionStr(char *inStr, const ManagerTable *inTables, size_t inNumTables);
290 } // namespace FaultInjection
295 * The macro to inject the fault code.
296 * Typically the module offering a fault-injection API
297 * wraps this macro into a macro that:
298 * 1. translates to a no-op if faults are disabled at compile time.
299 * 2. hardcodes aManager to the module's own.
301 * @param[in] aManager The Manager
302 * @param[in] aId The fault ID
303 * @param[in] aStatements C++ code to be executed if the fault is to be injected.
305 * - a single statement without terminating ";"
306 * - two or more statements, separated by ";"
307 * - a whole C++ block, enclosed in "{}"
309 #define nlFAULT_INJECT( aManager, aId, aStatements ) \
311 if ((aManager).CheckFault(aId)) \
318 * The macro to inject fault code that depends on extra arguments (see StoreArgsAtFault).
319 * Typically the module offering a fault-injection API
320 * wraps this macro into a macro that:
321 * 1. translates to a no-op if faults are disabled at compile time;
322 * 2. hardcodes aManager to the module's own.
324 * Note that on multithreaded systems the statements that consume the
325 * arguments need to be protected by the Manager's mutex.
326 * Any other statements should be executed outside of the mutex
327 * (this is a must in particular for statements that trigger the execution
328 * of a different fault injection site).
330 * @param[in] aManager The Manager
331 * @param[in] aId The fault ID
332 * @param[in] aProtectedStatements C++ code to be executed if the fault is to be injected,
333 * while holding the Manager's mutex.
334 * These statements usually refer to a local array of int32_t
335 * args called faultArgs, of length numFaultArgs to access the extra arguments.
336 * @param[in] aUnprotectedStatements C++ code to be executed if the fault is to be injected,
337 * outside of the Manager's mutex
339 #define nlFAULT_INJECT_WITH_ARGS( aManager, aId, aProtectedStatements, aUnprotectedStatements ) \
341 uint16_t numFaultArgs = 0; \
342 int32_t *faultArgs = NULL; \
345 if ((aManager).CheckFault(aId, numFaultArgs, faultArgs, nl::FaultInjection::Manager::kMutexDoNotTake)) \
347 aProtectedStatements; \
348 (aManager).Unlock(); \
349 aUnprotectedStatements; \
351 (aManager).Unlock(); \
355 #endif // FAULT_INJECTION_H_