36#define _DEFAULT_SOURCE
46#include <sys/select.h>
50#include <emscripten.h>
57#include <user_interface.h>
64void __attribute__((weak,noinline)) Executable::test_deletion() {}
66Executable::~Executable() {
102 if (!strcmp(name,
current->name_))
146 std::function<void()>
fn_;
189 for (
int i = 12; i > 0; --i) {
191 unsigned priority = UINT_MAX;
196 msg =
next(&priority);
214#if defined(__EMSCRIPTEN__)
216void executor_loop_some(
void* arg)
228 emscripten_set_main_loop_arg(&executor_loop_some, b, 100,
true);
232#elif defined(ESP_NONOS)
234#define EXECUTOR_TASK_PRIO USER_TASK_PRIO_0
236static os_event_t appl_task_queue[1];
237static os_timer_t appl_task_timer;
238static bool timer_pending =
false;
241void ets_timer_setfn(os_timer_t *ptimer, os_timer_func_t *pfunction,
void *);
242void ets_timer_arm_new(os_timer_t *,
int,
int,
int);
243void ets_timer_disarm(os_timer_t *ptimer);
246static void timer_fun(
void* arg) {
247 timer_pending =
false;
248 system_os_post(EXECUTOR_TASK_PRIO, 0, (uint32_t)arg);
254 system_os_post(EXECUTOR_TASK_PRIO, 0, (uint32_t)arg);
257static void appl_task(os_event_t *e)
260 long long sleep_time = eb->loop_some();
261 if (sleep_time == 0) {
262 system_os_post(EXECUTOR_TASK_PRIO, 0, e->par);
264 if (
true || timer_pending) {
265 os_timer_disarm(&appl_task_timer);
267 os_timer_arm(&appl_task_timer, sleep_time / 1000000,
false);
268 timer_pending =
true;
275 os_timer_setfn(&appl_task_timer, &timer_fun,
this);
276 system_os_task(appl_task, EXECUTOR_TASK_PRIO, appl_task_queue, 1);
277 system_os_post(EXECUTOR_TASK_PRIO, 0, (uint32_t)
this);
281#elif OPENMRN_FEATURE_SINGLE_THREADED
285 DIE(
"Arduino code should not start the executor.");
302 unsigned priority = UINT_MAX;
308 msg =
next(&priority);
339 "Multiple Selectables are waiting for the same fd %d type %u", fd,
356 return FD_ISSET(fd, s);
363 if (!FD_ISSET(fd, s))
365 LOG(
FATAL,
"Tried to remove a non-active selectable: fd %d type %u", fd,
368 FD_CLR((
unsigned)fd, s);
378 max_fd = std::max(max_fd, it->fd_ + 1U);
398 long long max_sleep =
MSEC_TO_NSEC(config_executor_max_sleep_msec());
399 if (wait_length > max_sleep)
401 wait_length = max_sleep;
412 case Selectable::READ: s = &fd_r;
break;
413 case Selectable::WRITE: s = &fd_w;
break;
414 case Selectable::EXCEPT: s = &fd_x;
break;
416 if (FD_ISSET(it->fd_, s)) {
417 add(it->wakeup_, it->priority_);
422 max_fd = std::max(max_fd, it->fd_ + 1U);
434void delay(
unsigned long);
441#if defined(__EMSCRIPTEN__)
442 emscripten_cancel_main_loop();
long long get_next_timeout()
Tell when the first timer will expire.
See OSMutexLock in os/OS.hxx.
An object that can be scheduled on an executor to run.
virtual void run()=0
Entry point.
This class implements an execution of tasks pulled off an input queue.
Executable *volatile current_
Currently executing closure.
void sync_run(std::function< void()> fn)
Synchronously runs a closure on this executor.
void shutdown()
Terminates the executor thread.
Executable * current()
Helper function for debugging and tracing.
~ExecutorBase()
Destructor.
long long loop_some() ICACHE_FLASH_ATTR
Performs a few loops of the executor on the calling thread.
void * entry() override
Thread entry point.
unsigned selectPrescaler_
How many executables we schedule blindly before calling a select() in order to find more data to read...
fd_set selectRead_
fd to select for read.
fd_set selectExcept_
fd to select for except.
void select(Selectable *job)
Adds a file descriptor to be watched to the select loop.
bool is_selected(Selectable *job)
volatile unsigned sequence_
Sequence number.
ExecutorBase()
Constructor.
static ExecutorBase * by_name(const char *name, bool wait)
Lookup an executor by its name.
virtual void add(Executable *action, unsigned priority=UINT_MAX)=0
Send a message to this Executor's queue.
void wait_with_select(long long next_timer_nsec)
Executes a select call, and schedules any necessary executables based on the return.
OSSelectWakeup selectHelper_
Helper object for interruptible select calls.
fd_set selectWrite_
fd to select for write.
bool loop_once()
Performs one loop of the execution on the calling thread.
std::atomic_uint_least8_t started_
1 if the executor is already running
void unselect(Selectable *job)
Removes a job from the select loop.
TypedQueue< Selectable > selectables_
Head of the linked list for the select calls.
ActiveTimers activeTimers_
List of active timers.
fd_set * get_select_set(Selectable::SelectType type)
Helper function.
std::atomic_uint_least8_t done_
Set to 1 when the executor thread has exited and it is safe to delete *this.
int selectNFds_
maximum fd to select for + 1
static Atomic * head_mu()
Locks the list for modification (at any entry!).
static ExecutorBase * head_
Beginning of the list.
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, long long deadline_nsec)
Portable call to a select that can be woken up asynchronously from a different thread or an ISR conte...
os_thread_t main_thread()
void clear_wakeup()
Called from the main thread after being woken up.
void lock_to_thread()
Prepares the current thread for asynchronous wakeups.
void unlock_from_thread()
Resets the thread handle to none.
QMember * next
pointer to the next member in the queue
Handler structure that ExecutorBase knows about each entry to the select call.
unsigned selectType_
What to watch the file for. See SelectType.
unsigned fd_
File descriptor to watch.
void erase(const iterator &position)
Removes the entry pointed to by the iterator.
An Executable that runs a callback on the executor and returns once the run is complete.
void run() OVERRIDE
Entry point.
SyncNotifiable n_
Blocks the calling thread until the callback is done running.
std::function< void()> fn_
Callback to run.
SyncExecutable(ExecutorBase *e, std::function< void()> &&fn)
A Notifiable for synchronously waiting for a notification.
void notify() override
Implementation of notification receive.
void wait_for_notification()
Blocks the current thread until the notification is delivered.
void push_front(T *entry)
Inserts an entry to the front of the queue.
#define LOG(level, message...)
Conditionally write a message to the logging output.
static const int FATAL
Loglevel that kills the current process.
#define OVERRIDE
Function attribute for virtual functions declaring that this funciton is overriding a funciton that s...
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
#define DIE(MSG)
Unconditionally terminates the current process with a message.
#define ICACHE_FLASH_ATTR
Declares (on the ESP8266) that the current function is not executed too often and should be placed in...
#define MSEC_TO_NSEC(_msec)
Convert a millisecond value to a nanosecond value.
OS_INLINE os_thread_t os_thread_self(void)
Return a handle to the calling thread.
Helper class for using lock_to_thread.