Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/atomic-queue.c@0:8f0bb79ddd48, 2021-05-04 (annotated)
- Committer:
- leothedragon
- Date:
- Tue May 04 08:55:12 2021 +0000
- Revision:
- 0:8f0bb79ddd48
nmn
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
leothedragon | 0:8f0bb79ddd48 | 1 | // ---------------------------------------------------------------------------- |
leothedragon | 0:8f0bb79ddd48 | 2 | // Copyright 2015-2017 ARM Ltd. |
leothedragon | 0:8f0bb79ddd48 | 3 | // |
leothedragon | 0:8f0bb79ddd48 | 4 | // SPDX-License-Identifier: Apache-2.0 |
leothedragon | 0:8f0bb79ddd48 | 5 | // |
leothedragon | 0:8f0bb79ddd48 | 6 | // Licensed under the Apache License, Version 2.0 (the "License"); |
leothedragon | 0:8f0bb79ddd48 | 7 | // you may not use this file except in compliance with the License. |
leothedragon | 0:8f0bb79ddd48 | 8 | // You may obtain a copy of the License at |
leothedragon | 0:8f0bb79ddd48 | 9 | // |
leothedragon | 0:8f0bb79ddd48 | 10 | // http://www.apache.org/licenses/LICENSE-2.0 |
leothedragon | 0:8f0bb79ddd48 | 11 | // |
leothedragon | 0:8f0bb79ddd48 | 12 | // Unless required by applicable law or agreed to in writing, software |
leothedragon | 0:8f0bb79ddd48 | 13 | // distributed under the License is distributed on an "AS IS" BASIS, |
leothedragon | 0:8f0bb79ddd48 | 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
leothedragon | 0:8f0bb79ddd48 | 15 | // See the License for the specific language governing permissions and |
leothedragon | 0:8f0bb79ddd48 | 16 | // limitations under the License. |
leothedragon | 0:8f0bb79ddd48 | 17 | // ---------------------------------------------------------------------------- |
leothedragon | 0:8f0bb79ddd48 | 18 | |
leothedragon | 0:8f0bb79ddd48 | 19 | #include "atomic-queue/atomic-queue.h" |
leothedragon | 0:8f0bb79ddd48 | 20 | #include "atomic.h" |
leothedragon | 0:8f0bb79ddd48 | 21 | |
leothedragon | 0:8f0bb79ddd48 | 22 | #include <stddef.h> |
leothedragon | 0:8f0bb79ddd48 | 23 | #include <stdint.h> |
leothedragon | 0:8f0bb79ddd48 | 24 | #include <stdio.h> |
leothedragon | 0:8f0bb79ddd48 | 25 | |
leothedragon | 0:8f0bb79ddd48 | 26 | #define CORE_UTIL_ASSERT_MSG(test, msg) |
leothedragon | 0:8f0bb79ddd48 | 27 | |
leothedragon | 0:8f0bb79ddd48 | 28 | |
leothedragon | 0:8f0bb79ddd48 | 29 | int aq_element_take(struct atomic_queue_element *e, void *ctx) |
leothedragon | 0:8f0bb79ddd48 | 30 | { |
leothedragon | 0:8f0bb79ddd48 | 31 | if (!e) { return ATOMIC_QUEUE_NULL_ELEMENT;} |
leothedragon | 0:8f0bb79ddd48 | 32 | if (!ctx) { return ATOMIC_QUEUE_INVALID_CONTEXT;} |
leothedragon | 0:8f0bb79ddd48 | 33 | // Duplicate element check using lock |
leothedragon | 0:8f0bb79ddd48 | 34 | uintptr_t lock; // This is initialized in the do/while loop. |
leothedragon | 0:8f0bb79ddd48 | 35 | // Check/obtain a lock on the element. |
leothedragon | 0:8f0bb79ddd48 | 36 | do { |
leothedragon | 0:8f0bb79ddd48 | 37 | lock = e->lock; |
leothedragon | 0:8f0bb79ddd48 | 38 | if (lock) { |
leothedragon | 0:8f0bb79ddd48 | 39 | return ATOMIC_QUEUE_DUPLICATE_ELEMENT; |
leothedragon | 0:8f0bb79ddd48 | 40 | } |
leothedragon | 0:8f0bb79ddd48 | 41 | } while (!aq_atomic_cas_uintptr(&e->lock, lock, (uintptr_t)ctx)); |
leothedragon | 0:8f0bb79ddd48 | 42 | return ATOMIC_QUEUE_SUCCESS; |
leothedragon | 0:8f0bb79ddd48 | 43 | } |
leothedragon | 0:8f0bb79ddd48 | 44 | |
leothedragon | 0:8f0bb79ddd48 | 45 | int aq_element_release(struct atomic_queue_element *e, void **ctx) |
leothedragon | 0:8f0bb79ddd48 | 46 | { |
leothedragon | 0:8f0bb79ddd48 | 47 | if (!e) { return ATOMIC_QUEUE_NULL_ELEMENT;} |
leothedragon | 0:8f0bb79ddd48 | 48 | if (!ctx) { return ATOMIC_QUEUE_INVALID_CONTEXT;} |
leothedragon | 0:8f0bb79ddd48 | 49 | *ctx = (void *) e->lock; |
leothedragon | 0:8f0bb79ddd48 | 50 | e->lock = 0; |
leothedragon | 0:8f0bb79ddd48 | 51 | return ATOMIC_QUEUE_SUCCESS; |
leothedragon | 0:8f0bb79ddd48 | 52 | } |
leothedragon | 0:8f0bb79ddd48 | 53 | |
leothedragon | 0:8f0bb79ddd48 | 54 | int aq_push_tail(struct atomic_queue *q, struct atomic_queue_element *e) |
leothedragon | 0:8f0bb79ddd48 | 55 | { |
leothedragon | 0:8f0bb79ddd48 | 56 | CORE_UTIL_ASSERT_MSG(q != NULL, "null queue used"); |
leothedragon | 0:8f0bb79ddd48 | 57 | if (!e) { return ATOMIC_QUEUE_NULL_ELEMENT;} |
leothedragon | 0:8f0bb79ddd48 | 58 | if (q == NULL) { |
leothedragon | 0:8f0bb79ddd48 | 59 | return ATOMIC_QUEUE_NULL_QUEUE; |
leothedragon | 0:8f0bb79ddd48 | 60 | } |
leothedragon | 0:8f0bb79ddd48 | 61 | |
leothedragon | 0:8f0bb79ddd48 | 62 | do { |
leothedragon | 0:8f0bb79ddd48 | 63 | e->next = q->tail; |
leothedragon | 0:8f0bb79ddd48 | 64 | } while (!aq_atomic_cas_uintptr((uintptr_t *)&q->tail, (uintptr_t)e->next, (uintptr_t)e)); |
leothedragon | 0:8f0bb79ddd48 | 65 | |
leothedragon | 0:8f0bb79ddd48 | 66 | return ATOMIC_QUEUE_SUCCESS; |
leothedragon | 0:8f0bb79ddd48 | 67 | } |
leothedragon | 0:8f0bb79ddd48 | 68 | |
leothedragon | 0:8f0bb79ddd48 | 69 | struct atomic_queue_element *aq_pop_head(struct atomic_queue *q) |
leothedragon | 0:8f0bb79ddd48 | 70 | { |
leothedragon | 0:8f0bb79ddd48 | 71 | CORE_UTIL_ASSERT_MSG(q != NULL, "null queue used"); |
leothedragon | 0:8f0bb79ddd48 | 72 | if (q == NULL) { |
leothedragon | 0:8f0bb79ddd48 | 73 | return NULL; |
leothedragon | 0:8f0bb79ddd48 | 74 | } |
leothedragon | 0:8f0bb79ddd48 | 75 | struct atomic_queue_element *current; |
leothedragon | 0:8f0bb79ddd48 | 76 | int fail = AQ_ATOMIC_CAS_DEREF_VALUE; |
leothedragon | 0:8f0bb79ddd48 | 77 | while (fail != AQ_ATOMIC_CAS_DEREF_SUCCESS) { |
leothedragon | 0:8f0bb79ddd48 | 78 | // Set the element reference pointer to the tail pointer |
leothedragon | 0:8f0bb79ddd48 | 79 | struct atomic_queue_element *volatile *px = &q->tail; |
leothedragon | 0:8f0bb79ddd48 | 80 | if (*px == NULL) { |
leothedragon | 0:8f0bb79ddd48 | 81 | return NULL; |
leothedragon | 0:8f0bb79ddd48 | 82 | } |
leothedragon | 0:8f0bb79ddd48 | 83 | fail = AQ_ATOMIC_CAS_DEREF_VALUE; |
leothedragon | 0:8f0bb79ddd48 | 84 | while (fail == AQ_ATOMIC_CAS_DEREF_VALUE) { |
leothedragon | 0:8f0bb79ddd48 | 85 | fail = aq_atomic_cas_deref_uintptr((uintptr_t *volatile *)px, |
leothedragon | 0:8f0bb79ddd48 | 86 | (uintptr_t **)¤t, |
leothedragon | 0:8f0bb79ddd48 | 87 | (uintptr_t) NULL, |
leothedragon | 0:8f0bb79ddd48 | 88 | NULL, |
leothedragon | 0:8f0bb79ddd48 | 89 | offsetof(struct atomic_queue_element, next)); |
leothedragon | 0:8f0bb79ddd48 | 90 | if (fail == AQ_ATOMIC_CAS_DEREF_VALUE) { |
leothedragon | 0:8f0bb79ddd48 | 91 | // Detect a loop to the tail of the queue |
leothedragon | 0:8f0bb79ddd48 | 92 | if (current->next == q->tail) { |
leothedragon | 0:8f0bb79ddd48 | 93 | return NULL; |
leothedragon | 0:8f0bb79ddd48 | 94 | } |
leothedragon | 0:8f0bb79ddd48 | 95 | px = ¤t->next; |
leothedragon | 0:8f0bb79ddd48 | 96 | } |
leothedragon | 0:8f0bb79ddd48 | 97 | } |
leothedragon | 0:8f0bb79ddd48 | 98 | } |
leothedragon | 0:8f0bb79ddd48 | 99 | |
leothedragon | 0:8f0bb79ddd48 | 100 | return current; |
leothedragon | 0:8f0bb79ddd48 | 101 | } |
leothedragon | 0:8f0bb79ddd48 | 102 | |
leothedragon | 0:8f0bb79ddd48 | 103 | |
leothedragon | 0:8f0bb79ddd48 | 104 | int aq_empty(struct atomic_queue *q) |
leothedragon | 0:8f0bb79ddd48 | 105 | { |
leothedragon | 0:8f0bb79ddd48 | 106 | return q->tail == NULL; |
leothedragon | 0:8f0bb79ddd48 | 107 | } |
leothedragon | 0:8f0bb79ddd48 | 108 | |
leothedragon | 0:8f0bb79ddd48 | 109 | unsigned aq_count(struct atomic_queue *q) |
leothedragon | 0:8f0bb79ddd48 | 110 | { |
leothedragon | 0:8f0bb79ddd48 | 111 | unsigned x; |
leothedragon | 0:8f0bb79ddd48 | 112 | struct atomic_queue_element *volatile e; |
leothedragon | 0:8f0bb79ddd48 | 113 | if (aq_empty(q)) { |
leothedragon | 0:8f0bb79ddd48 | 114 | return 0; |
leothedragon | 0:8f0bb79ddd48 | 115 | } |
leothedragon | 0:8f0bb79ddd48 | 116 | e = q->tail; |
leothedragon | 0:8f0bb79ddd48 | 117 | for (x = 1; e->next != NULL; x++, e = e->next) { |
leothedragon | 0:8f0bb79ddd48 | 118 | if (e->next == q->tail) { |
leothedragon | 0:8f0bb79ddd48 | 119 | return (unsigned) - 1; |
leothedragon | 0:8f0bb79ddd48 | 120 | } |
leothedragon | 0:8f0bb79ddd48 | 121 | } |
leothedragon | 0:8f0bb79ddd48 | 122 | return x; |
leothedragon | 0:8f0bb79ddd48 | 123 | } |
leothedragon | 0:8f0bb79ddd48 | 124 | |
leothedragon | 0:8f0bb79ddd48 | 125 | void aq_initialize_element(struct atomic_queue_element *e) |
leothedragon | 0:8f0bb79ddd48 | 126 | { |
leothedragon | 0:8f0bb79ddd48 | 127 | if (!e) { return;} |
leothedragon | 0:8f0bb79ddd48 | 128 | e->lock = 0; |
leothedragon | 0:8f0bb79ddd48 | 129 | e->next = NULL; |
leothedragon | 0:8f0bb79ddd48 | 130 | } |