rt/include/rt/syscall.h

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