1 /*
2 * Copyright (c) 2013-2014, Texas Instruments Incorporated
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 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
33 /*
34 * ======= IGateProvider.h ========
35 *
36 * Interface implemented by all gate providers.
37 *
38 * Gates are used serialize access to data structures that are used by more
39 * than one thread.
40 *
41 * Gates are responsible for ensuring that only one out of multiple threads
42 * can access a data structure at a time. There
43 * are important scheduling latency and performance considerations that
44 * affect the "type" of gate used to protect each data structure. For
45 * example, the best way to protect a shared counter is to simply disable
46 * all interrupts before the update and restore the interrupt state after
47 * the update; disabling all interrupts prevents all thread switching, so
48 * the update is guaranteed to be "atomic". Although highly efficient, this
49 * method of creating atomic sections causes serious system latencies when
50 * the time required to update the data structure can't be bounded.
51 *
52 * For example, a memory manager's list of free blocks can grow indefinitely
53 * long during periods of high fragmentation. Searching such a list with
54 * interrupts disabled would cause system latencies to also become unbounded.
55 * In this case, the best solution is to provide a gate that suspends the
56 * execution of threads that try to enter a gate that has already been
57 * entered; i.e., the gate "blocks" the thread until the thread
58 * already in the gate leaves. The time required to enter and leave the
59 * gate is greater than simply enabling and restoring interrupts, but since
60 * the time spent within the gate is relatively large, the overhead caused by
61 * entering and leaving gates will not become a significant percentage of
62 * overall system time. More importantly, threads that do not need to
63 * access the shared data structure are completely unaffected by threads
64 * that do access it.
65 *
66 */
68 #ifndef __IGATEPROVIDER_H__
69 #define __IGATEPROVIDER_H__
72 #if defined (__cplusplus)
73 extern "C" {
74 #endif
77 /* -----------------------------------------------------------------------------
78 * Macros
79 * -----------------------------------------------------------------------------
80 */
81 /*! Invalid Igate */
82 #define IGateProvider_NULL (IGateProvider_Handle)0xFFFFFFFF
84 /*!
85 * ======== IGateProvider_Q_BLOCKING ========
86 * Blocking quality
87 *
88 * Gates with this "quality" may cause the calling thread to block;
89 * i.e., suspend execution until another thread leaves the gate.
90 */
91 #define IGateProvider_Q_BLOCKING 1
93 /*!
94 * ======== IGateProvider_Q_PREEMPTING ========
95 * Preempting quality
96 *
97 * Gates with this "quality" allow other threads to preempt the thread
98 * that has already entered the gate.
99 */
100 #define IGateProvider_Q_PREEMPTING 2
102 /*!
103 * ======== IGateProvider_SuperObject ========
104 * Object embedded in other Gate modules. (Inheritance)
105 */
106 #define IGateProvider_SuperObject \
107 IGateProvider_ENTER enter; \
108 IGateProvider_LEAVE leave
111 /*!
112 *
113 */
114 #define IGateProvider_ObjectInitializer(x,y) \
115 ((IGateProvider_Handle)(x))->enter = (IGateProvider_ENTER)y##_enter; \
116 ((IGateProvider_Handle)(x))->leave = (IGateProvider_LEAVE)y##_leave;
118 /* -----------------------------------------------------------------------------
119 * Defines
120 * -----------------------------------------------------------------------------
121 */
122 /*! Prototype of enter function */
123 typedef IArg (*IGateProvider_ENTER) (Void *);
125 /*! Prototype of leave function */
126 typedef Void (*IGateProvider_LEAVE) (Void *, IArg);
129 /* -----------------------------------------------------------------------------
130 * Structs & Enums
131 * -----------------------------------------------------------------------------
132 */
133 /*!
134 * Structure for generic gate instance
135 */
136 typedef struct IGateProvider_Object {
137 IGateProvider_SuperObject;
138 } IGateProvider_Object, *IGateProvider_Handle;
141 /* -----------------------------------------------------------------------------
142 * APIs
143 * -----------------------------------------------------------------------------
144 */
145 /*!
146 * Enter this gate
147 *
148 * Each gate provider can implement mutual exclusion using different
149 * algorithms; e.g., disabling all scheduling, disabling the scheduling
150 * of all threads below a specified "priority level", suspending the
151 * caller when the gate has been entered by another thread and
152 * re-enabling it when the the other thread leaves the gate. However,
153 * in all cases, after this method returns that caller has exclusive
154 * access to the data protected by this gate.
155 *
156 * A thread may reenter a gate without blocking or failing.
157 *
158 * @param handle Handle to the Gate.
159 *
160 * @retval IArg Returns the instance specific return values.
161 *
162 * @sa IGateProvider_leave
163 *
164 */
165 static inline IArg IGateProvider_enter (IGateProvider_Handle handle)
166 {
167 IArg key = 0;
169 if (handle != 0x0 && handle != IGateProvider_NULL) {
170 key = (handle->enter) ((void *)handle);
171 }
172 return key;
173 }
176 /*!
177 * Leave this gate
178 *
179 * This method is only called by threads that have previously entered
180 * this gate via `{@link #enter}`. After this method returns, the
181 * caller must not access the data structure protected by this gate
182 * (unless the caller has entered the gate more than once and other
183 * calls to `leave` remain to balance the number of previous
184 * calls to `enter`).
185 *
186 * @param handle Handle to the Gate.
187 * @param key Instance specific argument.
188 *
189 * @sa IGateProvider_enter
190 *
191 */
192 static inline Void IGateProvider_leave (IGateProvider_Handle handle, IArg key)
193 {
194 if (handle != 0x0 && handle != IGateProvider_NULL)
195 (handle->leave) ((void *)handle, key);
196 }
199 #if defined (__cplusplus)
200 }
201 #endif /* defined (__cplusplus) */
204 #endif /* ifndef __IGATEPROVIDER_H__ */