#![allow(unused_variables)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(dead_code)]
use core::ffi::c_void;
use core::ptr;
use crate::config::*;
use crate::kernel::list::*;
use crate::port::*;
use crate::types::*;
pub const taskSCHEDULER_NOT_STARTED: BaseType_t = 0;
pub const taskSCHEDULER_RUNNING: BaseType_t = 1;
pub const taskSCHEDULER_SUSPENDED: BaseType_t = 2;
const taskNOT_WAITING_NOTIFICATION: u8 = 0;
const taskWAITING_NOTIFICATION: u8 = 1;
const taskNOTIFICATION_RECEIVED: u8 = 2;
const tskSTACK_FILL_BYTE: u8 = 0xa5;
const tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB: u8 = 0;
const tskSTATICALLY_ALLOCATED_STACK_ONLY: u8 = 1;
const tskSTATICALLY_ALLOCATED_STACK_AND_TCB: u8 = 2;
const tskRUNNING_CHAR: char = 'X';
const tskBLOCKED_CHAR: char = 'B';
const tskREADY_CHAR: char = 'R';
const tskDELETED_CHAR: char = 'D';
const tskSUSPENDED_CHAR: char = 'S';
const taskTASK_NOT_RUNNING: BaseType_t = -1;
const taskTASK_SCHEDULED_TO_YIELD: BaseType_t = -2;
const taskBITS_PER_BYTE: usize = 8;
#[cfg(feature = "tick-16bit")]
const taskEVENT_LIST_ITEM_VALUE_IN_USE: TickType_t = 0x8000;
#[cfg(all(not(feature = "tick-16bit"), not(feature = "tick-64bit")))]
const taskEVENT_LIST_ITEM_VALUE_IN_USE: TickType_t = 0x8000_0000;
#[cfg(feature = "tick-64bit")]
const taskEVENT_LIST_ITEM_VALUE_IN_USE: TickType_t = 0x8000_0000_0000_0000;
const configIDLE_TASK_NAME: &[u8] = b"IDLE\0";
const taskATTRIBUTE_IS_IDLE: UBaseType_t = 1 << 0;
#[repr(C)]
pub struct TimeOut_t {
pub xOverflowCount: BaseType_t,
pub xTimeOnEntering: TickType_t,
}
impl TimeOut_t {
pub const fn new() -> Self {
TimeOut_t {
xOverflowCount: 0,
xTimeOnEntering: 0,
}
}
}
impl Default for TimeOut_t {
fn default() -> Self {
Self::new()
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum eTaskState {
eRunning = 0,
eReady = 1,
eBlocked = 2,
eSuspended = 3,
eDeleted = 4,
eInvalid = 5,
}
#[repr(C)]
pub struct tskTaskControlBlock {
pub pxTopOfStack: *mut StackType_t,
pub xStateListItem: ListItem_t,
pub xEventListItem: ListItem_t,
pub uxPriority: UBaseType_t,
pub pxStack: *mut StackType_t,
pub pcTaskName: [u8; configMAX_TASK_NAME_LEN],
#[cfg(any(
not(feature = "arch-32bit"), // portSTACK_GROWTH > 0 check would go here
feature = "record-stack-high-address"
))]
pub pxEndOfStack: *mut StackType_t,
#[cfg(feature = "critical-nesting-in-tcb")]
pub uxCriticalNesting: UBaseType_t,
#[cfg(feature = "trace-facility")]
pub uxTCBNumber: UBaseType_t,
#[cfg(feature = "trace-facility")]
pub uxTaskNumber: UBaseType_t,
#[cfg(feature = "use-mutexes")]
pub uxBasePriority: UBaseType_t,
#[cfg(feature = "use-mutexes")]
pub uxMutexesHeld: UBaseType_t,
#[cfg(feature = "application-task-tag")]
pub pxTaskTag: Option<extern "C" fn(*mut c_void) -> BaseType_t>,
pub ulNotifiedValue: [u32; configTASK_NOTIFICATION_ARRAY_ENTRIES],
pub ucNotifyState: [u8; configTASK_NOTIFICATION_ARRAY_ENTRIES],
pub ucStaticallyAllocated: u8,
#[cfg(feature = "abort-delay")]
pub ucDelayAborted: u8,
#[cfg(feature = "posix-errno")]
pub iTaskErrno: i32,
#[cfg(feature = "thread-local-storage")]
pub pvThreadLocalStoragePointers: [*mut c_void; configNUM_THREAD_LOCAL_STORAGE_POINTERS],
#[cfg(feature = "generate-run-time-stats")]
pub ulRunTimeCounter: configRUN_TIME_COUNTER_TYPE,
}
pub type TCB_t = tskTaskControlBlock;
impl tskTaskControlBlock {
pub const fn new() -> Self {
tskTaskControlBlock {
pxTopOfStack: ptr::null_mut(),
xStateListItem: ListItem_t::new(),
xEventListItem: ListItem_t::new(),
uxPriority: 0,
pxStack: ptr::null_mut(),
pcTaskName: [0u8; configMAX_TASK_NAME_LEN],
#[cfg(any(not(feature = "arch-32bit"), feature = "record-stack-high-address"))]
pxEndOfStack: ptr::null_mut(),
#[cfg(feature = "critical-nesting-in-tcb")]
uxCriticalNesting: 0,
#[cfg(feature = "trace-facility")]
uxTCBNumber: 0,
#[cfg(feature = "trace-facility")]
uxTaskNumber: 0,
#[cfg(feature = "use-mutexes")]
uxBasePriority: 0,
#[cfg(feature = "use-mutexes")]
uxMutexesHeld: 0,
#[cfg(feature = "application-task-tag")]
pxTaskTag: None,
ulNotifiedValue: [0u32; configTASK_NOTIFICATION_ARRAY_ENTRIES],
ucNotifyState: [0u8; configTASK_NOTIFICATION_ARRAY_ENTRIES],
ucStaticallyAllocated: 0,
#[cfg(feature = "abort-delay")]
ucDelayAborted: 0,
#[cfg(feature = "posix-errno")]
iTaskErrno: 0,
#[cfg(feature = "thread-local-storage")]
pvThreadLocalStoragePointers: [ptr::null_mut();
configNUM_THREAD_LOCAL_STORAGE_POINTERS],
#[cfg(feature = "generate-run-time-stats")]
ulRunTimeCounter: 0,
}
}
}
#[repr(C)]
pub struct StaticTask_t {
_reserved: [u8; core::mem::size_of::<tskTaskControlBlock>()],
}
impl StaticTask_t {
pub const fn new() -> Self {
StaticTask_t {
_reserved: [0u8; core::mem::size_of::<tskTaskControlBlock>()],
}
}
}
#[no_mangle]
pub static mut pxCurrentTCB: *mut TCB_t = ptr::null_mut();
static mut pxReadyTasksLists: [List_t; configMAX_PRIORITIES as usize] =
[const { List_t::new() }; configMAX_PRIORITIES as usize];
static mut xDelayedTaskList1: List_t = List_t::new();
static mut xDelayedTaskList2: List_t = List_t::new();
static mut pxDelayedTaskList: *mut List_t = ptr::null_mut();
static mut pxOverflowDelayedTaskList: *mut List_t = ptr::null_mut();
static mut xPendingReadyList: List_t = List_t::new();
static mut xTasksWaitingTermination: List_t = List_t::new();
static mut uxDeletedTasksWaitingCleanUp: UBaseType_t = 0;
static mut xSuspendedTaskList: List_t = List_t::new();
static mut uxCurrentNumberOfTasks: UBaseType_t = 0;
static mut xTickCount: TickType_t = configINITIAL_TICK_COUNT;
static mut uxTopReadyPriority: UBaseType_t = tskIDLE_PRIORITY;
static mut xSchedulerRunning: BaseType_t = pdFALSE;
static mut xPendedTicks: TickType_t = 0;
static mut xYieldPendings: [BaseType_t; configNUMBER_OF_CORES as usize] =
[pdFALSE; configNUMBER_OF_CORES as usize];
static mut xNumOfOverflows: BaseType_t = 0;
static mut uxTaskNumber: UBaseType_t = 0;
static mut xNextTaskUnblockTime: TickType_t = 0;
static mut xIdleTaskHandles: [TaskHandle_t; configNUMBER_OF_CORES as usize] =
[ptr::null_mut(); configNUMBER_OF_CORES as usize];
static mut uxSchedulerSuspended: UBaseType_t = 0;
#[no_mangle]
static uxTopUsedPriority: UBaseType_t = configMAX_PRIORITIES - 1;
#[cfg(feature = "generate-run-time-stats")]
static mut ulTaskSwitchedInTime: configRUN_TIME_COUNTER_TYPE = 0;
#[cfg(feature = "generate-run-time-stats")]
static mut ulTotalRunTime: configRUN_TIME_COUNTER_TYPE = 0;
#[inline(always)]
unsafe fn taskRECORD_READY_PRIORITY(uxPriority: UBaseType_t) {
if uxPriority > uxTopReadyPriority {
uxTopReadyPriority = uxPriority;
}
}
#[inline(always)]
unsafe fn taskSELECT_HIGHEST_PRIORITY_TASK() {
let mut uxTopPriority: UBaseType_t = uxTopReadyPriority;
while listLIST_IS_EMPTY(&pxReadyTasksLists[uxTopPriority as usize]) != pdFALSE {
configASSERT(uxTopPriority > 0);
uxTopPriority -= 1;
}
pxCurrentTCB =
listGET_OWNER_OF_NEXT_ENTRY(&mut pxReadyTasksLists[uxTopPriority as usize]) as *mut TCB_t;
uxTopReadyPriority = uxTopPriority;
}
#[inline(always)]
unsafe fn taskRESET_READY_PRIORITY(_uxPriority: UBaseType_t) {
}
#[inline(always)]
unsafe fn taskSWITCH_DELAYED_LISTS() {
configASSERT(listLIST_IS_EMPTY(pxDelayedTaskList) != pdFALSE);
let pxTemp = pxDelayedTaskList;
pxDelayedTaskList = pxOverflowDelayedTaskList;
pxOverflowDelayedTaskList = pxTemp;
xNumOfOverflows += 1;
prvResetNextTaskUnblockTime();
}
#[inline(always)]
unsafe fn prvAddTaskToReadyList(pxTCB: *mut TCB_t) {
crate::trace::traceMOVED_TASK_TO_READY_STATE(pxTCB as *mut c_void);
taskRECORD_READY_PRIORITY((*pxTCB).uxPriority);
vListInsertEnd(
&mut pxReadyTasksLists[(*pxTCB).uxPriority as usize],
&mut (*pxTCB).xStateListItem,
);
crate::trace::tracePOST_MOVED_TASK_TO_READY_STATE(pxTCB as *mut c_void);
}
#[inline(always)]
unsafe fn prvGetTCBFromHandle(pxHandle: TaskHandle_t) -> *mut TCB_t {
if pxHandle.is_null() {
pxCurrentTCB
} else {
pxHandle as *mut TCB_t
}
}
#[inline(always)]
pub fn portYIELD_WITHIN_API() {
if configUSE_PREEMPTION != 0 {
portYIELD();
}
}
#[inline(always)]
unsafe fn taskYIELD_ANY_CORE_IF_USING_PREEMPTION(pxTCB: *mut TCB_t) {
if configUSE_PREEMPTION != 0 {
if !pxCurrentTCB.is_null() && (*pxCurrentTCB).uxPriority < (*pxTCB).uxPriority {
portYIELD_WITHIN_API();
}
}
}
unsafe fn prvInitialiseTaskLists() {
for uxPriority in 0..configMAX_PRIORITIES as usize {
vListInitialise(&mut pxReadyTasksLists[uxPriority]);
}
vListInitialise(&mut xDelayedTaskList1);
vListInitialise(&mut xDelayedTaskList2);
vListInitialise(&mut xPendingReadyList);
vListInitialise(&mut xTasksWaitingTermination);
vListInitialise(&mut xSuspendedTaskList);
pxDelayedTaskList = &mut xDelayedTaskList1;
pxOverflowDelayedTaskList = &mut xDelayedTaskList2;
}
unsafe fn prvResetNextTaskUnblockTime() {
if listLIST_IS_EMPTY(pxDelayedTaskList) != pdFALSE {
xNextTaskUnblockTime = portMAX_DELAY;
} else {
let pxTCB = listGET_OWNER_OF_HEAD_ENTRY(pxDelayedTaskList) as *mut TCB_t;
xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE(&(*pxTCB).xStateListItem);
}
}
unsafe fn prvAddNewTaskToReadyList(pxNewTCB: *mut TCB_t) {
taskENTER_CRITICAL();
{
uxCurrentNumberOfTasks += 1;
if pxCurrentTCB.is_null() {
pxCurrentTCB = pxNewTCB;
if uxCurrentNumberOfTasks == 1 {
prvInitialiseTaskLists();
}
} else {
if xSchedulerRunning == pdFALSE {
if (*pxCurrentTCB).uxPriority <= (*pxNewTCB).uxPriority {
pxCurrentTCB = pxNewTCB;
}
}
}
uxTaskNumber += 1;
#[cfg(feature = "trace-facility")]
{
(*pxNewTCB).uxTCBNumber = uxTaskNumber;
}
crate::trace::traceTASK_CREATE(pxNewTCB as *mut c_void);
prvAddTaskToReadyList(pxNewTCB);
}
taskEXIT_CRITICAL();
if xSchedulerRunning != pdFALSE {
if (*pxCurrentTCB).uxPriority < (*pxNewTCB).uxPriority {
portYIELD_WITHIN_API();
}
}
}
unsafe fn prvInitialiseNewTask(
pxTaskCode: TaskFunction_t,
pcName: *const u8,
uxStackDepth: configSTACK_DEPTH_TYPE,
pvParameters: *mut c_void,
uxPriority: UBaseType_t,
pxCreatedTask: *mut TaskHandle_t,
pxNewTCB: *mut TCB_t,
pxTopOfStack: *mut StackType_t,
) {
if !pcName.is_null() {
let mut i = 0usize;
while i < configMAX_TASK_NAME_LEN - 1 {
let c = *pcName.add(i);
(*pxNewTCB).pcTaskName[i] = c;
if c == 0 {
break;
}
i += 1;
}
(*pxNewTCB).pcTaskName[configMAX_TASK_NAME_LEN - 1] = 0;
} else {
(*pxNewTCB).pcTaskName[0] = 0;
}
let mut uxPriority = uxPriority;
if uxPriority >= configMAX_PRIORITIES {
uxPriority = configMAX_PRIORITIES - 1;
}
(*pxNewTCB).uxPriority = uxPriority;
#[cfg(feature = "use-mutexes")]
{
(*pxNewTCB).uxBasePriority = uxPriority;
(*pxNewTCB).uxMutexesHeld = 0;
}
vListInitialiseItem(&mut (*pxNewTCB).xStateListItem);
vListInitialiseItem(&mut (*pxNewTCB).xEventListItem);
listSET_LIST_ITEM_OWNER(&mut (*pxNewTCB).xStateListItem, pxNewTCB as *mut c_void);
listSET_LIST_ITEM_VALUE(
&mut (*pxNewTCB).xEventListItem,
(configMAX_PRIORITIES - 1 - uxPriority) as TickType_t,
);
listSET_LIST_ITEM_OWNER(&mut (*pxNewTCB).xEventListItem, pxNewTCB as *mut c_void);
for i in 0..configTASK_NOTIFICATION_ARRAY_ENTRIES {
(*pxNewTCB).ulNotifiedValue[i] = 0;
(*pxNewTCB).ucNotifyState[i] = taskNOT_WAITING_NOTIFICATION;
}
#[cfg(feature = "critical-nesting-in-tcb")]
{
(*pxNewTCB).uxCriticalNesting = 0;
}
#[cfg(feature = "application-task-tag")]
{
(*pxNewTCB).pxTaskTag = None;
}
#[cfg(feature = "abort-delay")]
{
(*pxNewTCB).ucDelayAborted = pdFALSE as u8;
}
(*pxNewTCB).pxTopOfStack = pxPortInitialiseStack(pxTopOfStack, pxTaskCode, pvParameters);
if !pxCreatedTask.is_null() {
*pxCreatedTask = pxNewTCB as TaskHandle_t;
}
}
unsafe fn prvAddCurrentTaskToDelayedList(
xTicksToWait: TickType_t,
xCanBlockIndefinitely: BaseType_t,
) {
let xConstTickCount = xTickCount;
let _ux = uxListRemove(&mut (*pxCurrentTCB).xStateListItem);
if xTicksToWait == portMAX_DELAY && xCanBlockIndefinitely != pdFALSE {
vListInsertEnd(&mut xSuspendedTaskList, &mut (*pxCurrentTCB).xStateListItem);
} else {
let xTimeToWake = xConstTickCount.wrapping_add(xTicksToWait);
listSET_LIST_ITEM_VALUE(&mut (*pxCurrentTCB).xStateListItem, xTimeToWake);
if xTimeToWake < xConstTickCount {
vListInsert(
pxOverflowDelayedTaskList,
&mut (*pxCurrentTCB).xStateListItem,
);
} else {
vListInsert(pxDelayedTaskList, &mut (*pxCurrentTCB).xStateListItem);
if xTimeToWake < xNextTaskUnblockTime {
xNextTaskUnblockTime = xTimeToWake;
}
}
}
}
unsafe fn prvCheckTasksWaitingTermination() {
#[cfg(feature = "task-delete")]
{
taskENTER_CRITICAL();
{
while uxDeletedTasksWaitingCleanUp > 0 {
let pxTCB = listGET_OWNER_OF_HEAD_ENTRY(&xTasksWaitingTermination) as *mut TCB_t;
let _ux = uxListRemove(&mut (*pxTCB).xStateListItem);
uxCurrentNumberOfTasks -= 1;
uxDeletedTasksWaitingCleanUp -= 1;
taskEXIT_CRITICAL();
prvDeleteTCB(pxTCB);
taskENTER_CRITICAL();
}
}
taskEXIT_CRITICAL();
}
}
#[cfg(feature = "task-delete")]
unsafe fn prvDeleteTCB(pxTCB: *mut TCB_t) {
if (*pxTCB).ucStaticallyAllocated == tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB {
crate::memory::vPortFree((*pxTCB).pxStack as *mut c_void);
crate::memory::vPortFree(pxTCB as *mut c_void);
} else if (*pxTCB).ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_ONLY {
crate::memory::vPortFree(pxTCB as *mut c_void);
}
}
extern "C" fn prvIdleTask(_pvParameters: *mut c_void) {
loop {
unsafe {
prvCheckTasksWaitingTermination();
}
if configUSE_IDLE_HOOK != 0 {
}
#[cfg(feature = "tickless-idle")]
{
let xExpectedIdleTime = prvGetExpectedIdleTime();
if xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP {
vTaskSuspendAll();
{
unsafe {
configASSERT(xNextTaskUnblockTime >= xTickCount);
}
let xExpectedIdleTime = prvGetExpectedIdleTime();
if xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP {
crate::trace::traceLOW_POWER_IDLE_BEGIN();
crate::port::vPortSuppressTicksAndSleep(xExpectedIdleTime);
crate::trace::traceLOW_POWER_IDLE_END();
}
}
xTaskResumeAll();
}
}
#[cfg(feature = "idle-yield")]
{
portYIELD_WITHIN_API();
}
}
}
unsafe fn prvCreateIdleTasks() -> BaseType_t {
let xReturn: BaseType_t;
#[cfg(any(feature = "alloc", feature = "heap-4", feature = "heap-5"))]
{
xReturn = xTaskCreate(
prvIdleTask,
configIDLE_TASK_NAME.as_ptr(),
configMINIMAL_STACK_SIZE,
ptr::null_mut(),
tskIDLE_PRIORITY,
&mut xIdleTaskHandles[0],
);
}
#[cfg(not(any(feature = "alloc", feature = "heap-4", feature = "heap-5")))]
{
xReturn = pdFAIL;
}
xReturn
}
#[cfg(any(feature = "alloc", feature = "heap-4", feature = "heap-5"))]
pub unsafe fn xTaskCreate(
pxTaskCode: TaskFunction_t,
pcName: *const u8,
uxStackDepth: configSTACK_DEPTH_TYPE,
pvParameters: *mut c_void,
uxPriority: UBaseType_t,
pxCreatedTask: *mut TaskHandle_t,
) -> BaseType_t {
let xReturn: BaseType_t;
let pxNewTCB = crate::memory::pvPortMalloc(core::mem::size_of::<TCB_t>()) as *mut TCB_t;
if !pxNewTCB.is_null() {
let pxStack =
crate::memory::pvPortMalloc(uxStackDepth * core::mem::size_of::<StackType_t>())
as *mut StackType_t;
if !pxStack.is_null() {
(*pxNewTCB).pxStack = pxStack;
let pxTopOfStack: *mut StackType_t;
if portSTACK_GROWTH < 0 {
pxTopOfStack = pxStack.add(uxStackDepth - 1);
let aligned = (pxTopOfStack as usize) & !(portBYTE_ALIGNMENT - 1);
let pxTopOfStack = aligned as *mut StackType_t;
#[cfg(any(not(feature = "arch-32bit"), feature = "record-stack-high-address"))]
{
(*pxNewTCB).pxEndOfStack = pxStack.add(uxStackDepth - 1);
}
} else {
pxTopOfStack = pxStack;
#[cfg(any(not(feature = "arch-32bit"), feature = "record-stack-high-address"))]
{
(*pxNewTCB).pxEndOfStack = pxStack.add(uxStackDepth - 1);
}
}
if tskSET_NEW_STACKS_TO_KNOWN_VALUE != 0 {
ptr::write_bytes(
pxStack as *mut u8,
tskSTACK_FILL_BYTE,
uxStackDepth * core::mem::size_of::<StackType_t>(),
);
}
(*pxNewTCB).ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB;
prvInitialiseNewTask(
pxTaskCode,
pcName,
uxStackDepth,
pvParameters,
uxPriority,
pxCreatedTask,
pxNewTCB,
pxTopOfStack,
);
prvAddNewTaskToReadyList(pxNewTCB);
xReturn = pdPASS;
} else {
crate::memory::vPortFree(pxNewTCB as *mut c_void);
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
}
} else {
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
}
xReturn
}
pub unsafe fn xTaskCreateStatic(
pxTaskCode: TaskFunction_t,
pcName: *const u8,
uxStackDepth: configSTACK_DEPTH_TYPE,
pvParameters: *mut c_void,
uxPriority: UBaseType_t,
puxStackBuffer: *mut StackType_t,
pxTaskBuffer: *mut StaticTask_t,
) -> TaskHandle_t {
let mut xReturn: TaskHandle_t = ptr::null_mut();
if !puxStackBuffer.is_null() && !pxTaskBuffer.is_null() {
let pxNewTCB = pxTaskBuffer as *mut TCB_t;
ptr::write_bytes(pxNewTCB, 0, 1);
(*pxNewTCB).pxStack = puxStackBuffer;
let pxTopOfStack: *mut StackType_t;
if portSTACK_GROWTH < 0 {
let pxTop = puxStackBuffer.add(uxStackDepth - 1);
let aligned = (pxTop as usize) & !(portBYTE_ALIGNMENT - 1);
pxTopOfStack = aligned as *mut StackType_t;
#[cfg(any(not(feature = "arch-32bit"), feature = "record-stack-high-address"))]
{
(*pxNewTCB).pxEndOfStack = puxStackBuffer.add(uxStackDepth - 1);
}
} else {
pxTopOfStack = puxStackBuffer;
#[cfg(any(not(feature = "arch-32bit"), feature = "record-stack-high-address"))]
{
(*pxNewTCB).pxEndOfStack = puxStackBuffer.add(uxStackDepth - 1);
}
}
if tskSET_NEW_STACKS_TO_KNOWN_VALUE != 0 {
ptr::write_bytes(
puxStackBuffer as *mut u8,
tskSTACK_FILL_BYTE,
uxStackDepth * core::mem::size_of::<StackType_t>(),
);
}
(*pxNewTCB).ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB;
prvInitialiseNewTask(
pxTaskCode,
pcName,
uxStackDepth,
pvParameters,
uxPriority,
&mut xReturn,
pxNewTCB,
pxTopOfStack,
);
prvAddNewTaskToReadyList(pxNewTCB);
}
xReturn
}
pub fn vTaskStartScheduler() {
unsafe {
let xReturn = prvCreateIdleTasks();
if xReturn == pdPASS {
#[cfg(feature = "timers")]
{
crate::kernel::timers::xTimerCreateTimerTask();
}
portDISABLE_INTERRUPTS();
xNextTaskUnblockTime = portMAX_DELAY;
xSchedulerRunning = pdTRUE;
xTickCount = 0;
if configINITIAL_TICK_COUNT != 0 {
xTickCount = configINITIAL_TICK_COUNT;
}
crate::trace::traceTASK_SWITCHED_IN();
xPortStartScheduler();
} else {
configASSERT(xReturn == pdPASS);
}
}
}
pub fn vTaskEndScheduler() {
unsafe {
portDISABLE_INTERRUPTS();
xSchedulerRunning = pdFALSE;
vPortEndScheduler();
}
}
pub fn vTaskSuspendAll() {
unsafe {
portDISABLE_INTERRUPTS();
uxSchedulerSuspended += 1;
portENABLE_INTERRUPTS();
}
}
pub fn xTaskResumeAll() -> BaseType_t {
let mut xAlreadyYielded = pdFALSE;
unsafe {
configASSERT(uxSchedulerSuspended > 0);
taskENTER_CRITICAL();
{
uxSchedulerSuspended -= 1;
if uxSchedulerSuspended == 0 {
if uxCurrentNumberOfTasks > 0 {
while listLIST_IS_EMPTY(&xPendingReadyList) == pdFALSE {
let pxTCB = listGET_OWNER_OF_HEAD_ENTRY(&xPendingReadyList) as *mut TCB_t;
let _ux = uxListRemove(&mut (*pxTCB).xEventListItem);
let _ux = uxListRemove(&mut (*pxTCB).xStateListItem);
prvAddTaskToReadyList(pxTCB);
if (*pxTCB).uxPriority >= (*pxCurrentTCB).uxPriority {
xYieldPendings[0] = pdTRUE;
}
}
if xPendedTicks > 0 {
while xPendedTicks > 0 {
if xTaskIncrementTick() != pdFALSE {
xYieldPendings[0] = pdTRUE;
}
xPendedTicks -= 1;
}
}
if xYieldPendings[0] != pdFALSE {
xAlreadyYielded = pdTRUE;
portYIELD_WITHIN_API();
}
}
}
}
taskEXIT_CRITICAL();
}
xAlreadyYielded
}
pub fn vTaskDelay(xTicksToDelay: TickType_t) {
if xTicksToDelay > 0 {
unsafe {
configASSERT(uxSchedulerSuspended == 0);
vTaskSuspendAll();
{
crate::trace::traceTASK_DELAY();
prvAddCurrentTaskToDelayedList(xTicksToDelay, pdFALSE);
}
xTaskResumeAll();
}
}
portYIELD_WITHIN_API();
}
pub fn xTaskDelayUntil(
pxPreviousWakeTime: *mut TickType_t,
xTimeIncrement: TickType_t,
) -> BaseType_t {
let mut xShouldDelay = pdFALSE;
unsafe {
configASSERT(!pxPreviousWakeTime.is_null());
configASSERT(xTimeIncrement > 0);
configASSERT(uxSchedulerSuspended == 0);
vTaskSuspendAll();
{
let xConstTickCount = xTickCount;
let xTimeToWake = (*pxPreviousWakeTime).wrapping_add(xTimeIncrement);
if xConstTickCount < *pxPreviousWakeTime {
if xTimeToWake < *pxPreviousWakeTime && xTimeToWake > xConstTickCount {
xShouldDelay = pdTRUE;
}
} else {
if xTimeToWake < *pxPreviousWakeTime || xTimeToWake > xConstTickCount {
xShouldDelay = pdTRUE;
}
}
*pxPreviousWakeTime = xTimeToWake;
if xShouldDelay != pdFALSE {
crate::trace::traceTASK_DELAY_UNTIL(xTimeToWake);
prvAddCurrentTaskToDelayedList(xTimeToWake.wrapping_sub(xConstTickCount), pdFALSE);
}
}
xTaskResumeAll();
}
xShouldDelay
}
pub fn xTaskGetSchedulerState() -> BaseType_t {
unsafe {
if xSchedulerRunning == pdFALSE {
taskSCHEDULER_NOT_STARTED
} else if uxSchedulerSuspended == 0 {
taskSCHEDULER_RUNNING
} else {
taskSCHEDULER_SUSPENDED
}
}
}
pub fn xTaskGetCurrentTaskHandle() -> TaskHandle_t {
unsafe { pxCurrentTCB as TaskHandle_t }
}
#[cfg(feature = "use-mutexes")]
pub fn pvTaskIncrementMutexHeldCount() {
unsafe {
if !pxCurrentTCB.is_null() {
(*pxCurrentTCB).uxMutexesHeld += 1;
}
}
}
pub fn uxTaskGetNumberOfTasks() -> UBaseType_t {
unsafe { uxCurrentNumberOfTasks }
}
pub fn xTaskGetTickCount() -> TickType_t {
unsafe { xTickCount }
}
pub fn xTaskGetTickCountFromISR() -> TickType_t {
unsafe { xTickCount }
}
pub unsafe fn xTaskRemoveFromEventList(pxEventList: *const List_t) -> BaseType_t {
let pxUnblockedTCB = listGET_OWNER_OF_HEAD_ENTRY(pxEventList) as *mut TCB_t;
configASSERT(!pxUnblockedTCB.is_null());
let _ux = uxListRemove(&mut (*pxUnblockedTCB).xEventListItem);
if uxSchedulerSuspended == 0 {
let _ux = uxListRemove(&mut (*pxUnblockedTCB).xStateListItem);
prvAddTaskToReadyList(pxUnblockedTCB);
listSET_LIST_ITEM_VALUE(
&mut (*pxUnblockedTCB).xEventListItem,
(configMAX_PRIORITIES - 1 - (*pxUnblockedTCB).uxPriority) as TickType_t,
);
} else {
vListInsertEnd(
&mut xPendingReadyList,
&mut (*pxUnblockedTCB).xEventListItem,
);
}
if (*pxUnblockedTCB).uxPriority > (*pxCurrentTCB).uxPriority {
pdTRUE
} else {
pdFALSE
}
}
pub unsafe fn vTaskPlaceOnEventList(pxEventList: *mut List_t, xTicksToWait: TickType_t) {
configASSERT(!pxEventList.is_null());
vListInsert(pxEventList, &mut (*pxCurrentTCB).xEventListItem);
prvAddCurrentTaskToDelayedList(xTicksToWait, pdTRUE);
}
pub unsafe fn vTaskPlaceOnEventListRestricted(
pxEventList: *mut List_t,
xTicksToWait: TickType_t,
xWaitIndefinitely: BaseType_t,
) {
configASSERT(!pxEventList.is_null());
vListInsertEnd(pxEventList, &mut (*pxCurrentTCB).xEventListItem);
prvAddCurrentTaskToDelayedList(xTicksToWait, xWaitIndefinitely);
}
pub unsafe fn vTaskPlaceOnUnorderedEventList(
pxEventList: *mut List_t,
xItemValue: TickType_t,
xTicksToWait: TickType_t,
) {
configASSERT(!pxEventList.is_null());
listSET_LIST_ITEM_VALUE(
&mut (*pxCurrentTCB).xEventListItem,
xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE,
);
vListInsertEnd(pxEventList, &mut (*pxCurrentTCB).xEventListItem);
prvAddCurrentTaskToDelayedList(xTicksToWait, pdTRUE);
}
pub unsafe fn xTaskRemoveFromUnorderedEventList(
pxEventListItem: *mut ListItem_t,
xItemValue: TickType_t,
) -> BaseType_t {
listSET_LIST_ITEM_VALUE(pxEventListItem, xItemValue);
let pxUnblockedTCB = listGET_LIST_ITEM_OWNER(pxEventListItem) as *mut TCB_t;
configASSERT(!pxUnblockedTCB.is_null());
let _ux = uxListRemove(pxEventListItem);
if uxSchedulerSuspended == 0 {
let _ux = uxListRemove(&mut (*pxUnblockedTCB).xStateListItem);
prvAddTaskToReadyList(pxUnblockedTCB);
} else {
vListInsertEnd(
&mut xPendingReadyList,
&mut (*pxUnblockedTCB).xEventListItem,
);
}
if (*pxUnblockedTCB).uxPriority > (*pxCurrentTCB).uxPriority {
pdTRUE
} else {
pdFALSE
}
}
pub fn uxTaskResetEventItemValue() -> TickType_t {
unsafe {
let pxCurrentTCBLocal = pxCurrentTCB;
let uxReturn = listGET_LIST_ITEM_VALUE(&(*pxCurrentTCBLocal).xEventListItem);
listSET_LIST_ITEM_VALUE(
&mut (*pxCurrentTCBLocal).xEventListItem,
(configMAX_PRIORITIES as TickType_t)
.wrapping_sub((*pxCurrentTCBLocal).uxPriority as TickType_t),
);
uxReturn
}
}
pub fn vTaskSetTimeOutState(pxTimeOut: *mut TimeOut_t) {
unsafe {
configASSERT(!pxTimeOut.is_null());
taskENTER_CRITICAL();
{
(*pxTimeOut).xOverflowCount = xNumOfOverflows;
(*pxTimeOut).xTimeOnEntering = xTickCount;
}
taskEXIT_CRITICAL();
}
}
pub fn vTaskInternalSetTimeOutState(pxTimeOut: *mut TimeOut_t) {
unsafe {
(*pxTimeOut).xOverflowCount = xNumOfOverflows;
(*pxTimeOut).xTimeOnEntering = xTickCount;
}
}
pub fn xTaskCheckForTimeOut(
pxTimeOut: *mut TimeOut_t,
pxTicksToWait: *mut TickType_t,
) -> BaseType_t {
let xReturn: BaseType_t;
unsafe {
configASSERT(!pxTimeOut.is_null());
configASSERT(!pxTicksToWait.is_null());
taskENTER_CRITICAL();
{
let xConstTickCount = xTickCount;
let xElapsedTime = xConstTickCount.wrapping_sub((*pxTimeOut).xTimeOnEntering);
#[cfg(feature = "abort-delay")]
{
if (*pxCurrentTCB).ucDelayAborted != (pdFALSE as u8) {
(*pxCurrentTCB).ucDelayAborted = pdFALSE as u8;
xReturn = pdTRUE;
taskEXIT_CRITICAL();
return xReturn;
}
}
if *pxTicksToWait == portMAX_DELAY {
xReturn = pdFALSE;
} else if xNumOfOverflows != (*pxTimeOut).xOverflowCount
&& xConstTickCount >= (*pxTimeOut).xTimeOnEntering
{
xReturn = pdTRUE;
*pxTicksToWait = 0;
} else if xElapsedTime < *pxTicksToWait {
*pxTicksToWait -= xElapsedTime;
vTaskInternalSetTimeOutState(pxTimeOut);
xReturn = pdFALSE;
} else {
*pxTicksToWait = 0;
xReturn = pdTRUE;
}
}
taskEXIT_CRITICAL();
}
xReturn
}
pub fn vTaskPriorityInherit(pxMutexHolder: TaskHandle_t) {
#[cfg(feature = "use-mutexes")]
unsafe {
if !pxMutexHolder.is_null() {
let pxMutexHolderTCB = pxMutexHolder as *mut TCB_t;
if (*pxMutexHolderTCB).uxPriority < (*pxCurrentTCB).uxPriority {
if (listGET_LIST_ITEM_VALUE(&(*pxMutexHolderTCB).xEventListItem)
& taskEVENT_LIST_ITEM_VALUE_IN_USE)
== 0
{
listSET_LIST_ITEM_VALUE(
&mut (*pxMutexHolderTCB).xEventListItem,
(configMAX_PRIORITIES - 1 - (*pxCurrentTCB).uxPriority) as TickType_t,
);
}
if listIS_CONTAINED_WITHIN(
&pxReadyTasksLists[(*pxMutexHolderTCB).uxPriority as usize],
&(*pxMutexHolderTCB).xStateListItem,
) != pdFALSE
{
let _ux = uxListRemove(&mut (*pxMutexHolderTCB).xStateListItem);
(*pxMutexHolderTCB).uxPriority = (*pxCurrentTCB).uxPriority;
prvAddTaskToReadyList(pxMutexHolderTCB);
} else {
(*pxMutexHolderTCB).uxPriority = (*pxCurrentTCB).uxPriority;
}
crate::trace::traceTASK_PRIORITY_INHERIT(
pxMutexHolderTCB as *mut c_void,
(*pxCurrentTCB).uxPriority,
);
}
}
}
#[cfg(not(feature = "use-mutexes"))]
{
let _ = pxMutexHolder;
}
}
pub fn xTaskPriorityDisinherit(pxMutexHolder: TaskHandle_t) -> BaseType_t {
#[cfg(feature = "use-mutexes")]
unsafe {
if !pxMutexHolder.is_null() {
let pxTCB = pxMutexHolder as *mut TCB_t;
configASSERT((*pxTCB).uxMutexesHeld > 0);
(*pxTCB).uxMutexesHeld -= 1;
if (*pxTCB).uxPriority != (*pxTCB).uxBasePriority {
if (*pxTCB).uxMutexesHeld == 0 {
let _ux = uxListRemove(&mut (*pxTCB).xStateListItem);
(*pxTCB).uxPriority = (*pxTCB).uxBasePriority;
listSET_LIST_ITEM_VALUE(
&mut (*pxTCB).xEventListItem,
(configMAX_PRIORITIES - 1 - (*pxTCB).uxPriority) as TickType_t,
);
prvAddTaskToReadyList(pxTCB);
crate::trace::traceTASK_PRIORITY_DISINHERIT(
pxTCB as *mut c_void,
(*pxTCB).uxBasePriority,
);
return pdTRUE;
}
}
}
pdFALSE
}
#[cfg(not(feature = "use-mutexes"))]
{
let _ = pxMutexHolder;
pdFALSE
}
}
pub fn vTaskPriorityDisinheritAfterTimeout(
pxMutexHolder: TaskHandle_t,
uxHighestPriorityWaitingTask: UBaseType_t,
) {
#[cfg(feature = "use-mutexes")]
unsafe {
if !pxMutexHolder.is_null() {
let pxTCB = pxMutexHolder as *mut TCB_t;
if (*pxTCB).uxPriority != (*pxTCB).uxBasePriority {
let uxPriorityToUse = if (*pxTCB).uxBasePriority > uxHighestPriorityWaitingTask {
(*pxTCB).uxBasePriority
} else {
uxHighestPriorityWaitingTask
};
if uxPriorityToUse != (*pxTCB).uxPriority {
if listIS_CONTAINED_WITHIN(
&pxReadyTasksLists[(*pxTCB).uxPriority as usize],
&(*pxTCB).xStateListItem,
) != pdFALSE
{
let _ux = uxListRemove(&mut (*pxTCB).xStateListItem);
(*pxTCB).uxPriority = uxPriorityToUse;
prvAddTaskToReadyList(pxTCB);
} else {
(*pxTCB).uxPriority = uxPriorityToUse;
}
}
}
}
}
#[cfg(not(feature = "use-mutexes"))]
{
let _ = pxMutexHolder;
let _ = uxHighestPriorityWaitingTask;
}
}
pub fn vTaskMissedYield() {
unsafe {
xYieldPendings[0] = pdTRUE;
}
}
#[no_mangle]
pub extern "C" fn xTaskIncrementTick() -> BaseType_t {
let mut xSwitchRequired = pdFALSE;
unsafe {
if uxSchedulerSuspended == 0 {
let xConstTickCount = xTickCount.wrapping_add(1);
xTickCount = xConstTickCount;
if xConstTickCount == 0 {
taskSWITCH_DELAYED_LISTS();
}
if xConstTickCount >= xNextTaskUnblockTime {
loop {
if listLIST_IS_EMPTY(pxDelayedTaskList) != pdFALSE {
xNextTaskUnblockTime = portMAX_DELAY;
break;
} else {
let pxTCB = listGET_OWNER_OF_HEAD_ENTRY(pxDelayedTaskList) as *mut TCB_t;
let xItemValue = listGET_LIST_ITEM_VALUE(&(*pxTCB).xStateListItem);
if xConstTickCount < xItemValue {
xNextTaskUnblockTime = xItemValue;
break;
}
let _ux = uxListRemove(&mut (*pxTCB).xStateListItem);
if listLIST_ITEM_CONTAINER(&(*pxTCB).xEventListItem) != ptr::null_mut() {
let _ux = uxListRemove(&mut (*pxTCB).xEventListItem);
}
prvAddTaskToReadyList(pxTCB);
if configUSE_PREEMPTION != 0 {
if (*pxTCB).uxPriority >= (*pxCurrentTCB).uxPriority {
xSwitchRequired = pdTRUE;
}
}
}
}
}
if configUSE_PREEMPTION != 0 {
if listCURRENT_LIST_LENGTH(&pxReadyTasksLists[(*pxCurrentTCB).uxPriority as usize])
> 1
{
xSwitchRequired = pdTRUE;
}
}
if configUSE_TICK_HOOK != 0 {
}
if xYieldPendings[0] != pdFALSE {
xSwitchRequired = pdTRUE;
}
} else {
xPendedTicks += 1;
if configUSE_TICK_HOOK != 0 {
}
}
}
xSwitchRequired
}
#[no_mangle]
pub extern "C" fn vTaskSwitchContext() {
unsafe {
if uxSchedulerSuspended != 0 {
xYieldPendings[0] = pdTRUE;
return;
}
xYieldPendings[0] = pdFALSE;
crate::trace::traceTASK_SWITCHED_OUT();
#[cfg(feature = "stack-overflow-check")]
{
}
#[cfg(feature = "generate-run-time-stats")]
{
ulTotalRunTime = crate::port::portGET_RUN_TIME_COUNTER_VALUE();
if ulTotalRunTime > ulTaskSwitchedInTime {
if !pxCurrentTCB.is_null() {
(*pxCurrentTCB).ulRunTimeCounter += ulTotalRunTime - ulTaskSwitchedInTime;
}
}
ulTaskSwitchedInTime = ulTotalRunTime;
}
taskSELECT_HIGHEST_PRIORITY_TASK();
crate::trace::traceTASK_SWITCHED_IN();
}
}
#[inline(always)]
pub fn vTaskYieldWithinAPI() {
portYIELD();
}
#[cfg(feature = "task-delete")]
pub fn vTaskDelete(xTaskToDelete: TaskHandle_t) {
unsafe {
let mut xDeleteTCBInIdleTask: BaseType_t = pdFALSE;
taskENTER_CRITICAL();
{
let pxTCB = prvGetTCBFromHandle(xTaskToDelete);
configASSERT(!pxTCB.is_null());
if uxListRemove(&mut (*pxTCB).xStateListItem) == 0 {
taskRESET_READY_PRIORITY((*pxTCB).uxPriority);
}
if !listLIST_ITEM_CONTAINER(&(*pxTCB).xEventListItem).is_null() {
uxListRemove(&mut (*pxTCB).xEventListItem);
}
uxTaskNumber += 1;
let xTaskIsRunning = pxTCB == pxCurrentTCB;
if xSchedulerRunning != pdFALSE && xTaskIsRunning {
vListInsertEnd(&mut xTasksWaitingTermination, &mut (*pxTCB).xStateListItem);
uxDeletedTasksWaitingCleanUp += 1;
crate::trace::traceTASK_DELETE(pxTCB as *mut c_void);
xDeleteTCBInIdleTask = pdTRUE;
xYieldPendings[0] = pdTRUE;
} else {
uxCurrentNumberOfTasks -= 1;
crate::trace::traceTASK_DELETE(pxTCB as *mut c_void);
prvResetNextTaskUnblockTime();
}
}
taskEXIT_CRITICAL();
if xDeleteTCBInIdleTask != pdTRUE {
prvDeleteTCB(prvGetTCBFromHandle(xTaskToDelete));
}
if xSchedulerRunning != pdFALSE {
let pxTCB = prvGetTCBFromHandle(xTaskToDelete);
if pxTCB == pxCurrentTCB {
configASSERT(uxSchedulerSuspended == 0);
portYIELD_WITHIN_API();
}
}
}
}
#[cfg(feature = "task-suspend")]
pub fn vTaskSuspend(xTaskToSuspend: TaskHandle_t) {
unsafe {
taskENTER_CRITICAL();
{
let pxTCB = prvGetTCBFromHandle(xTaskToSuspend);
crate::trace::traceTASK_SUSPEND(pxTCB as *mut c_void);
let _ux = uxListRemove(&mut (*pxTCB).xStateListItem);
if listLIST_ITEM_CONTAINER(&(*pxTCB).xEventListItem) != ptr::null_mut() {
let _ux = uxListRemove(&mut (*pxTCB).xEventListItem);
}
vListInsertEnd(&mut xSuspendedTaskList, &mut (*pxTCB).xStateListItem);
for i in 0..configTASK_NOTIFICATION_ARRAY_ENTRIES {
if (*pxTCB).ucNotifyState[i] == taskWAITING_NOTIFICATION {
(*pxTCB).ucNotifyState[i] = taskNOT_WAITING_NOTIFICATION;
}
}
}
taskEXIT_CRITICAL();
if xSchedulerRunning != pdFALSE {
taskENTER_CRITICAL();
{
prvResetNextTaskUnblockTime();
}
taskEXIT_CRITICAL();
}
let pxTCB = prvGetTCBFromHandle(xTaskToSuspend);
if pxTCB == pxCurrentTCB {
if xSchedulerRunning != pdFALSE {
portYIELD_WITHIN_API();
} else {
if listCURRENT_LIST_LENGTH(&xSuspendedTaskList) == uxCurrentNumberOfTasks {
pxCurrentTCB = ptr::null_mut();
} else {
vTaskSwitchContext();
}
}
}
}
}
#[cfg(feature = "task-suspend")]
pub fn vTaskResume(xTaskToResume: TaskHandle_t) {
unsafe {
let pxTCB = xTaskToResume as *mut TCB_t;
if !pxTCB.is_null() && pxTCB != pxCurrentTCB {
taskENTER_CRITICAL();
{
if prvTaskIsTaskSuspended(pxTCB) != pdFALSE {
crate::trace::traceTASK_RESUME(pxTCB as *mut c_void);
let _ux = uxListRemove(&mut (*pxTCB).xStateListItem);
prvAddTaskToReadyList(pxTCB);
if (*pxTCB).uxPriority >= (*pxCurrentTCB).uxPriority {
portYIELD_WITHIN_API();
}
}
}
taskEXIT_CRITICAL();
}
}
}
#[cfg(feature = "task-suspend")]
unsafe fn prvTaskIsTaskSuspended(pxTCB: *const TCB_t) -> BaseType_t {
if listIS_CONTAINED_WITHIN(&xSuspendedTaskList, &(*pxTCB).xStateListItem) != pdFALSE {
if listIS_CONTAINED_WITHIN(&xPendingReadyList, &(*pxTCB).xEventListItem) == pdFALSE {
if listLIST_ITEM_CONTAINER(&(*pxTCB).xEventListItem) == ptr::null_mut() {
return pdTRUE;
}
}
}
pdFALSE
}
#[inline(always)]
pub fn taskENTER_CRITICAL() {
portENTER_CRITICAL();
}
#[inline(always)]
pub fn taskEXIT_CRITICAL() {
portEXIT_CRITICAL();
}
#[inline(always)]
pub fn taskENTER_CRITICAL_FROM_ISR() -> UBaseType_t {
portSET_INTERRUPT_MASK_FROM_ISR()
}
#[inline(always)]
pub fn taskEXIT_CRITICAL_FROM_ISR(uxSavedInterruptStatus: UBaseType_t) {
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
}
#[repr(u8)]
pub enum eNotifyAction {
eNoAction = 0,
eSetBits = 1,
eIncrement = 2,
eSetValueWithOverwrite = 3,
eSetValueWithoutOverwrite = 4,
}
const tskDEFAULT_INDEX_TO_NOTIFY: UBaseType_t = 0;
pub unsafe fn xTaskNotify(xTaskToNotify: TaskHandle_t, ulValue: u32, eAction: i32) -> BaseType_t {
xTaskGenericNotify(
xTaskToNotify,
tskDEFAULT_INDEX_TO_NOTIFY,
ulValue,
eAction,
ptr::null_mut(),
)
}
pub unsafe fn xTaskNotifyWait(
ulBitsToClearOnEntry: u32,
ulBitsToClearOnExit: u32,
pulNotificationValue: *mut u32,
xTicksToWait: TickType_t,
) -> BaseType_t {
xTaskGenericNotifyWait(
tskDEFAULT_INDEX_TO_NOTIFY,
ulBitsToClearOnEntry,
ulBitsToClearOnExit,
pulNotificationValue,
xTicksToWait,
)
}
pub unsafe fn xTaskNotifyFromISR(
xTaskToNotify: TaskHandle_t,
ulValue: u32,
eAction: i32,
pxHigherPriorityTaskWoken: *mut BaseType_t,
) -> BaseType_t {
xTaskGenericNotifyFromISR(
xTaskToNotify,
tskDEFAULT_INDEX_TO_NOTIFY,
ulValue,
eAction,
ptr::null_mut(),
pxHigherPriorityTaskWoken,
)
}
pub unsafe fn xTaskGenericNotify(
xTaskToNotify: TaskHandle_t,
uxIndexToNotify: UBaseType_t,
ulValue: u32,
eAction: i32,
pulPreviousNotificationValue: *mut u32,
) -> BaseType_t {
configASSERT(!xTaskToNotify.is_null());
configASSERT((uxIndexToNotify as usize) < configTASK_NOTIFICATION_ARRAY_ENTRIES);
let pxTCB = xTaskToNotify as *mut TCB_t;
let mut xReturn: BaseType_t = pdPASS;
let ucOriginalNotifyState: u8;
taskENTER_CRITICAL();
{
if !pulPreviousNotificationValue.is_null() {
*pulPreviousNotificationValue = (*pxTCB).ulNotifiedValue[uxIndexToNotify as usize];
}
ucOriginalNotifyState = (*pxTCB).ucNotifyState[uxIndexToNotify as usize];
(*pxTCB).ucNotifyState[uxIndexToNotify as usize] = taskNOTIFICATION_RECEIVED;
match eAction {
x if x == eNotifyAction::eSetBits as i32 => {
(*pxTCB).ulNotifiedValue[uxIndexToNotify as usize] |= ulValue;
}
x if x == eNotifyAction::eIncrement as i32 => {
(*pxTCB).ulNotifiedValue[uxIndexToNotify as usize] += 1;
}
x if x == eNotifyAction::eSetValueWithOverwrite as i32 => {
(*pxTCB).ulNotifiedValue[uxIndexToNotify as usize] = ulValue;
}
x if x == eNotifyAction::eSetValueWithoutOverwrite as i32 => {
if ucOriginalNotifyState != taskNOTIFICATION_RECEIVED {
(*pxTCB).ulNotifiedValue[uxIndexToNotify as usize] = ulValue;
} else {
xReturn = pdFAIL;
}
}
_ => {
}
}
if ucOriginalNotifyState == taskWAITING_NOTIFICATION {
let _ = uxListRemove(&mut (*pxTCB).xStateListItem);
prvAddTaskToReadyList(pxTCB);
if (*pxTCB).uxPriority > (*pxCurrentTCB).uxPriority {
portYIELD_WITHIN_API();
}
}
}
taskEXIT_CRITICAL();
xReturn
}
pub unsafe fn xTaskGenericNotifyWait(
uxIndexToWait: UBaseType_t,
ulBitsToClearOnEntry: u32,
ulBitsToClearOnExit: u32,
pulNotificationValue: *mut u32,
xTicksToWait: TickType_t,
) -> BaseType_t {
configASSERT((uxIndexToWait as usize) < configTASK_NOTIFICATION_ARRAY_ENTRIES);
let xReturn: BaseType_t;
let mut xShouldBlock: BaseType_t = pdFALSE;
if (*pxCurrentTCB).ucNotifyState[uxIndexToWait as usize] != taskNOTIFICATION_RECEIVED
&& xTicksToWait > 0
{
vTaskSuspendAll();
{
taskENTER_CRITICAL();
{
if (*pxCurrentTCB).ucNotifyState[uxIndexToWait as usize]
!= taskNOTIFICATION_RECEIVED
{
(*pxCurrentTCB).ulNotifiedValue[uxIndexToWait as usize] &=
!ulBitsToClearOnEntry;
(*pxCurrentTCB).ucNotifyState[uxIndexToWait as usize] =
taskWAITING_NOTIFICATION;
xShouldBlock = pdTRUE;
}
}
taskEXIT_CRITICAL();
if xShouldBlock == pdTRUE {
prvAddCurrentTaskToDelayedList(xTicksToWait, pdTRUE);
}
}
xTaskResumeAll();
}
taskENTER_CRITICAL();
{
if !pulNotificationValue.is_null() {
*pulNotificationValue = (*pxCurrentTCB).ulNotifiedValue[uxIndexToWait as usize];
}
if (*pxCurrentTCB).ucNotifyState[uxIndexToWait as usize] != taskNOTIFICATION_RECEIVED {
xReturn = pdFALSE;
} else {
(*pxCurrentTCB).ulNotifiedValue[uxIndexToWait as usize] &= !ulBitsToClearOnExit;
xReturn = pdTRUE;
}
(*pxCurrentTCB).ucNotifyState[uxIndexToWait as usize] = taskNOT_WAITING_NOTIFICATION;
}
taskEXIT_CRITICAL();
xReturn
}
pub unsafe fn xTaskGenericNotifyFromISR(
xTaskToNotify: TaskHandle_t,
uxIndexToNotify: UBaseType_t,
ulValue: u32,
eAction: i32,
pulPreviousNotificationValue: *mut u32,
pxHigherPriorityTaskWoken: *mut BaseType_t,
) -> BaseType_t {
configASSERT(!xTaskToNotify.is_null());
configASSERT((uxIndexToNotify as usize) < configTASK_NOTIFICATION_ARRAY_ENTRIES);
let pxTCB = xTaskToNotify as *mut TCB_t;
let mut xReturn: BaseType_t = pdPASS;
let ucOriginalNotifyState: u8;
let uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
{
if !pulPreviousNotificationValue.is_null() {
*pulPreviousNotificationValue = (*pxTCB).ulNotifiedValue[uxIndexToNotify as usize];
}
ucOriginalNotifyState = (*pxTCB).ucNotifyState[uxIndexToNotify as usize];
(*pxTCB).ucNotifyState[uxIndexToNotify as usize] = taskNOTIFICATION_RECEIVED;
match eAction {
x if x == eNotifyAction::eSetBits as i32 => {
(*pxTCB).ulNotifiedValue[uxIndexToNotify as usize] |= ulValue;
}
x if x == eNotifyAction::eIncrement as i32 => {
(*pxTCB).ulNotifiedValue[uxIndexToNotify as usize] += 1;
}
x if x == eNotifyAction::eSetValueWithOverwrite as i32 => {
(*pxTCB).ulNotifiedValue[uxIndexToNotify as usize] = ulValue;
}
x if x == eNotifyAction::eSetValueWithoutOverwrite as i32 => {
if ucOriginalNotifyState != taskNOTIFICATION_RECEIVED {
(*pxTCB).ulNotifiedValue[uxIndexToNotify as usize] = ulValue;
} else {
xReturn = pdFAIL;
}
}
_ => {
}
}
if ucOriginalNotifyState == taskWAITING_NOTIFICATION {
if uxSchedulerSuspended != 0 {
vListInsertEnd(&mut xPendingReadyList, &mut (*pxTCB).xEventListItem);
} else {
let _ = uxListRemove(&mut (*pxTCB).xStateListItem);
prvAddTaskToReadyList(pxTCB);
}
if (*pxTCB).uxPriority > (*pxCurrentTCB).uxPriority {
if !pxHigherPriorityTaskWoken.is_null() {
*pxHigherPriorityTaskWoken = pdTRUE;
}
xYieldPendings[0] = pdTRUE;
}
}
}
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
xReturn
}
#[cfg(feature = "thread-local-storage")]
pub unsafe fn vTaskSetThreadLocalStoragePointer(
xTaskToSet: TaskHandle_t,
xIndex: BaseType_t,
pvValue: *mut c_void,
) {
let pxTCB = prvGetTCBFromHandle(xTaskToSet);
if xIndex >= 0 && (xIndex as usize) < configNUM_THREAD_LOCAL_STORAGE_POINTERS {
(*pxTCB).pvThreadLocalStoragePointers[xIndex as usize] = pvValue;
}
}
#[cfg(feature = "thread-local-storage")]
pub unsafe fn pvTaskGetThreadLocalStoragePointer(
xTaskToQuery: TaskHandle_t,
xIndex: BaseType_t,
) -> *mut c_void {
let mut pvReturn: *mut c_void = ptr::null_mut();
let pxTCB = prvGetTCBFromHandle(xTaskToQuery);
if xIndex >= 0 && (xIndex as usize) < configNUM_THREAD_LOCAL_STORAGE_POINTERS {
pvReturn = (*pxTCB).pvThreadLocalStoragePointers[xIndex as usize];
}
pvReturn
}
#[cfg(feature = "application-task-tag")]
pub type TaskHookFunction_t = Option<extern "C" fn(*mut c_void) -> BaseType_t>;
#[cfg(feature = "application-task-tag")]
pub unsafe fn vTaskSetApplicationTaskTag(xTask: TaskHandle_t, pxHookFunction: TaskHookFunction_t) {
let pxTCB: *mut TCB_t;
if xTask.is_null() {
pxTCB = pxCurrentTCB;
} else {
pxTCB = xTask as *mut TCB_t;
}
taskENTER_CRITICAL();
(*pxTCB).pxTaskTag = pxHookFunction;
taskEXIT_CRITICAL();
}
#[cfg(feature = "application-task-tag")]
pub unsafe fn xTaskGetApplicationTaskTag(xTask: TaskHandle_t) -> TaskHookFunction_t {
let pxTCB: *mut TCB_t;
let xReturn: TaskHookFunction_t;
if xTask.is_null() {
pxTCB = pxCurrentTCB;
} else {
pxTCB = xTask as *mut TCB_t;
}
taskENTER_CRITICAL();
xReturn = (*pxTCB).pxTaskTag;
taskEXIT_CRITICAL();
xReturn
}
#[cfg(feature = "application-task-tag")]
pub unsafe fn xTaskGetApplicationTaskTagFromISR(xTask: TaskHandle_t) -> TaskHookFunction_t {
let pxTCB: *mut TCB_t;
let xReturn: TaskHookFunction_t;
if xTask.is_null() {
pxTCB = pxCurrentTCB;
} else {
pxTCB = xTask as *mut TCB_t;
}
let uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
xReturn = (*pxTCB).pxTaskTag;
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
xReturn
}
#[cfg(feature = "application-task-tag")]
pub unsafe fn xTaskCallApplicationTaskHook(
xTask: TaskHandle_t,
pvParameter: *mut c_void,
) -> BaseType_t {
let pxTCB: *mut TCB_t;
let xReturn: BaseType_t;
if xTask.is_null() {
pxTCB = pxCurrentTCB;
} else {
pxTCB = xTask as *mut TCB_t;
}
if let Some(hook) = (*pxTCB).pxTaskTag {
xReturn = hook(pvParameter);
} else {
xReturn = pdFAIL;
}
xReturn
}
#[cfg(feature = "stack-high-water-mark")]
unsafe fn prvTaskCheckFreeStackSpace(pxStack: *const u8) -> UBaseType_t {
let mut pucStackByte = pxStack;
let mut ulCount: UBaseType_t = 0;
while *pucStackByte == tskSTACK_FILL_BYTE {
pucStackByte = pucStackByte.add(1);
ulCount += 1;
}
ulCount /= core::mem::size_of::<StackType_t>() as UBaseType_t;
ulCount
}
#[cfg(feature = "stack-high-water-mark")]
pub unsafe fn uxTaskGetStackHighWaterMark(xTask: TaskHandle_t) -> UBaseType_t {
let pxTCB = prvGetTCBFromHandle(xTask);
let pucStackByte: *const u8;
#[cfg(feature = "arch-32bit")]
{
pucStackByte = (*pxTCB).pxStack as *const u8;
}
#[cfg(not(feature = "arch-32bit"))]
{
pucStackByte = (*pxTCB).pxStack as *const u8;
}
prvTaskCheckFreeStackSpace(pucStackByte)
}
#[cfg(feature = "stack-high-water-mark")]
pub unsafe fn uxTaskGetStackHighWaterMark2(xTask: TaskHandle_t) -> configSTACK_DEPTH_TYPE {
uxTaskGetStackHighWaterMark(xTask) as configSTACK_DEPTH_TYPE
}
#[cfg(feature = "task-priority-set")]
pub unsafe fn uxTaskPriorityGet(xTask: TaskHandle_t) -> UBaseType_t {
let pxTCB = prvGetTCBFromHandle(xTask);
(*pxTCB).uxPriority
}
#[cfg(feature = "task-priority-set")]
pub unsafe fn uxTaskPriorityGetFromISR(xTask: TaskHandle_t) -> UBaseType_t {
let pxTCB = prvGetTCBFromHandle(xTask);
let uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
let uxReturn = (*pxTCB).uxPriority;
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
uxReturn
}
#[cfg(feature = "task-priority-set")]
pub unsafe fn vTaskPrioritySet(xTask: TaskHandle_t, uxNewPriority: UBaseType_t) {
let pxTCB: *mut TCB_t;
let uxCurrentBasePriority: UBaseType_t;
let uxPriorityUsedOnEntry: UBaseType_t;
let mut xYieldRequired: BaseType_t = pdFALSE;
let uxNewPriority = if uxNewPriority >= configMAX_PRIORITIES {
configMAX_PRIORITIES - 1
} else {
uxNewPriority
};
taskENTER_CRITICAL();
{
pxTCB = prvGetTCBFromHandle(xTask);
configASSERT(!pxTCB.is_null());
#[cfg(feature = "use-mutexes")]
{
uxCurrentBasePriority = (*pxTCB).uxBasePriority;
}
#[cfg(not(feature = "use-mutexes"))]
{
uxCurrentBasePriority = (*pxTCB).uxPriority;
}
if uxCurrentBasePriority != uxNewPriority {
if uxNewPriority > uxCurrentBasePriority {
if pxTCB != pxCurrentTCB {
if uxNewPriority > (*pxCurrentTCB).uxPriority {
xYieldRequired = pdTRUE;
}
}
} else if pxTCB == pxCurrentTCB {
xYieldRequired = pdTRUE;
}
uxPriorityUsedOnEntry = (*pxTCB).uxPriority;
#[cfg(feature = "use-mutexes")]
{
if (*pxTCB).uxBasePriority == (*pxTCB).uxPriority
|| uxNewPriority > (*pxTCB).uxPriority
{
(*pxTCB).uxPriority = uxNewPriority;
}
(*pxTCB).uxBasePriority = uxNewPriority;
}
#[cfg(not(feature = "use-mutexes"))]
{
(*pxTCB).uxPriority = uxNewPriority;
}
let xItemValue = listGET_LIST_ITEM_VALUE(&(*pxTCB).xEventListItem);
if (xItemValue & taskEVENT_LIST_ITEM_VALUE_IN_USE) == 0 {
listSET_LIST_ITEM_VALUE(
&mut (*pxTCB).xEventListItem,
(configMAX_PRIORITIES as TickType_t) - (uxNewPriority as TickType_t),
);
}
if listIS_CONTAINED_WITHIN(
&pxReadyTasksLists[uxPriorityUsedOnEntry as usize],
&(*pxTCB).xStateListItem,
) != pdFALSE
{
if uxListRemove(&mut (*pxTCB).xStateListItem) == 0 {
taskRESET_READY_PRIORITY(uxPriorityUsedOnEntry);
}
prvAddTaskToReadyList(pxTCB);
}
if xYieldRequired != pdFALSE {
portYIELD_WITHIN_API();
}
}
}
taskEXIT_CRITICAL();
}
#[cfg(any(feature = "abort-delay", feature = "trace-facility"))]
pub unsafe fn eTaskGetState(xTask: TaskHandle_t) -> eTaskState {
let pxTCB = xTask as *const TCB_t;
configASSERT(!pxTCB.is_null());
if pxTCB == pxCurrentTCB {
return eTaskState::eRunning;
}
let pxStateList: *const List_t;
let pxEventList: *const List_t;
let pxDelayedList: *const List_t;
let pxOverflowedDelayedList: *const List_t;
taskENTER_CRITICAL();
{
pxStateList = listLIST_ITEM_CONTAINER(&(*pxTCB).xStateListItem);
pxEventList = listLIST_ITEM_CONTAINER(&(*pxTCB).xEventListItem);
pxDelayedList = pxDelayedTaskList;
pxOverflowedDelayedList = pxOverflowDelayedTaskList;
}
taskEXIT_CRITICAL();
if pxEventList == &xPendingReadyList as *const _ {
return eTaskState::eReady;
}
if pxStateList == pxDelayedList || pxStateList == pxOverflowedDelayedList {
return eTaskState::eBlocked;
}
#[cfg(feature = "task-suspend")]
{
if pxStateList == &xSuspendedTaskList as *const _ {
if listLIST_ITEM_CONTAINER(&(*pxTCB).xEventListItem).is_null() {
let mut is_blocked = false;
for i in 0..configTASK_NOTIFICATION_ARRAY_ENTRIES {
if (*pxTCB).ucNotifyState[i] == taskWAITING_NOTIFICATION {
is_blocked = true;
break;
}
}
if is_blocked {
return eTaskState::eBlocked;
} else {
return eTaskState::eSuspended;
}
} else {
return eTaskState::eBlocked;
}
}
}
#[cfg(feature = "task-delete")]
{
if pxStateList == &xTasksWaitingTermination as *const _ || pxStateList.is_null() {
return eTaskState::eDeleted;
}
}
eTaskState::eReady
}
#[cfg(feature = "abort-delay")]
pub unsafe fn xTaskAbortDelay(xTask: TaskHandle_t) -> BaseType_t {
let pxTCB = xTask as *mut TCB_t;
configASSERT(!pxTCB.is_null());
let xReturn: BaseType_t;
vTaskSuspendAll();
{
if eTaskGetState(xTask) == eTaskState::eBlocked {
xReturn = pdPASS;
uxListRemove(&mut (*pxTCB).xStateListItem);
taskENTER_CRITICAL();
{
if !listLIST_ITEM_CONTAINER(&(*pxTCB).xEventListItem).is_null() {
uxListRemove(&mut (*pxTCB).xEventListItem);
(*pxTCB).ucDelayAborted = pdTRUE as u8;
}
}
taskEXIT_CRITICAL();
prvAddTaskToReadyList(pxTCB);
if configUSE_PREEMPTION != 0 {
if (*pxTCB).uxPriority > (*pxCurrentTCB).uxPriority {
xYieldPendings[0] = pdTRUE;
}
}
} else {
xReturn = pdFAIL;
}
}
xTaskResumeAll();
xReturn
}
#[cfg(feature = "trace-facility")]
pub unsafe fn vTaskGetInfo(
xTask: TaskHandle_t,
pxTaskStatus: *mut crate::types::TaskStatus_t,
xGetFreeStackSpace: BaseType_t,
eState: eTaskState,
) {
let pxTCB: *mut TCB_t = if xTask.is_null() {
pxCurrentTCB
} else {
xTask as *mut TCB_t
};
if pxTCB.is_null() || pxTaskStatus.is_null() {
return;
}
(*pxTaskStatus).xHandle = pxTCB as TaskHandle_t;
(*pxTaskStatus).pcTaskName = (*pxTCB).pcTaskName.as_ptr();
#[cfg(feature = "trace-facility")]
{
(*pxTaskStatus).xTaskNumber = (*pxTCB).uxTaskNumber;
}
#[cfg(not(feature = "trace-facility"))]
{
(*pxTaskStatus).xTaskNumber = 0;
}
(*pxTaskStatus).uxCurrentPriority = (*pxTCB).uxPriority;
#[cfg(feature = "use-mutexes")]
{
(*pxTaskStatus).uxBasePriority = (*pxTCB).uxBasePriority;
}
#[cfg(not(feature = "use-mutexes"))]
{
(*pxTaskStatus).uxBasePriority = (*pxTCB).uxPriority;
}
#[cfg(feature = "generate-run-time-stats")]
{
(*pxTaskStatus).ulRunTimeCounter = (*pxTCB).ulRunTimeCounter;
}
#[cfg(not(feature = "generate-run-time-stats"))]
{
(*pxTaskStatus).ulRunTimeCounter = 0;
}
(*pxTaskStatus).pxStackBase = (*pxTCB).pxStack;
if xGetFreeStackSpace != pdFALSE {
#[cfg(feature = "stack-high-water-mark")]
{
(*pxTaskStatus).usStackHighWaterMark =
uxTaskGetStackHighWaterMark(pxTCB as TaskHandle_t) as u16;
}
#[cfg(not(feature = "stack-high-water-mark"))]
{
(*pxTaskStatus).usStackHighWaterMark = 0;
}
} else {
(*pxTaskStatus).usStackHighWaterMark = 0;
}
(*pxTaskStatus).eCurrentState = if eState != eTaskState::eInvalid {
eState as u8
} else {
eTaskGetState(pxTCB as TaskHandle_t) as u8
};
}
#[cfg(feature = "trace-facility")]
unsafe fn prvListTasksWithinSingleList(
pxTaskStatusArray: *mut crate::types::TaskStatus_t,
pxList: *mut List_t,
eState: eTaskState,
) -> UBaseType_t {
let mut uxTask: UBaseType_t = 0;
if listCURRENT_LIST_LENGTH(pxList) > 0 {
let pxListEnd = listGET_END_MARKER(pxList) as *mut ListItem_t;
let mut pxNextListItem = listGET_HEAD_ENTRY(pxList);
while pxNextListItem != pxListEnd {
let pxTCB = listGET_LIST_ITEM_OWNER(pxNextListItem) as *mut TCB_t;
vTaskGetInfo(
pxTCB as TaskHandle_t,
pxTaskStatusArray.add(uxTask as usize),
pdTRUE,
eState,
);
uxTask += 1;
pxNextListItem = listGET_NEXT(pxNextListItem);
}
}
uxTask
}
#[cfg(feature = "trace-facility")]
pub unsafe fn uxTaskGetSystemState(
pxTaskStatusArray: *mut crate::types::TaskStatus_t,
uxArraySize: UBaseType_t,
pulTotalRunTime: *mut u32,
) -> UBaseType_t {
let mut uxTask: UBaseType_t = 0;
let mut uxQueue: UBaseType_t = configMAX_PRIORITIES;
vTaskSuspendAll();
{
if uxArraySize >= uxCurrentNumberOfTasks {
loop {
uxQueue -= 1;
uxTask += prvListTasksWithinSingleList(
pxTaskStatusArray.add(uxTask as usize),
&mut pxReadyTasksLists[uxQueue as usize],
eTaskState::eReady,
);
if uxQueue == 0 {
break;
}
}
uxTask += prvListTasksWithinSingleList(
pxTaskStatusArray.add(uxTask as usize),
pxDelayedTaskList,
eTaskState::eBlocked,
);
uxTask += prvListTasksWithinSingleList(
pxTaskStatusArray.add(uxTask as usize),
pxOverflowDelayedTaskList,
eTaskState::eBlocked,
);
#[cfg(feature = "task-suspend")]
{
uxTask += prvListTasksWithinSingleList(
pxTaskStatusArray.add(uxTask as usize),
&mut xSuspendedTaskList,
eTaskState::eSuspended,
);
}
#[cfg(feature = "task-delete")]
{
uxTask += prvListTasksWithinSingleList(
pxTaskStatusArray.add(uxTask as usize),
&mut xTasksWaitingTermination,
eTaskState::eDeleted,
);
}
if !pulTotalRunTime.is_null() {
#[cfg(feature = "generate-run-time-stats")]
{
*pulTotalRunTime = ulTotalRunTime;
}
#[cfg(not(feature = "generate-run-time-stats"))]
{
*pulTotalRunTime = 0;
}
}
} else {
uxTask = 0;
}
}
xTaskResumeAll();
uxTask
}
#[cfg(feature = "stats-formatting")]
pub struct BufferWriter<'a> {
buf: &'a mut [u8],
pos: usize,
}
#[cfg(feature = "stats-formatting")]
impl<'a> BufferWriter<'a> {
pub fn new(buf: &'a mut [u8]) -> Self {
BufferWriter { buf, pos: 0 }
}
pub fn len(&self) -> usize {
self.pos
}
pub fn is_empty(&self) -> bool {
self.pos == 0
}
}
#[cfg(feature = "stats-formatting")]
impl<'a> core::fmt::Write for BufferWriter<'a> {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
let bytes = s.as_bytes();
let remaining = &mut self.buf[self.pos..];
if bytes.len() <= remaining.len() {
remaining[..bytes.len()].copy_from_slice(bytes);
self.pos += bytes.len();
Ok(())
} else {
remaining.copy_from_slice(&bytes[..remaining.len()]);
self.pos = self.buf.len();
Err(core::fmt::Error)
}
}
}
#[cfg(feature = "stats-formatting")]
fn prvGetTaskStateChar(eState: eTaskState) -> char {
match eState {
eTaskState::eRunning => 'X', eTaskState::eReady => 'R', eTaskState::eBlocked => 'B', eTaskState::eSuspended => 'S', eTaskState::eDeleted => 'D', eTaskState::eInvalid => '?', }
}
#[cfg(all(feature = "stats-formatting", feature = "trace-facility"))]
pub unsafe fn vTaskListTasks(pcWriteBuffer: *mut u8, uxBufferLength: usize) {
use core::fmt::Write;
let buffer = core::slice::from_raw_parts_mut(pcWriteBuffer, uxBufferLength);
let mut writer = BufferWriter::new(buffer);
let _ = writeln!(
writer,
"{:<16} {:>5} {:>4} {:>6} {:>4}",
"Name", "State", "Prio", "Stack", "Num"
);
let uxArraySize = uxTaskGetNumberOfTasks();
if uxArraySize == 0 {
return;
}
const MAX_STACK_TASKS: usize = 16;
#[cfg(any(feature = "alloc", feature = "heap-4", feature = "heap-5"))]
{
extern crate alloc;
use alloc::vec::Vec;
let mut pxTaskStatusArray: Vec<crate::types::TaskStatus_t> =
Vec::with_capacity(uxArraySize as usize);
pxTaskStatusArray.resize_with(uxArraySize as usize, crate::types::TaskStatus_t::new);
let uxTasksReturned =
uxTaskGetSystemState(pxTaskStatusArray.as_mut_ptr(), uxArraySize, ptr::null_mut());
for i in 0..uxTasksReturned as usize {
let pxTaskStatus = &pxTaskStatusArray[i];
let name = prvGetTaskNameFromPtr(pxTaskStatus.pcTaskName);
let state_char = prvGetTaskStateChar(core::mem::transmute::<u8, eTaskState>(
pxTaskStatus.eCurrentState,
));
let _ = writeln!(
writer,
"{:<16} {:>5} {:>4} {:>6} {:>4}",
name,
state_char,
pxTaskStatus.uxCurrentPriority,
pxTaskStatus.usStackHighWaterMark,
pxTaskStatus.xTaskNumber
);
}
}
#[cfg(not(any(feature = "alloc", feature = "heap-4", feature = "heap-5")))]
{
let mut pxTaskStatusArray: [crate::types::TaskStatus_t; MAX_STACK_TASKS] =
[const { crate::types::TaskStatus_t::new() }; MAX_STACK_TASKS];
let uxArraySizeClamped = if uxArraySize as usize > MAX_STACK_TASKS {
MAX_STACK_TASKS as UBaseType_t
} else {
uxArraySize
};
let uxTasksReturned = uxTaskGetSystemState(
pxTaskStatusArray.as_mut_ptr(),
uxArraySizeClamped,
ptr::null_mut(),
);
for i in 0..uxTasksReturned as usize {
let pxTaskStatus = &pxTaskStatusArray[i];
let name = prvGetTaskNameFromPtr(pxTaskStatus.pcTaskName);
let state_char = prvGetTaskStateChar(core::mem::transmute::<u8, eTaskState>(
pxTaskStatus.eCurrentState,
));
let _ = writeln!(
writer,
"{:<16} {:>5} {:>4} {:>6} {:>4}",
name,
state_char,
pxTaskStatus.uxCurrentPriority,
pxTaskStatus.usStackHighWaterMark,
pxTaskStatus.xTaskNumber
);
}
}
if writer.pos < uxBufferLength {
buffer[writer.pos] = 0;
}
}
#[cfg(feature = "stats-formatting")]
fn prvGetTaskNameFromPtr(pcTaskName: *const u8) -> &'static str {
if pcTaskName.is_null() {
return "<null>";
}
let mut len = 0;
unsafe {
while len < configMAX_TASK_NAME_LEN && *pcTaskName.add(len) != 0 {
len += 1;
}
core::str::from_utf8_unchecked(core::slice::from_raw_parts(pcTaskName, len))
}
}
#[cfg(feature = "generate-run-time-stats")]
pub fn ulTaskGetRunTimeCounter(xTask: TaskHandle_t) -> configRUN_TIME_COUNTER_TYPE {
unsafe {
let pxTCB = prvGetTCBFromHandle(xTask);
if pxTCB.is_null() {
return 0;
}
(*pxTCB).ulRunTimeCounter
}
}
#[cfg(feature = "generate-run-time-stats")]
pub fn ulTaskGetRunTimePercent(xTask: TaskHandle_t) -> configRUN_TIME_COUNTER_TYPE {
unsafe {
let pxTCB = prvGetTCBFromHandle(xTask);
if pxTCB.is_null() || ulTotalRunTime == 0 {
return 0;
}
let ulTaskRunTime = (*pxTCB).ulRunTimeCounter;
((ulTaskRunTime as u64 * 100) / ulTotalRunTime as u64) as configRUN_TIME_COUNTER_TYPE
}
}
#[cfg(feature = "generate-run-time-stats")]
pub fn ulTaskGetIdleRunTimeCounter() -> configRUN_TIME_COUNTER_TYPE {
unsafe {
let xIdleTaskHandle = xIdleTaskHandles[0];
if xIdleTaskHandle.is_null() {
return 0;
}
let pxIdleTCB = xIdleTaskHandle as *mut TCB_t;
(*pxIdleTCB).ulRunTimeCounter
}
}
#[cfg(feature = "generate-run-time-stats")]
pub fn ulTaskGetIdleRunTimePercent() -> configRUN_TIME_COUNTER_TYPE {
unsafe {
if ulTotalRunTime == 0 {
return 0;
}
let xIdleTaskHandle = xIdleTaskHandles[0];
if xIdleTaskHandle.is_null() {
return 0;
}
let pxIdleTCB = xIdleTaskHandle as *mut TCB_t;
let ulIdleRunTime = (*pxIdleTCB).ulRunTimeCounter;
((ulIdleRunTime as u64 * 100) / ulTotalRunTime as u64) as configRUN_TIME_COUNTER_TYPE
}
}
#[cfg(feature = "generate-run-time-stats")]
pub fn ulTaskGetTotalRunTime() -> configRUN_TIME_COUNTER_TYPE {
unsafe { ulTotalRunTime }
}
#[cfg(all(
feature = "generate-run-time-stats",
feature = "stats-formatting",
feature = "trace-facility"
))]
pub unsafe fn vTaskGetRunTimeStatistics(pcWriteBuffer: *mut u8, uxBufferLength: usize) {
use core::fmt::Write;
let buffer = core::slice::from_raw_parts_mut(pcWriteBuffer, uxBufferLength);
let mut writer = BufferWriter::new(buffer);
let _ = writeln!(writer, "{:<16} {:>12} {:>8}", "Name", "Abs. Time", "% Time");
let uxArraySize = uxTaskGetNumberOfTasks();
if uxArraySize == 0 {
return;
}
let ulTotalTime = ulTotalRunTime;
if ulTotalTime == 0 {
let _ = writeln!(writer, "(No run time data collected yet)");
return;
}
#[cfg(any(feature = "alloc", feature = "heap-4", feature = "heap-5"))]
{
extern crate alloc;
use alloc::vec::Vec;
let mut pxTaskStatusArray: Vec<crate::types::TaskStatus_t> =
Vec::with_capacity(uxArraySize as usize);
pxTaskStatusArray.resize_with(uxArraySize as usize, crate::types::TaskStatus_t::new);
let mut ulTotalRunTimeReturned: u32 = 0;
let uxTasksReturned = uxTaskGetSystemState(
pxTaskStatusArray.as_mut_ptr(),
uxArraySize,
&mut ulTotalRunTimeReturned,
);
for i in 0..uxTasksReturned as usize {
let pxTaskStatus = &pxTaskStatusArray[i];
let ulStatsAsPercentage = if ulTotalTime > 0 {
((pxTaskStatus.ulRunTimeCounter as u64 * 100) / ulTotalTime as u64) as u32
} else {
0
};
let pcTaskName = pxTaskStatus.pcTaskName;
let name = prvGetTaskNameFromPtr(pcTaskName);
if ulStatsAsPercentage > 0 {
let _ = writeln!(
writer,
"{:<16} {:>12} {:>7}%",
name, pxTaskStatus.ulRunTimeCounter, ulStatsAsPercentage
);
} else {
let _ = writeln!(
writer,
"{:<16} {:>12} {:>7}",
name, pxTaskStatus.ulRunTimeCounter, "<1%"
);
}
}
}
#[cfg(not(any(feature = "alloc", feature = "heap-4", feature = "heap-5")))]
{
const MAX_STACK_TASKS: usize = 16;
let mut pxTaskStatusArray: [crate::types::TaskStatus_t; MAX_STACK_TASKS] =
[const { crate::types::TaskStatus_t::new() }; MAX_STACK_TASKS];
let uxActualArraySize = if uxArraySize as usize > MAX_STACK_TASKS {
MAX_STACK_TASKS as UBaseType_t
} else {
uxArraySize
};
let mut ulTotalRunTimeReturned: u32 = 0;
let uxTasksReturned = uxTaskGetSystemState(
pxTaskStatusArray.as_mut_ptr(),
uxActualArraySize,
&mut ulTotalRunTimeReturned,
);
for i in 0..uxTasksReturned as usize {
let pxTaskStatus = &pxTaskStatusArray[i];
let ulStatsAsPercentage = if ulTotalTime > 0 {
((pxTaskStatus.ulRunTimeCounter as u64 * 100) / ulTotalTime as u64) as u32
} else {
0
};
let pcTaskName = pxTaskStatus.pcTaskName;
let name = prvGetTaskNameFromPtr(pcTaskName);
if ulStatsAsPercentage > 0 {
let _ = writeln!(
writer,
"{:<16} {:>12} {:>7}%",
name, pxTaskStatus.ulRunTimeCounter, ulStatsAsPercentage
);
} else {
let _ = writeln!(
writer,
"{:<16} {:>12} {:>7}",
name, pxTaskStatus.ulRunTimeCounter, "<1%"
);
}
}
}
}
#[cfg(feature = "tickless-idle")]
fn prvGetExpectedIdleTime() -> TickType_t {
unsafe {
let mut xReturn: TickType_t;
let mut xHigherPriorityReadyTasks = pdFALSE;
#[cfg(not(feature = "port-optimised-task-selection"))]
{
if uxTopReadyPriority > tskIDLE_PRIORITY {
xHigherPriorityReadyTasks = pdTRUE;
}
}
#[cfg(feature = "port-optimised-task-selection")]
{
const UX_LEAST_SIGNIFICANT_BIT: UBaseType_t = 0x01;
if uxTopReadyPriority > UX_LEAST_SIGNIFICANT_BIT {
xHigherPriorityReadyTasks = pdTRUE;
}
}
if !pxCurrentTCB.is_null() && (*pxCurrentTCB).uxPriority > tskIDLE_PRIORITY {
xReturn = 0;
} else if listCURRENT_LIST_LENGTH(&pxReadyTasksLists[tskIDLE_PRIORITY as usize]) > 1 {
xReturn = 0;
} else if xHigherPriorityReadyTasks != pdFALSE {
xReturn = 0;
} else {
xReturn = xNextTaskUnblockTime;
xReturn = xReturn.wrapping_sub(xTickCount);
}
xReturn
}
}
#[cfg(feature = "tickless-idle")]
pub fn eTaskConfirmSleepModeStatus() -> crate::types::eSleepModeStatus {
use crate::types::eSleepModeStatus;
unsafe {
if listCURRENT_LIST_LENGTH(&xPendingReadyList) != 0 {
return eSleepModeStatus::eAbortSleep;
}
if xYieldPendings[0] != pdFALSE {
return eSleepModeStatus::eAbortSleep;
}
if xPendedTicks != 0 {
return eSleepModeStatus::eAbortSleep;
}
#[cfg(feature = "task-suspend")]
{
let uxNonApplicationTasks: UBaseType_t = configNUMBER_OF_CORES as UBaseType_t;
if listCURRENT_LIST_LENGTH(&xSuspendedTaskList)
== (uxCurrentNumberOfTasks - uxNonApplicationTasks)
{
return eSleepModeStatus::eNoTasksWaitingTimeout;
}
}
eSleepModeStatus::eStandardSleep
}
}
#[cfg(feature = "tickless-idle")]
pub fn vTaskStepTick(xTicksToJump: TickType_t) {
unsafe {
let mut xTicksToJump = xTicksToJump;
let xUpdatedTickCount = xTickCount.wrapping_add(xTicksToJump);
configASSERT(xUpdatedTickCount <= xNextTaskUnblockTime);
if xUpdatedTickCount == xNextTaskUnblockTime {
configASSERT(uxSchedulerSuspended != 0);
configASSERT(xTicksToJump != 0);
taskENTER_CRITICAL();
{
xPendedTicks += 1;
}
taskEXIT_CRITICAL();
xTicksToJump -= 1;
}
xTickCount = xTickCount.wrapping_add(xTicksToJump);
crate::trace::traceINCREASE_TICK_COUNT(xTicksToJump);
}
}