blob: 9e385471a6385bd29f76a6b73128e1c3d9049a64 [file] [log] [blame]
/*
* 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;
}