]> begriffs open source - cmsis-freertos/blob - Source/portable/ThirdParty/GCC/Xtensa_ESP32/portmux_impl.inc.h
Updated pack to FreeRTOS 10.3.1
[cmsis-freertos] / Source / portable / ThirdParty / GCC / Xtensa_ESP32 / portmux_impl.inc.h
1 /*
2     Copyright (C) 2016-2017 Espressif Shanghai PTE LTD
3     Copyright (C) 2015 Real Time Engineers Ltd.
4
5     All rights reserved
6
7     FreeRTOS is free software; you can redistribute it and/or modify it under
8     the terms of the GNU General Public License (version 2) as published by the
9     Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
10
11         ***************************************************************************
12     >>!   NOTE: The modification to the GPL is included to allow you to     !<<
13     >>!   distribute a combined work that includes FreeRTOS without being   !<<
14     >>!   obliged to provide the source code for proprietary components     !<<
15     >>!   outside of the FreeRTOS kernel.                                   !<<
16         ***************************************************************************
17
18     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
19     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20     FOR A PARTICULAR PURPOSE.  Full license text is available on the following
21     link: http://www.freertos.org/a00114.html
22 */
23
24
25 /*
26   Warning: funky preprocessor hackery ahead. Including these headers will generate two
27   functions, which names are defined by the preprocessor macros 
28   PORTMUX_AQUIRE_MUX_FN_NAME and PORTMUX_RELEASE_MUX_FN_NAME. In order to do the compare
29   and exchange function, they will use whatever PORTMUX_COMPARE_SET_FN_NAME resolves to.
30
31   In some scenarios, this header is included *twice* in portmux_impl.h: one time 
32   for the 'normal' mux code which uses a compare&exchange routine, another time 
33   to generate code for a second set of these routines that use a second mux 
34   (in internal ram) to fake a compare&exchange on a variable in external memory.
35 */
36
37
38
39 static inline bool __attribute__((always_inline))
40 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
41 PORTMUX_AQUIRE_MUX_FN_NAME(portMUX_TYPE *mux, int timeout_cycles, const char *fnName, int line) {
42 #else
43 PORTMUX_AQUIRE_MUX_FN_NAME(portMUX_TYPE *mux, int timeout_cycles) {
44 #endif
45
46
47 #if !CONFIG_FREERTOS_UNICORE
48         uint32_t res;
49         portBASE_TYPE coreID, otherCoreID;
50         uint32_t ccount_start;
51         bool set_timeout = timeout_cycles > portMUX_NO_TIMEOUT;
52 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
53         if (!set_timeout) {
54                 timeout_cycles = 10000; // Always set a timeout in debug mode
55                 set_timeout = true;
56         }
57 #endif
58         if (set_timeout) { // Timeout
59                 RSR(CCOUNT, ccount_start);
60         }
61
62 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
63         uint32_t owner = mux->owner;
64         if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) {
65                 ets_printf("ERROR: vPortCPUAcquireMutex: mux %p is uninitialized (0x%X)! Called from %s line %d.\n", mux, owner, fnName, line);
66                 mux->owner=portMUX_FREE_VAL;
67         }
68 #endif
69
70         /* Spin until we own the core */
71
72         RSR(PRID, coreID);
73         /* Note: coreID is the full 32 bit core ID (CORE_ID_PRO/CORE_ID_APP),
74            not the 0/1 value returned by xPortGetCoreID()
75         */
76         otherCoreID = CORE_ID_XOR_SWAP ^ coreID;
77         do {
78                 /* mux->owner should be one of portMUX_FREE_VAL, CORE_ID_PRO,
79                    CORE_ID_APP:
80
81                    - If portMUX_FREE_VAL, we want to atomically set to 'coreID'.
82                    - If "our" coreID, we can drop through immediately.
83                    - If "otherCoreID", we spin here.
84                  */
85                 res = coreID;
86                 PORTMUX_COMPARE_SET_FN_NAME(&mux->owner, portMUX_FREE_VAL, &res);
87
88                 if (res != otherCoreID) {
89                         break; // mux->owner is "our" coreID
90                 }
91
92                 if (set_timeout) {
93                         uint32_t ccount_now;
94                         RSR(CCOUNT, ccount_now);
95                         if (ccount_now - ccount_start > (unsigned)timeout_cycles) {
96 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
97                                 ets_printf("Timeout on mux! last non-recursive lock %s line %d, curr %s line %d\n", mux->lastLockedFn, mux->lastLockedLine, fnName, line);
98                                 ets_printf("Owner 0x%x count %d\n", mux->owner, mux->count);
99 #endif
100                                 return false;
101                         }
102                 }
103         } while (1);
104
105         assert(res == coreID || res == portMUX_FREE_VAL); /* any other value implies memory corruption or uninitialized mux */
106         assert((res == portMUX_FREE_VAL) == (mux->count == 0)); /* we're first to lock iff count is zero */
107     assert(mux->count < 0xFF); /* Bad count value implies memory corruption */
108
109         /* now we own it, we can increment the refcount */
110         mux->count++;
111
112
113 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
114         if (res==portMUX_FREE_VAL) { //initial lock
115                 mux->lastLockedFn=fnName;
116                 mux->lastLockedLine=line;
117         } else {
118                 ets_printf("Recursive lock: count=%d last non-recursive lock %s line %d, curr %s line %d\n", mux->count-1,
119                                    mux->lastLockedFn, mux->lastLockedLine, fnName, line);
120         }
121 #endif /* CONFIG_FREERTOS_PORTMUX_DEBUG */
122 #endif /* CONFIG_FREERTOS_UNICORE */
123         return true;
124 }
125
126 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
127 static inline void PORTMUX_RELEASE_MUX_FN_NAME(portMUX_TYPE *mux, const char *fnName, int line) {
128 #else
129 static inline void PORTMUX_RELEASE_MUX_FN_NAME(portMUX_TYPE *mux) {
130 #endif
131
132
133 #if !CONFIG_FREERTOS_UNICORE
134         portBASE_TYPE coreID;
135 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
136         const char *lastLockedFn=mux->lastLockedFn;
137         int lastLockedLine=mux->lastLockedLine;
138         mux->lastLockedFn=fnName;
139         mux->lastLockedLine=line;
140         uint32_t owner = mux->owner;
141         if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) {
142                 ets_printf("ERROR: vPortCPUReleaseMutex: mux %p is invalid (0x%x)!\n", mux, mux->owner);
143         }
144 #endif
145
146 #if CONFIG_FREERTOS_PORTMUX_DEBUG || !defined(NDEBUG)
147         RSR(PRID, coreID);
148 #endif
149
150 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
151         if (coreID != mux->owner) {
152                 ets_printf("ERROR: vPortCPUReleaseMutex: mux %p was already unlocked!\n", mux);
153                 ets_printf("Last non-recursive unlock %s line %d, curr unlock %s line %d\n", lastLockedFn, lastLockedLine, fnName, line);
154         }
155 #endif
156
157         assert(coreID == mux->owner); // This is a mutex we didn't lock, or it's corrupt
158
159         mux->count--;
160         if(mux->count == 0) {
161                 mux->owner = portMUX_FREE_VAL;
162         } else {
163                 assert(mux->count < 0x100); // Indicates memory corruption
164 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG_RECURSIVE
165                 ets_printf("Recursive unlock: count=%d last locked %s line %d, curr %s line %d\n", mux->count, lastLockedFn, lastLockedLine, fnName, line);
166 #endif
167         }
168 #endif //!CONFIG_FREERTOS_UNICORE
169 }