le_safeRef.h

Go to the documentation of this file.
1 /**
2  * @page c_safeRef Safe References API
3  *
4  * @ref le_safeRef.h "API Reference"
5  *
6  * <HR>
7  *
8  *
9  * The term "reference" is used to mean "opaque data that refers to some conceptual object".
10  * It is intentionally vague to support "information hiding". Behind the
11  * scenes, different implementations can use almost anything that fits into a pointer as a
12  * "reference". Often, they are indexes into arrays or actual pointers to memory objects.
13  * When passing those references through an API to outside clients, the implementation
14  * becomes exposed to crash bugs when clients
15  * pass those references back into the API damaged or stale ("stale" meaning
16  * something that has been deleted).
17  *
18  * <b> Safe References </b> are designed to help protect against damaged or stale references being
19  * used by clients.
20  *
21  * @section c_safeRef_create Create Safe Reference
22  *
23  * Client calls an API's "Create" function:
24  * - "Create" function creates an object.
25  * - "Create" function creates a "Safe Reference" for the new object @c le_ref_CreateRef()
26  * - "Create" function returns the Safe Reference.
27  *
28  * @section c_safeRef_lookup Lookup Pointer
29  *
30  * Followed by:
31  *
32  * Client calls another API function, passing in the Safe Reference:
33  * - API function translates the Safe Reference back into an object pointer @c le_ref_Lookup()
34  * - API function acts on the object.
35  *
36  * @section c_safeRef_delete Delete Safe Reference
37  *
38  * Finishing with:
39  *
40  * Client calls API's "Delete" function, passing in the Safe Reference:
41  * - "Delete" function translates the Safe Reference back into a pointer to its object.
42  * - "Delete" function invalidates the Safe Reference @c le_ref_DeleteRef()
43  * - "Delete" function deletes the object.
44  *
45  * At this point, if the Client calls an API function and passes that same (now invalid) Safe Reference
46  * (or if the client accidentally passes in some garbage value, like a pointer or zero), the
47  * API function will try to translate that into an object pointer. But it'll be told that it's
48  * an invalid Safe Reference. The API function can then handle it gracefully, rather
49  * than just acting as if it were a valid reference and clobbering the object's deallocated
50  * memory or some other object that's reusing the old object's memory.
51  *
52  * @section c_safeRef_map Create Referece Map
53  *
54  * A <b> Reference Map </b> object can be used to create Safe References and keep track of the
55  * mappings from Safe References to pointers. At start-up, a Reference Map is
56  * created by calling @c le_ref_CreateMap(). It takes a single argument, the maximum number
57  * of mappings expected to track of at any time.
58  *
59  * @section c_safeRef_multithreading Multithreading
60  *
61  * This API's functions are reentrant, but not thread safe. If there's the slightest
62  * possibility the same Reference Map will be accessed by two threads at the same time, use
63  * a mutex or some other thread synchronization mechanism to protect the Reference Map from
64  * concurrent access.
65  *
66  * @section c_safeRef_example Sample Code
67  *
68  * Here's an API Definition sample:
69  *
70  * @code
71  * // Opaque reference to Foo objects.
72  * typedef struct xyz_foo_Obj* xyz_foo_ObjRef_t;
73  *
74  * xyz_foo_Ref_t xyz_foo_CreateObject
75  * (
76  * void
77  * );
78  *
79  * void xyz_foo_DoSomething
80  * (
81  * xyz_foo_Ref_t objRef
82  * );
83  *
84  * void xyz_foo_DeleteObject
85  * (
86  * xyz_foo_Ref_t objRef
87  * );
88  * @endcode
89  *
90  * Here's an API Implementation sample:
91  *
92  * @code
93  * // Maximum number of Foo objects we expect to have at one time.
94  * #define MAX_FOO_OBJECTS 27
95  *
96  * // Actual Foo objects.
97  * typedef struct
98  * {
99  * ...
100  * }
101  * Foo_t;
102  *
103  * // Pool from which Foo objects are allocated.
104  * le_mem_PoolRef_t FooPool;
105  *
106  * // Safe Reference Map for Foo objects.
107  * le_ref_MapRef_t FooRefMap;
108  *
109  * COMPONENT_INIT
110  * {
111  * // Create the Foo object pool.
112  * FooPool = le_mem_CreatePool("FooPool", sizeof(Foo_t));
113  * le_mem_ExpandPool(FooPool, MAX_FOO_OBJECTS);
114  *
115  * // Create the Safe Reference Map to use for Foo object Safe References.
116  * FooRefMap = le_ref_CreateMap("FooMap", MAX_FOO_OBJECTS);
117  * };
118  *
119  * xyz_foo_Ref_t xyz_foo_CreateObject
120  * (
121  * void
122  * )
123  * {
124  * Foo_t* fooPtr = le_mem_ForceAlloc(FooPool);
125  *
126  * // Initialize the new Foo object.
127  * ...
128  *
129  * // Create and return a Safe Reference for this Foo object.
130  * return le_ref_CreateRef(FooRefMap, fooPtr);
131  * }
132  *
133  * void xyz_foo_DoSomething
134  * (
135  * xyz_foo_Ref_t objRef
136  * )
137  * {
138  * Foo_t* fooPtr = le_ref_Lookup(FooRefMap, objRef);
139  *
140  * if (fooPtr == NULL)
141  * {
142  * LE_CRIT("Invalid reference (%p) provided!", objRef);
143  * return;
144  * }
145  *
146  * // Do something to the object.
147  * ...
148  * }
149  *
150  * void xyz_foo_DeleteObject
151  * (
152  * xyz_foo_Ref_t objRef
153  * )
154  * {
155  * Foo_t* fooPtr = le_ref_Lookup(FooRefMap, objRef);
156  *
157  * if (fooPtr == NULL)
158  * {
159  * LE_CRIT("Invalid reference (%p) provided!", objRef);
160  * return;
161  * }
162  *
163  * // Invalidate the Safe Reference.
164  * le_ref_DeleteRef(FooRefMap, objRef);
165  *
166  * // Release the Foo object.
167  * le_mem_Release(fooPtr);
168  * }
169  * @endcode
170  *
171  * <HR>
172  *
173  * Copyright (C) Sierra Wireless Inc. Use of this work is subject to license.
174  */
175 
176 /** @file le_safeRef.h
177  *
178  * Legato @ref c_safeRef include file.
179  *
180  * Copyright (C) Sierra Wireless Inc. Use of this work is subject to license.
181  */
182 
183 #ifndef LEGATO_SAFEREF_INCLUDE_GUARD
184 #define LEGATO_SAFEREF_INCLUDE_GUARD
185 
186 //--------------------------------------------------------------------------------------------------
187 /**
188  * Reference to a "Reference Map" object, which stores mappings from Safe References to pointers.
189  */
190 //--------------------------------------------------------------------------------------------------
191 typedef struct le_ref_Map* le_ref_MapRef_t;
192 
193 
194 //--------------------------------------------------------------------------------------------------
195 /**
196  * Reference to an "iterator" object, used to manage iterating a collection of safe refs.
197  */
198 //--------------------------------------------------------------------------------------------------
199 typedef struct le_ref_Iter* le_ref_IterRef_t;
200 
201 
202 //--------------------------------------------------------------------------------------------------
203 /**
204  * Create a Reference Map that can hold mappings from Safe References to pointers.
205  *
206  * @return A reference to the Reference Map object.
207  */
208 //--------------------------------------------------------------------------------------------------
210 (
211  const char* name, ///< [in] Name of the map (for diagnostics).
212 
213  size_t maxRefs ///< [in] Maximum number of Safe References expected to be kept in
214  /// this Reference Map at any one time.
215 );
216 
217 
218 //--------------------------------------------------------------------------------------------------
219 /**
220  * Creates a Safe Reference, storing a mapping between that reference and a specified pointer for
221  * future lookup.
222  *
223  * @return The Safe Reference.
224  */
225 //--------------------------------------------------------------------------------------------------
226 void* le_ref_CreateRef
227 (
228  le_ref_MapRef_t mapRef, ///< [in] Reference Map in which the mapping should be kept.
229  void* ptr ///< [in] Pointer value to which the new Safe Reference will be mapped.
230 );
231 
232 
233 //--------------------------------------------------------------------------------------------------
234 /**
235  * Translates a Safe Reference back to the pointer from when the Safe Reference
236  * was created.
237  *
238  * @return Pointer that the Safe Reference maps to, or NULL if the Safe Reference has been
239  * deleted or is invalid.
240  */
241 //--------------------------------------------------------------------------------------------------
242 void* le_ref_Lookup
243 (
244  le_ref_MapRef_t mapRef, ///< [in] Reference Map to do the lookup in.
245  void* safeRef ///< [in] Safe Reference to be translated into a pointer.
246 );
247 
248 
249 //--------------------------------------------------------------------------------------------------
250 /**
251  * Deletes a Safe Reference.
252  */
253 //--------------------------------------------------------------------------------------------------
254 void le_ref_DeleteRef
255 (
256  le_ref_MapRef_t mapRef, ///< [in] Reference Map to delete the mapping from.
257  void* safeRef ///< [in] Safe Reference to be deleted (invalidated).
258 );
259 
260 
261 //--------------------------------------------------------------------------------------------------
262 /**
263  * Gets an interator for step-by-step iteration over the map. In this mode the iteration is
264  * controlled by the calling function using the le_ref_NextNode() function. There is one iterator
265  * per map, and calling this function resets the iterator position to the start of the map. The
266  * iterator is not ready for data access until le_ref_NextNode() has been called at least once.
267  *
268  * @return Returns A reference to a hashmap iterator which is ready for le_hashmap_NextNode() to be
269  * called on it.
270  */
271 //--------------------------------------------------------------------------------------------------
273 (
274  le_ref_MapRef_t mapRef ///< [in] Reference to the map.
275 );
276 
277 
278 //--------------------------------------------------------------------------------------------------
279 /**
280  * Moves the iterator to the next key/value pair in the map.
281  *
282  * @return Returns LE_OK unless you go past the end of the map, then returns LE_NOT_FOUND.
283  * If the iterator has been invalidated by the map changing or you have previously
284  * received a LE_NOT_FOUND then this returns LE_FAULT.
285  */
286 //--------------------------------------------------------------------------------------------------
288 (
289  le_ref_IterRef_t iteratorRef ///< [IN] Reference to the iterator.
290 );
291 
292 
293 //--------------------------------------------------------------------------------------------------
294 /**
295  * Retrieves a pointer to the safe ref iterator is currently pointing at. If the iterator has just
296  * been initialized and le_hashmap_NextNode() has not been called, or if the iterator has been
297  * invalidated then this will return NULL.
298  *
299  * @return A pointer to the current key, or NULL if the iterator has been invalidated or is not ready.
300  *
301  */
302 //--------------------------------------------------------------------------------------------------
303 void const * le_ref_GetSafeRef
304 (
305  le_ref_IterRef_t iteratorRef ///< [IN] Reference to the iterator.
306 );
307 
308 
309 //--------------------------------------------------------------------------------------------------
310 /**
311  * Retrieves a pointer to the value which the iterator is currently pointing at. If the iterator
312  * has just been initialized and le_ref_NextNode() has not been called, or if the iterator has been
313  * invalidated then this will return NULL.
314  *
315  * @return A pointer to the current value, or NULL if the iterator has been invalidated or is not
316  * ready.
317  */
318 //--------------------------------------------------------------------------------------------------
319 void const * le_ref_GetValue
320 (
321  le_ref_IterRef_t iteratorRef ///< [IN] Reference to the iterator.
322 );
323 
324 
325 #endif // LEGATO_SAFEREF_INCLUDE_GUARD
le_result_t
Definition: le_basics.h:35
struct le_ref_Iter * le_ref_IterRef_t
Definition: le_safeRef.h:199
struct le_ref_Map * le_ref_MapRef_t
Definition: le_safeRef.h:191
le_ref_MapRef_t le_ref_CreateMap(const char *name, size_t maxRefs)
le_ref_IterRef_t le_ref_GetIterator(le_ref_MapRef_t mapRef)
void le_ref_DeleteRef(le_ref_MapRef_t mapRef, void *safeRef)
void * le_ref_CreateRef(le_ref_MapRef_t mapRef, void *ptr)
le_result_t le_ref_NextNode(le_ref_IterRef_t iteratorRef)
void const * le_ref_GetSafeRef(le_ref_IterRef_t iteratorRef)
void * le_ref_Lookup(le_ref_MapRef_t mapRef, void *safeRef)
void const * le_ref_GetValue(le_ref_IterRef_t iteratorRef)