| /* |
| * Copyright (c) 2022 Raspberry Pi (Trading) Ltd. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| */ |
| |
| #include "pico/async_context_base.h" |
| |
| bool async_context_base_add_at_time_worker(async_context_t *self, async_at_time_worker_t *worker) { |
| async_at_time_worker_t **prev = &self->at_time_list; |
| while (*prev) { |
| if (worker == *prev) { |
| return false; |
| } |
| prev = &(*prev)->next; |
| } |
| *prev = worker; |
| worker->next = NULL; |
| return true; |
| } |
| |
| bool async_context_base_remove_at_time_worker(async_context_t *self, async_at_time_worker_t *worker) { |
| async_at_time_worker_t **prev = &self->at_time_list; |
| while (*prev) { |
| if (worker == *prev) { |
| *prev = worker->next; |
| return true; |
| } |
| prev = &(*prev)->next; |
| } |
| return false; |
| } |
| |
| bool async_context_base_add_when_pending_worker(async_context_t *self, async_when_pending_worker_t *worker) { |
| async_when_pending_worker_t **prev = &self->when_pending_list; |
| while (*prev) { |
| if (worker == *prev) { |
| return false; |
| } |
| prev = &(*prev)->next; |
| } |
| *prev = worker; |
| worker->next = NULL; |
| return true; |
| } |
| |
| bool async_context_base_remove_when_pending_worker(async_context_t *self, async_when_pending_worker_t *worker) { |
| async_when_pending_worker_t **prev = &self->when_pending_list; |
| while (*prev) { |
| if (worker == *prev) { |
| *prev = worker->next; |
| return true; |
| } |
| prev = &(*prev)->next; |
| } |
| return false; |
| } |
| |
| async_at_time_worker_t *async_context_base_remove_ready_at_time_worker(async_context_t *self) { |
| async_at_time_worker_t **best_prev = NULL; |
| if (self->at_time_list) { |
| absolute_time_t earliest = get_absolute_time(); |
| for (async_at_time_worker_t **prev = &self->at_time_list; *prev; prev = &(*prev)->next) { |
| if (absolute_time_diff_us((*prev)->next_time, earliest) >= 0) { |
| earliest = (*prev)->next_time; |
| assert(!is_at_the_end_of_time(earliest)); // should never be less than now |
| best_prev = prev; |
| } |
| } |
| } |
| async_at_time_worker_t *rc; |
| if (best_prev) { |
| rc = *best_prev; |
| *best_prev = rc->next; |
| } else { |
| rc = NULL; |
| } |
| return rc; |
| } |
| |
| void async_context_base_refresh_next_timeout(async_context_t *self) { |
| absolute_time_t earliest = at_the_end_of_time; |
| for (async_at_time_worker_t *worker = self->at_time_list; worker; ) { |
| async_at_time_worker_t *next = worker->next; |
| if (absolute_time_diff_us(worker->next_time, earliest) > 0) { |
| earliest = worker->next_time; |
| } |
| worker = next; |
| } |
| self->next_time = earliest; |
| } |
| |
| absolute_time_t async_context_base_execute_once(async_context_t *self) { |
| async_at_time_worker_t *at_time_worker; |
| while (NULL != (at_time_worker = async_context_base_remove_ready_at_time_worker(self))) { |
| at_time_worker->do_work(self, at_time_worker); |
| } |
| for(async_when_pending_worker_t *when_pending_worker = self->when_pending_list; when_pending_worker; when_pending_worker = when_pending_worker->next) { |
| if (when_pending_worker->work_pending) { |
| when_pending_worker->work_pending = false; |
| when_pending_worker->do_work(self, when_pending_worker); |
| } |
| } |
| async_context_base_refresh_next_timeout(self); |
| return self->next_time; |
| } |
| |
| bool async_context_base_needs_servicing(async_context_t *self) { |
| absolute_time_t now = get_absolute_time(); |
| if (self->at_time_list) { |
| for (async_at_time_worker_t *worker = self->at_time_list; worker; worker = worker->next) { |
| if (absolute_time_diff_us(worker->next_time, now) >= 0) { |
| return true; |
| } |
| } |
| } |
| for(async_when_pending_worker_t *when_pending_worker = self->when_pending_list; when_pending_worker; when_pending_worker = when_pending_worker->next) { |
| if (when_pending_worker->work_pending) { |
| return true; |
| } |
| } |
| return false; |
| } |