Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / nlfaultinjection / repo / include / nlfaultinjection.hpp
1 /*
2  *
3  *    Copyright 2016-2018 The nlfaultinjection Authors.
4  *
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
8  *
9  *    http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  *
17  */
18
19 /**
20  *    @file
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
24  *      production code.
25  */
26
27 #ifndef FAULT_INJECTION_H_
28 #define FAULT_INJECTION_H_
29
30 #include <stddef.h>
31 #include <stdint.h>
32 #include <errno.h>
33
34 namespace nl {
35
36 namespace FaultInjection {
37
38 typedef struct _Record Record;
39 typedef struct _Callback Callback;
40
41 typedef uint32_t Identifier;
42
43 typedef const char *Name;
44
45 enum {
46     kMaxFaultArgs = 8 /**< The max number of arguments that can be stored in a fault */
47 };
48
49 /**
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.
57  *
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
63  *                              structure.
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.
66  */
67 typedef bool (*CallbackFn)(Identifier aId, Record *aFaultRecord, void *aContext);
68
69 /**
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.
72  */
73 struct _Callback
74 {
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 */
78 };
79
80 /**
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.
84  */
85 struct _Record
86 {
87     uint16_t  mNumCallsToSkip;    /**< The number of times this fault should not trigger before it
88                                        starts failing */
89     uint16_t  mNumCallsToFail;    /**< The number of times this fault should fail, before disabling
90                                        itself */
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 */
94
95     uint8_t   mLengthOfArguments; /**< The length of the array pointed to by mArguments */
96
97     uint8_t   mNumArguments;      /**< The number of items currently stored in the array pointed to by mArguments */
98
99     Callback *mCallbackList;      /**< A list of callbacks */
100
101     uint32_t  mNumTimesChecked;   /**< The number of times the fault location was executed */
102
103
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). */
113 };
114
115 /**
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.
118  */
119 class Manager
120 {
121 public:
122
123     static const bool kMutexDoNotTake = false;
124     static const bool kMutexTake = true;
125
126     int32_t Init(size_t inNumFaults, Record *inFaultArray, Name inManagerName, const Name *inFaultNames);
127
128     int32_t FailRandomlyAtFault(Identifier inId, uint8_t inPercentage = 10);
129
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,
136                         bool inTakeMutex);
137
138     int32_t RebootAtFault(Identifier inId);
139
140     int32_t StoreArgsAtFault(Identifier inId, uint16_t inNumArgs, int32_t *inArgs);
141
142     int32_t InsertCallbackAtFault(Identifier inId, Callback *inCallBack);
143
144     int32_t RemoveCallbackAtFault(Identifier inId, Callback *inCallBack);
145     int32_t RemoveCallbackAtFault(Identifier inId, Callback *inCallBack, bool inTakeMutex);
146
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);
151
152     /**
153      * Get the number of fault IDs defined by the Manager.
154      *
155      * @return  the number of fault IDs defined by the Manager.
156      */
157     size_t GetNumFaults(void) const
158     {
159         return mNumFaults;
160     }
161
162     /**
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.
165      *
166      * @return  The Manager's name, as a pointer to a const null-terminated string.
167      */
168     Name GetName(void) const
169     {
170         return mName;
171     }
172
173     /**
174      * Get a pointer to the array of fault names.
175      *
176      * @return  A pointer to a const char pointer. The array length
177      *          is the number of faults defined by the Manager; see GetNumFaults.
178      */
179     const Name *GetFaultNames(void) const
180     {
181         return mFaultNames;
182     }
183
184     const Record *GetFaultRecords(void) const
185     {
186         return mFaultRecords;
187     }
188
189     void ResetFaultCounters(void);
190
191     int32_t ResetFaultConfigurations(void);
192     int32_t ResetFaultConfigurations(Identifier inId);
193
194     /**
195      * Pointer to a function to be called when entering or exiting a critical section
196      */
197     typedef void (*LockCbFn)(void *inLockContext);
198
199     /**
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.
211      *
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
215      *                              callbacks
216      */
217     void SetLockCallbacks(LockCbFn inLock, LockCbFn inUnlock, void *inLockContext)
218     {
219         mLock = inLock;
220         mUnlock = inUnlock;
221         mLockContext = inLockContext;
222     }
223
224     void Lock(void);
225
226     void Unlock(void);
227
228 private:
229
230     size_t  mNumFaults;
231     Record *mFaultRecords;
232     Name mName;
233     const Name *mFaultNames;
234     LockCbFn mLock;
235     LockCbFn mUnlock;
236     void *mLockContext;
237 };
238
239 /**
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.
244  */
245 typedef Manager &(*GetManagerFn)(void);
246
247 /**
248  * A callback for the application to implement support for restarting
249  * the system.
250  */
251 typedef void (*RebootCallbackFn)(void);
252
253 /**
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.
256  */
257 typedef void (*PostInjectionCallbackFn)(Manager *aManager, Identifier aId, Record *aFaultRecord);
258
259 /**
260  * A table of callbacks used by all managers.
261  */
262 typedef struct _GlobalCallbackTable {
263     RebootCallbackFn        mRebootCb;        /**< See RebootCallbackFn */
264     PostInjectionCallbackFn mPostInjectionCb; /**< See PostInjectionCallbackFn */
265 } GlobalCallbackTable;
266
267 /**
268  * A structure to hold global state that is used
269  * by all Managers.
270  */
271 typedef struct _GlobalContext {
272     GlobalCallbackTable mCbTable;             /**< A table of callbacks */
273 } GlobalContext;
274
275 void SetGlobalContext(GlobalContext *inGlobalContext);
276
277 bool ParseFaultInjectionStr(char *inStr, const GetManagerFn *inArray, size_t inArraySize);
278
279 /**
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.
283  */
284 typedef struct _ManagerTable {
285     const GetManagerFn *mArray;               /**< A pointer to an array of GetManagerFn */
286     size_t mNumItems;                         /**< The length of mArray */
287 } ManagerTable;
288 bool ParseFaultInjectionStr(char *inStr, const ManagerTable *inTables, size_t inNumTables);
289
290 } // namespace FaultInjection
291
292 } // namespace nl
293
294 /**
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.
300  *
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.
304  *                        For example:
305  *                            - a single statement without terminating ";"
306  *                            - two or more statements, separated by ";"
307  *                            - a whole C++ block, enclosed in "{}"
308  */
309 #define nlFAULT_INJECT( aManager, aId, aStatements ) \
310     do { \
311         if ((aManager).CheckFault(aId)) \
312         { \
313             aStatements; \
314         } \
315     } while (0)
316
317 /**
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.
323  *
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).
329  *
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
338  */
339 #define nlFAULT_INJECT_WITH_ARGS( aManager, aId, aProtectedStatements, aUnprotectedStatements ) \
340     do { \
341         uint16_t numFaultArgs = 0; \
342         int32_t *faultArgs = NULL; \
343         \
344         (aManager).Lock(); \
345         if ((aManager).CheckFault(aId, numFaultArgs, faultArgs, nl::FaultInjection::Manager::kMutexDoNotTake)) \
346         { \
347             aProtectedStatements; \
348             (aManager).Unlock(); \
349             aUnprotectedStatements; \
350         } else { \
351             (aManager).Unlock(); \
352         } \
353     } while (0)
354
355 #endif // FAULT_INJECTION_H_