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 }