Simple interface for Mbed Cloud Client
Embed:
(wiki syntax)
Show/hide line numbers
arm_uc_scheduler.c
00001 // ---------------------------------------------------------------------------- 00002 // Copyright 2016-2017 ARM Ltd. 00003 // 00004 // SPDX-License-Identifier: Apache-2.0 00005 // 00006 // Licensed under the Apache License, Version 2.0 (the "License"); 00007 // you may not use this file except in compliance with the License. 00008 // You may obtain a copy of the License at 00009 // 00010 // http://www.apache.org/licenses/LICENSE-2.0 00011 // 00012 // Unless required by applicable law or agreed to in writing, software 00013 // distributed under the License is distributed on an "AS IS" BASIS, 00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 // See the License for the specific language governing permissions and 00016 // limitations under the License. 00017 // ---------------------------------------------------------------------------- 00018 00019 #include "update-client-common/arm_uc_common.h" 00020 00021 #include "pal.h" 00022 00023 static struct atomic_queue arm_uc_queue = { 0 }; 00024 static void (*arm_uc_notificationHandler)(void) = NULL; 00025 static int32_t arm_uc_queue_counter = 0; 00026 00027 void ARM_UC_AddNotificationHandler(void (*handler)(void)) 00028 { 00029 arm_uc_notificationHandler = handler; 00030 } 00031 00032 bool ARM_UC_PostCallback(arm_uc_callback_t* _storage, 00033 void (*_callback)(uint32_t), 00034 uint32_t _parameter) 00035 { 00036 bool success = false; 00037 00038 if (_storage) 00039 { 00040 /* push struct to atomic queue */ 00041 int result = aq_push_tail(&arm_uc_queue, (void *) _storage); 00042 00043 if (result == ATOMIC_QUEUE_SUCCESS) 00044 { 00045 /* populate callback struct */ 00046 /* WARNING: This is a dangerous pattern. The atomic queue should own 00047 all memory referenced by the storage element. 00048 00049 This only works when ARM_UC_ProcessQueue and 00050 ARM_UC_ProcessSingleCallback are guaranteed to be called only from 00051 lower priority than ARM_UC_PostCallback. In the update client, 00052 this is expected to be true, but it cannot be assumed to be true in 00053 all environments. This requires further rework, possibly including 00054 a critical section in ARM_UC_PostCallback, or a "taken" flag on the 00055 callback storage. 00056 */ 00057 _storage->callback = _callback; 00058 _storage->parameter = _parameter; 00059 00060 success = true; 00061 00062 /* The queue is processed by removing an element first and then 00063 decrementing the queue counter. This continues until the counter 00064 reaches 0 (process single callback) or the queue is empty 00065 (process queue). 00066 00067 If the counter is zero at this point, there is one element in 00068 the queue, and incrementing the counter will return 1 and which 00069 triggers a notification. 00070 00071 If the queue is empty at this point, the counter is -1 and 00072 incrementing the counter will return 0. This does not trigger 00073 a notification, which is correct since the queue is empty. 00074 */ 00075 int32_t count = pal_osAtomicIncrement(&arm_uc_queue_counter, 1); 00076 00077 /* if notification handler is set, check if this is the first 00078 insertion 00079 */ 00080 if ((arm_uc_notificationHandler) && (count == 1)) 00081 { 00082 /* disable: UC_COMM_TRACE("notify nanostack scheduler"); */ 00083 arm_uc_notificationHandler(); 00084 } 00085 } 00086 /* disable when not debugging */ 00087 #if 0 00088 else 00089 { 00090 UC_COMM_ERR_MSG("failed to add callback to queue: %p %p", 00091 _storage, 00092 _callback); 00093 } 00094 #endif 00095 } 00096 00097 return success; 00098 } 00099 00100 void ARM_UC_ProcessQueue(void) 00101 { 00102 arm_uc_callback_t* element = (arm_uc_callback_t*) aq_pop_head(&arm_uc_queue); 00103 00104 while (element != NULL) 00105 { 00106 /* execute callback */ 00107 element->callback(element->parameter); 00108 00109 /* decrement element counter after executing the callback. 00110 otherwise further callbacks posted inside this callback could 00111 trigger notifications eventhough we are still processing the queue. 00112 */ 00113 pal_osAtomicIncrement(&arm_uc_queue_counter, -1); 00114 00115 /* get next element */ 00116 element = (arm_uc_callback_t*) aq_pop_head(&arm_uc_queue); 00117 } 00118 } 00119 00120 bool ARM_UC_ProcessSingleCallback(void) 00121 { 00122 /* elements in queue */ 00123 int32_t count = 0; 00124 00125 /* get first element */ 00126 arm_uc_callback_t* element = (arm_uc_callback_t*) aq_pop_head(&arm_uc_queue); 00127 00128 if (element != NULL) 00129 { 00130 /* execute callback */ 00131 element->callback(element->parameter); 00132 00133 /* decrement element counter after executing the callback. 00134 otherwise further callbacks posted inside this callback could 00135 trigger notifications eventhough we are still processing the queue. 00136 00137 when this function returns false, the counter is 0 and there are 00138 either 1 or 0 elements in the queue. if there is 1 element in 00139 the queue, it means the counter hasn't been incremented yet, and 00140 incrmenting it will return 1, which will trigger a notification. 00141 */ 00142 count = pal_osAtomicIncrement(&arm_uc_queue_counter, -1); 00143 } 00144 00145 return (count > 0); 00146 }
Generated on Tue Jul 12 2022 19:01:33 by 1.7.2