130 lines
3.5 KiB
C
130 lines
3.5 KiB
C
#pragma once
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
// Syscalls that can be invoked from tasks.
|
|
enum rt_syscall
|
|
{
|
|
RT_SYSCALL_SLEEP,
|
|
RT_SYSCALL_SLEEP_PERIODIC,
|
|
RT_SYSCALL_SEM_WAIT,
|
|
RT_SYSCALL_SEM_TIMEDWAIT,
|
|
RT_SYSCALL_SEM_POST,
|
|
RT_SYSCALL_MUTEX_LOCK,
|
|
RT_SYSCALL_MUTEX_TIMEDLOCK,
|
|
RT_SYSCALL_MUTEX_UNLOCK,
|
|
RT_SYSCALL_YIELD,
|
|
RT_SYSCALL_EXIT,
|
|
};
|
|
|
|
// Syscalls that can be invoked from interrupts.
|
|
enum rt_syscall_pendable
|
|
{
|
|
RT_SYSCALL_PENDABLE_SEM_POST,
|
|
RT_SYSCALL_PENDABLE_TICK,
|
|
};
|
|
|
|
struct rt_sem;
|
|
struct rt_mutex;
|
|
|
|
union rt_syscall_args
|
|
{
|
|
struct rt_syscall_args_sem_post
|
|
{
|
|
struct rt_sem *sem;
|
|
int n;
|
|
} sem_post;
|
|
};
|
|
|
|
struct rt_syscall_record
|
|
{
|
|
struct rt_syscall_record *next;
|
|
union rt_syscall_args args;
|
|
enum rt_syscall_pendable syscall;
|
|
};
|
|
|
|
/* Architecture-dependent synchronous syscall triggers. The syscall should be
|
|
* executed before this function returns. */
|
|
void rt_syscall_0(enum rt_syscall syscall);
|
|
void rt_syscall_1(enum rt_syscall syscall, uintptr_t arg0);
|
|
void rt_syscall_2(enum rt_syscall syscall, uintptr_t arg0, uintptr_t arg1);
|
|
void rt_syscall_3(enum rt_syscall syscall, uintptr_t arg0, uintptr_t arg1,
|
|
uintptr_t arg2);
|
|
|
|
static inline void rt_syscall_sleep(unsigned long ticks)
|
|
{
|
|
rt_syscall_1(RT_SYSCALL_SLEEP, ticks);
|
|
}
|
|
|
|
static inline void rt_syscall_sleep_periodic(unsigned long last_wake_tick,
|
|
unsigned long period)
|
|
{
|
|
rt_syscall_2(RT_SYSCALL_SLEEP_PERIODIC, last_wake_tick, period);
|
|
}
|
|
|
|
static inline void rt_syscall_sem_wait(struct rt_sem *sem)
|
|
{
|
|
rt_syscall_1(RT_SYSCALL_SEM_WAIT, (uintptr_t)sem);
|
|
}
|
|
|
|
static inline bool rt_syscall_sem_timedwait(struct rt_sem *sem,
|
|
unsigned long ticks)
|
|
{
|
|
uintptr_t success = 1;
|
|
rt_syscall_3(RT_SYSCALL_SEM_TIMEDWAIT, (uintptr_t)sem, ticks,
|
|
(uintptr_t)&success);
|
|
return success;
|
|
}
|
|
|
|
static inline void rt_syscall_mutex_lock(struct rt_mutex *mutex)
|
|
{
|
|
rt_syscall_1(RT_SYSCALL_MUTEX_LOCK, (uintptr_t)mutex);
|
|
}
|
|
|
|
static inline bool rt_syscall_mutex_timedlock(struct rt_mutex *mutex,
|
|
unsigned long ticks)
|
|
{
|
|
uintptr_t success = 1;
|
|
rt_syscall_3(RT_SYSCALL_MUTEX_TIMEDLOCK, (uintptr_t)mutex, ticks,
|
|
(uintptr_t)&success);
|
|
return success;
|
|
}
|
|
|
|
static inline void rt_syscall_mutex_unlock(struct rt_mutex *mutex)
|
|
{
|
|
rt_syscall_1(RT_SYSCALL_MUTEX_UNLOCK, (uintptr_t)mutex);
|
|
}
|
|
|
|
static inline void rt_syscall_sem_post(struct rt_sem *sem, int n)
|
|
{
|
|
rt_syscall_2(RT_SYSCALL_SEM_POST, (uintptr_t)sem, (uintptr_t)n);
|
|
}
|
|
|
|
/* Enqueue a system call record. It will be processed in the pending syscall
|
|
* handler, triggered by rt_syscall_pend. */
|
|
void rt_syscall_push(struct rt_syscall_record *record);
|
|
|
|
/* Architecture-dependent trigger for the syscall handler that can only be
|
|
* called from an interrupt. If called from an interrupt, the syscall should
|
|
* run once no other interrupts are running, but before another task gets to
|
|
* run. */
|
|
void rt_syscall_pend(void);
|
|
|
|
/* Perform a single system call and return a new context to execute or NULL if
|
|
* no context switch is required. */
|
|
void *rt_syscall_run(enum rt_syscall syscall, uintptr_t arg0, uintptr_t arg1,
|
|
uintptr_t arg2);
|
|
|
|
/* Perform all pending system calls and return a new context to execute or NULL
|
|
* if no context switch is required. */
|
|
void *rt_syscall_run_pending(void);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|