1 /*
2 * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "pico/async_context_base.h"
8
async_context_base_add_at_time_worker(async_context_t * self,async_at_time_worker_t * worker)9 bool async_context_base_add_at_time_worker(async_context_t *self, async_at_time_worker_t *worker) {
10 async_at_time_worker_t **prev = &self->at_time_list;
11 while (*prev) {
12 if (worker == *prev) {
13 return false;
14 }
15 prev = &(*prev)->next;
16 }
17 *prev = worker;
18 worker->next = NULL;
19 return true;
20 }
21
async_context_base_remove_at_time_worker(async_context_t * self,async_at_time_worker_t * worker)22 bool async_context_base_remove_at_time_worker(async_context_t *self, async_at_time_worker_t *worker) {
23 async_at_time_worker_t **prev = &self->at_time_list;
24 while (*prev) {
25 if (worker == *prev) {
26 *prev = worker->next;
27 return true;
28 }
29 prev = &(*prev)->next;
30 }
31 return false;
32 }
33
async_context_base_add_when_pending_worker(async_context_t * self,async_when_pending_worker_t * worker)34 bool async_context_base_add_when_pending_worker(async_context_t *self, async_when_pending_worker_t *worker) {
35 async_when_pending_worker_t **prev = &self->when_pending_list;
36 while (*prev) {
37 if (worker == *prev) {
38 return false;
39 }
40 prev = &(*prev)->next;
41 }
42 *prev = worker;
43 worker->next = NULL;
44 return true;
45 }
46
async_context_base_remove_when_pending_worker(async_context_t * self,async_when_pending_worker_t * worker)47 bool async_context_base_remove_when_pending_worker(async_context_t *self, async_when_pending_worker_t *worker) {
48 async_when_pending_worker_t **prev = &self->when_pending_list;
49 while (*prev) {
50 if (worker == *prev) {
51 *prev = worker->next;
52 return true;
53 }
54 prev = &(*prev)->next;
55 }
56 return false;
57 }
58
async_context_base_remove_ready_at_time_worker(async_context_t * self)59 async_at_time_worker_t *async_context_base_remove_ready_at_time_worker(async_context_t *self) {
60 async_at_time_worker_t **best_prev = NULL;
61 if (self->at_time_list) {
62 absolute_time_t earliest = get_absolute_time();
63 for (async_at_time_worker_t **prev = &self->at_time_list; *prev; prev = &(*prev)->next) {
64 if (absolute_time_diff_us((*prev)->next_time, earliest) >= 0) {
65 earliest = (*prev)->next_time;
66 assert(!is_at_the_end_of_time(earliest)); // should never be less than now
67 best_prev = prev;
68 }
69 }
70 }
71 async_at_time_worker_t *rc;
72 if (best_prev) {
73 rc = *best_prev;
74 *best_prev = rc->next;
75 } else {
76 rc = NULL;
77 }
78 return rc;
79 }
80
async_context_base_refresh_next_timeout(async_context_t * self)81 void async_context_base_refresh_next_timeout(async_context_t *self) {
82 absolute_time_t earliest = at_the_end_of_time;
83 for (async_at_time_worker_t *worker = self->at_time_list; worker; ) {
84 async_at_time_worker_t *next = worker->next;
85 if (absolute_time_diff_us(worker->next_time, earliest) > 0) {
86 earliest = worker->next_time;
87 }
88 worker = next;
89 }
90 self->next_time = earliest;
91 }
92
async_context_base_execute_once(async_context_t * self)93 absolute_time_t async_context_base_execute_once(async_context_t *self) {
94 async_at_time_worker_t *at_time_worker;
95 while (NULL != (at_time_worker = async_context_base_remove_ready_at_time_worker(self))) {
96 at_time_worker->do_work(self, at_time_worker);
97 }
98 for(async_when_pending_worker_t *when_pending_worker = self->when_pending_list; when_pending_worker; when_pending_worker = when_pending_worker->next) {
99 if (when_pending_worker->work_pending) {
100 when_pending_worker->work_pending = false;
101 when_pending_worker->do_work(self, when_pending_worker);
102 }
103 }
104 async_context_base_refresh_next_timeout(self);
105 return self->next_time;
106 }
107
async_context_base_needs_servicing(async_context_t * self)108 bool async_context_base_needs_servicing(async_context_t *self) {
109 absolute_time_t now = get_absolute_time();
110 if (self->at_time_list) {
111 for (async_at_time_worker_t *worker = self->at_time_list; worker; worker = worker->next) {
112 if (absolute_time_diff_us(worker->next_time, now) >= 0) {
113 return true;
114 }
115 }
116 }
117 for(async_when_pending_worker_t *when_pending_worker = self->when_pending_list; when_pending_worker; when_pending_worker = when_pending_worker->next) {
118 if (when_pending_worker->work_pending) {
119 return true;
120 }
121 }
122 return false;
123 }