Simple interface for Mbed Cloud Client

Dependents:  

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers arm_uc_scheduler.c Source File

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 }