Skip to content

Commit 2ede8d2

Browse files
committed
Add missing new C++ API to C interface.
Fix MemoryAllocator::Stats::allocate_count/free_count are not updated.
1 parent fb73569 commit 2ede8d2

6 files changed

Lines changed: 168 additions & 22 deletions

File tree

interop/c/include/stk_c.h

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,27 @@ void stk_kernel_suspend_task(stk_kernel_t *k, stk_task_t *task, bool *suspended)
352352
*/
353353
void stk_kernel_resume_task(stk_kernel_t *k, stk_task_t *task);
354354

355+
/*! \brief Suspend scheduling (tickless idle entry point).
356+
\param[in] k: Kernel handle.
357+
\return Number of ticks available for the suspension period, determined by the
358+
nearest pending wake-up deadline across all sleeping tasks. The caller
359+
may program a hardware timer with this value to suppress SysTick wakeups.
360+
\note ISR-safe. Pair every call with stk_kernel_resume().
361+
\note Only meaningful when the kernel was created with KERNEL_TICKLESS mode.
362+
\see stk_kernel_resume, STK_KERNEL_STATE_SUSPENDED
363+
*/
364+
int32_t stk_kernel_suspend(stk_kernel_t *k);
365+
366+
/*! \brief Resume scheduling after a prior stk_kernel_suspend() call.
367+
\param[in] k: Kernel handle.
368+
\param[in] elapsed_ticks: Number of ticks that elapsed during the suspended period.
369+
The kernel uses this value to advance internal time counters and wake tasks
370+
whose sleep deadlines have expired.
371+
\note ISR-safe.
372+
\see stk_kernel_suspend
373+
*/
374+
void stk_kernel_resume(stk_kernel_t *k, int32_t elapsed_ticks);
375+
355376
/*! \brief Enumerate all currently active tasks.
356377
\param[in] k: Kernel handle.
357378
\param[out] tasks: Caller-allocated array of opaque task pointers. Each element is a
@@ -362,6 +383,25 @@ void stk_kernel_resume_task(stk_kernel_t *k, stk_task_t *task);
362383
*/
363384
size_t stk_kernel_enumerate_tasks(stk_kernel_t *k, stk_task_t **tasks, size_t max_count);
364385

386+
/*! \brief Manually deliver one scheduler tick to the kernel.
387+
\param[in] k: Kernel handle.
388+
\note Use this when the platform driver's built-in SysTick handler is disabled
389+
(STK_SYSTICK_HANDLER = _STK_SYSTICK_HANDLER_DISABLE in stk_config.h) and
390+
the application provides its own tick source. Call from your custom tick ISR
391+
at the rate matching the tick period configured in stk_kernel_init().
392+
\note ISR-safe.
393+
*/
394+
void stk_kernel_process_tick(stk_kernel_t *k);
395+
396+
/*! \brief Trigger a kernel hard fault (safe-state handler).
397+
\param[in] k: Kernel handle.
398+
\note Normally invoked automatically by the kernel when an HRT task misses its
399+
deadline. Exposed here for custom fault handlers or test harnesses that need
400+
to force a controlled system halt via the platform driver's fault path.
401+
\note This call does not return.
402+
*/
403+
void stk_kernel_process_hard_fault(stk_kernel_t *k);
404+
365405
// ─────────────────────────────────────────────────────────────────────────────
366406
// Task creation
367407
// ─────────────────────────────────────────────────────────────────────────────
@@ -411,6 +451,22 @@ void stk_task_set_priority(stk_task_t *task, uint8_t priority);
411451
*/
412452
void stk_task_set_name(stk_task_t *task, const char *tname);
413453

454+
/*! \brief Get human-readable task name previously set with stk_task_set_name().
455+
\param[in] task: Task handle.
456+
\return Null-terminated name string, or NULL if not set.
457+
\note ISR-safe (reads a stored pointer, no kernel call).
458+
*/
459+
const char *stk_task_get_name(const stk_task_t *task);
460+
461+
/*! \brief Get the unique identifier of a task.
462+
\param[in] task: Task handle.
463+
\return Task identifier (stk_tid_t). Equivalent to the value stk_tid() returns
464+
when called from within that task.
465+
\note ISR-safe.
466+
\see stk_tid
467+
*/
468+
stk_tid_t stk_task_get_id(const stk_task_t *task);
469+
414470
// ─────────────────────────────────────────────────────────────────────────────
415471
// Services available from inside tasks
416472
// ─────────────────────────────────────────────────────────────────────────────
@@ -563,6 +619,15 @@ void stk_sleep_until(int64_t ts);
563619
*/
564620
void stk_yield(void);
565621

622+
/*! \brief Cancel the sleep of a task, waking it immediately.
623+
\param[in] tid: Identifier of the task to wake (obtained from stk_tid() or
624+
stk_task_get_id()).
625+
\note No-op if the target task is not currently sleeping.
626+
\note ISR-safe.
627+
\see stk_sleep, stk_sleep_ms, stk_sleep_until
628+
*/
629+
void stk_sleep_cancel(stk_tid_t tid);
630+
566631
// ─────────────────────────────────────────────────────────────────────────────
567632
// Dynamic cleanup
568633
// ─────────────────────────────────────────────────────────────────────────────

interop/c/include/stk_c_memory.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,11 @@ extern "C" {
104104

105105
/*! \def STK_BLOCKPOOL_STORAGE_DECL(name, capacity, raw_block_size)
106106
\brief Declare a correctly sized and aligned external storage array.
107-
\details Expands to a \c static \c stk_word_t_t array with the required size and
107+
\details Expands to a \c static \c stk_word_t array with the required size and
108108
pointer-sized alignment. Intended for file-scope or function-scope use.
109+
\c STK_BLOCKPOOL_ALIGN_BLOCK_SIZE() guarantees the total byte count is
110+
always an exact multiple of \c sizeof(stk_word_t), so the integer
111+
division in the array dimension is lossless by construction.
109112
\param name: C identifier for the array variable.
110113
\param capacity: Number of blocks the pool will hold.
111114
\param raw_block_size: Raw per-block size in bytes.
@@ -142,6 +145,9 @@ typedef struct stk_blockpool_t stk_blockpool_t;
142145
Forwarded to \c ITraceable::SetTraceName().
143146
\return Pool handle, or \c NULL if the static slot pool is exhausted
144147
(\c STK_C_BLOCKPOOL_MAX reached).
148+
A non-NULL handle does \b not guarantee the backing storage was
149+
successfully heap-allocated; always call \c stk_blockpool_is_storage_valid()
150+
immediately after creation when operating without exceptions.
145151
\note Not ISR-safe.
146152
\see stk_blockpool_is_storage_valid(), stk_blockpool_destroy()
147153
*/
@@ -180,6 +186,9 @@ stk_blockpool_t *stk_blockpool_create_static(size_t capacity,
180186
\warning Destroying a pool while tasks are blocked in \c stk_blockpool_alloc()
181187
or \c stk_blockpool_timed_alloc() is a logic error and triggers an
182188
assertion in debug builds.
189+
\warning Set the pool pointer to \c NULL after this call to prevent accidental
190+
use-after-destroy (the handle slot may be reused by a subsequent
191+
\c stk_blockpool_create() call).
183192
\note Not ISR-safe.
184193
*/
185194
void stk_blockpool_destroy(stk_blockpool_t *pool);
@@ -272,7 +281,10 @@ size_t stk_blockpool_get_block_size(const stk_blockpool_t *pool);
272281
\param[in] pool: Pool handle.
273282
\return Point-in-time snapshot. May be stale immediately after return in a
274283
multi-task environment.
275-
\note ISR-safe on targets where a 16-bit aligned read is atomic.
284+
\note ISR-safety depends on target ABI: the counter is a 16-bit value, so a
285+
single-instruction atomic read is guaranteed on 32-bit Cortex-M (aligned
286+
halfword load) but not on 8-bit targets where two bus cycles may be needed.
287+
Treat the result as advisory in all multi-core or 8-bit contexts.
276288
*/
277289
size_t stk_blockpool_get_used_count(const stk_blockpool_t *pool);
278290

interop/c/include/stk_c_time.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ extern "C" {
3939

4040
/*! \def STK_C_TIMER_MAX
4141
\brief Maximum number of concurrent \a stk_timer_t instances per core (default: 32).
42+
The total pool size is \a STK_C_TIMER_MAX × \a STK_C_CPU_COUNT slots, shared
43+
across all cores. When the pool is exhausted \a stk_timer_create() asserts
44+
in debug builds and returns NULL in release builds.
4245
\note Increase if your application needs more simultaneous timers.
4346
*/
4447
#ifndef STK_C_TIMER_MAX
@@ -130,9 +133,12 @@ int64_t stk_timerhost_get_time_now(const stk_timerhost_t *host);
130133
/*! \brief Allocate a timer from the static pool.
131134
\param[in] callback: Function to call when the timer expires (must not be NULL).
132135
\param[in] user_data: Opaque pointer forwarded to \a callback on expiration.
133-
\return Timer handle, or NULL if the pool is exhausted (\a STK_C_TIMER_MAX reached).
136+
\return Timer handle, or NULL if the pool is exhausted
137+
(\a STK_C_TIMER_MAX × \a STK_C_CPU_COUNT slots total).
134138
\note The returned handle is valid until \a stk_timer_destroy() is called.
135139
It must not be active (i.e. not currently started) when destroyed.
140+
\note The pool is shared across all CPU cores. Total capacity is
141+
\a STK_C_TIMER_MAX * \a STK_C_CPU_COUNT.
136142
*/
137143
stk_timer_t *stk_timer_create(stk_timer_callback_t callback, void *user_data);
138144

@@ -301,11 +307,11 @@ typedef struct stk_periodic_trigger_t stk_periodic_trigger_t;
301307
\param[in] memory: Pointer to the caller-supplied memory container.
302308
\param[in] memory_size: Size of the container in bytes (must be >= sizeof(stk_periodic_trigger_mem_t)).
303309
\param[in] period: Trigger period in ticks. Must be > 0.
304-
\param[in] started: \a true to create instance in a started state, \a false otherwise.
310+
\param[in] started: \c true to create the instance in a started state (first firing occurs
311+
no earlier than \a period ticks after construction); \c false to create it in a
312+
stopped state (call \a stk_periodic_trigger_restart() before polling).
305313
\return Trigger handle on success, or \c NULL if \a memory is \c NULL
306314
or \a memory_size is too small.
307-
\note The trigger is created in a stopped state.
308-
Call \a stk_periodic_trigger_restart() before polling.
309315
*/
310316
stk_periodic_trigger_t *stk_periodic_trigger_create(stk_periodic_trigger_mem_t *memory,
311317
uint32_t memory_size,

interop/c/src/stk_c.cpp

Lines changed: 62 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ bool stk_kernel_is_schedulable(const stk_kernel_t *k)
220220
STK_ASSERT(k != nullptr);
221221

222222
return SchedulabilityCheck::IsSchedulableWCRT<STK_C_KERNEL_MAX_TASKS>(
223-
reinterpret_cast<stk::IKernel *>(const_cast<stk_kernel_t *>(k))->GetSwitchStrategy());
223+
reinterpret_cast<stk::IKernel *>(const_cast<stk_kernel_t *>(k))->GetSwitchStrategy());
224224
}
225225

226226
void stk_kernel_add_task(stk_kernel_t *k, stk_task_t *task)
@@ -293,6 +293,37 @@ size_t stk_kernel_enumerate_tasks(stk_kernel_t *k, stk_task_t **tasks, size_t ma
293293
return n;
294294
}
295295

296+
int32_t stk_kernel_suspend(stk_kernel_t *k)
297+
{
298+
STK_ASSERT(k != nullptr);
299+
300+
return static_cast<int32_t>(
301+
reinterpret_cast<stk::IKernel *>(k)->GetPlatform()->Suspend());
302+
}
303+
304+
void stk_kernel_resume(stk_kernel_t *k, int32_t elapsed_ticks)
305+
{
306+
STK_ASSERT(k != nullptr);
307+
STK_ASSERT(elapsed_ticks >= 0);
308+
309+
reinterpret_cast<stk::IKernel *>(k)->GetPlatform()->Resume(
310+
static_cast<stk::Timeout>(elapsed_ticks));
311+
}
312+
313+
void stk_kernel_process_tick(stk_kernel_t *k)
314+
{
315+
STK_ASSERT(k != nullptr);
316+
317+
reinterpret_cast<stk::IKernel *>(k)->GetPlatform()->ProcessTick();
318+
}
319+
320+
void stk_kernel_process_hard_fault(stk_kernel_t *k)
321+
{
322+
STK_ASSERT(k != nullptr);
323+
324+
reinterpret_cast<stk::IKernel *>(k)->GetPlatform()->ProcessHardFault();
325+
}
326+
296327
void stk_kernel_add_task_hrt(stk_kernel_t *k,
297328
stk_task_t *task,
298329
int32_t periodicity_ticks,
@@ -358,6 +389,20 @@ void stk_task_set_name(stk_task_t *task, const char *tname)
358389
task->handle.SetName(tname);
359390
}
360391

392+
const char *stk_task_get_name(const stk_task_t *task)
393+
{
394+
STK_ASSERT(task != nullptr);
395+
396+
return task->handle.GetTraceName();
397+
}
398+
399+
stk_tid_t stk_task_get_id(const stk_task_t *task)
400+
{
401+
STK_ASSERT(task != nullptr);
402+
403+
return task->handle.GetId();
404+
}
405+
361406
void stk_task_destroy(stk_task_t *task)
362407
{
363408
STK_ASSERT(task != nullptr);
@@ -368,22 +413,23 @@ void stk_task_destroy(stk_task_t *task)
368413
// ---------------------------------------------------------------------------
369414
// Kernel services (available inside tasks)
370415
// ---------------------------------------------------------------------------
371-
stk_tid_t stk_tid(void) { return stk::GetTid(); }
372-
int64_t stk_ticks(void) { return stk::GetTicks(); }
373-
int32_t stk_tick_resolution(void) { return stk::GetTickResolution(); }
374-
int64_t stk_time_now_ms(void) { return stk::GetTimeNowMs(); }
416+
stk_tid_t stk_tid(void) { return stk::GetTid(); }
417+
int64_t stk_ticks(void) { return stk::GetTicks(); }
418+
int32_t stk_tick_resolution(void) { return stk::GetTickResolution(); }
419+
int64_t stk_time_now_ms(void) { return stk::GetTimeNowMs(); }
375420
int64_t stk_ticks_from_ms(int64_t msec) { return stk_ticks_from_ms_r(msec, stk::GetTickResolution()); }
376-
uint64_t stk_sys_timer_count(void) { return stk::GetSysTimerCount(); }
377-
uint32_t stk_sys_timer_frequency(void) { return stk::GetSysTimerFrequency(); }
378-
uint64_t stk_hires_cycles(void) { return stk::hw::HiResClock::GetCycles(); }
379-
uint32_t stk_hires_frequency(void) { return stk::hw::HiResClock::GetFrequency(); }
380-
int64_t stk_hires_time_us(void) { return stk::hw::HiResClock::GetTimeUs(); }
381-
void stk_delay(uint32_t ticks) { stk::Delay(ticks); }
382-
void stk_sleep(uint32_t ticks) { stk::Sleep(ticks); }
383-
void stk_delay_ms(uint32_t ms) { stk::DelayMs(ms); }
384-
void stk_sleep_ms(uint32_t ms) { stk::SleepMs(ms); }
385-
void stk_sleep_until(int64_t ts) { stk::SleepUntil(ts); }
386-
void stk_yield(void) { stk::Yield(); }
421+
uint64_t stk_sys_timer_count(void) { return stk::GetSysTimerCount(); }
422+
uint32_t stk_sys_timer_frequency(void) { return stk::GetSysTimerFrequency(); }
423+
uint64_t stk_hires_cycles(void) { return stk::hw::HiResClock::GetCycles(); }
424+
uint32_t stk_hires_frequency(void) { return stk::hw::HiResClock::GetFrequency(); }
425+
int64_t stk_hires_time_us(void) { return stk::hw::HiResClock::GetTimeUs(); }
426+
void stk_delay(uint32_t ticks) { stk::Delay(ticks); }
427+
void stk_sleep(uint32_t ticks) { stk::Sleep(ticks); }
428+
void stk_delay_ms(uint32_t ms) { stk::DelayMs(ms); }
429+
void stk_sleep_ms(uint32_t ms) { stk::SleepMs(ms); }
430+
void stk_sleep_until(int64_t ts) { stk::SleepUntil(ts); }
431+
void stk_sleep_cancel(stk_tid_t tid) { stk::SleepCancel(tid); }
432+
void stk_yield(void) { stk::Yield(); }
387433

388434
// ---------------------------------------------------------------------------
389435
// Thread-Local Storage (TLS) API

interop/c/src/stk_c_memory.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,18 @@
1919
using namespace stk;
2020
using namespace stk::memory;
2121

22+
// Guard against divergence between the C macro STK_BLOCKPOOL_ALIGN_BLOCK_SIZE and
23+
// the C++ BlockMemoryPool::AlignBlockSize() function. Both must produce identical
24+
// results; if this assertion fires, update one of the two definitions.
25+
static_assert(
26+
STK_BLOCKPOOL_ALIGN_BLOCK_SIZE(1) == BlockMemoryPool::AlignBlockSize(1) &&
27+
STK_BLOCKPOOL_ALIGN_BLOCK_SIZE(3) == BlockMemoryPool::AlignBlockSize(3) &&
28+
STK_BLOCKPOOL_ALIGN_BLOCK_SIZE(4) == BlockMemoryPool::AlignBlockSize(4) &&
29+
STK_BLOCKPOOL_ALIGN_BLOCK_SIZE(7) == BlockMemoryPool::AlignBlockSize(7) &&
30+
STK_BLOCKPOOL_ALIGN_BLOCK_SIZE(16) == BlockMemoryPool::AlignBlockSize(16),
31+
"STK_BLOCKPOOL_ALIGN_BLOCK_SIZE and BlockMemoryPool::AlignBlockSize() have diverged. "
32+
"Keep both definitions in sync.");
33+
2234
// Returns a size of memory in stk::Word elements required for object allocation.
2335
template <typename T> static constexpr size_t StkGetWordCountForType()
2436
{
@@ -179,6 +191,9 @@ void stk_blockpool_destroy(stk_blockpool_t *pool)
179191
void *stk_blockpool_alloc(stk_blockpool_t *pool)
180192
{
181193
STK_ASSERT(pool != nullptr);
194+
// stk_blockpool_alloc() blocks indefinitely and must never be called from an ISR.
195+
// Use stk_blockpool_try_alloc() or stk_blockpool_timed_alloc(..., STK_NO_WAIT) instead.
196+
STK_ASSERT(!hw::IsInsideISR());
182197

183198
return pool->handle.Alloc();
184199
}

stk/include/memory/stk_memory_allocator.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ struct MemoryAllocator
9090
void RecordAllocate(size_t size)
9191
{
9292
allocated += size;
93+
++allocate_count;
9394
min_ever_free = Min(GetAvailable(), min_ever_free);
9495
}
9596

@@ -101,6 +102,7 @@ struct MemoryAllocator
101102
STK_ASSERT(allocated >= size);
102103

103104
allocated -= size;
105+
++free_count;
104106
}
105107
};
106108

0 commit comments

Comments
 (0)