Commit Graph

101 Commits

Author SHA1 Message Date
anth64 03cce766cd fix(module): add missing logging for deferred module dependencies 2026-03-07 17:04:41 +01:00
anth64 08c846d641 perf: batch stk_pending_add calls in stk_poll load loops
Replace per-module stk_pending_add() calls in the load holes loop and
append_modules loop with a single shared load_batch[load_count] buffer,
flushed via stk_pending_add_batch() once after both loops complete.
2026-03-07 14:51:10 +01:00
anth64 ba3a9dd163 perf: batch stk_init deferred module pending adds 2026-03-07 14:35:21 +01:00
anth64 49ecd8fde5 perf: batch pending queue allocations in poll and retry
Replace per-module malloc calls in stk_pending_retry and stk_poll
with bulk allocations.

- stk_pending_retry: single realloc to module_count + stk_pending_count
  before the retry loop instead of realloc + 1 per module at attempt_load
- stk_poll unload loop: collect cascade deps into a batch array, call
  stk_pending_add_batch once after instead of stk_pending_add per module
- stk_poll cascade loop: same pattern, batch collect and add once per
  cascade iteration
2026-03-07 14:21:15 +01:00
anth64 06d04cf92b docs: update CHANGELOG and README for v1.0.0-pre.3 2026-03-07 12:16:47 +01:00
anth64 4250f91969 feat(stk.h, module, stk): improve dependency failure logging
- Add STK_MOD_DEP_LOG_BUFFER (2048) to stk.h for the dep failure message
buffer size.

- Add stk_log_dependency_failures(index, action) to module.c. Walks all
deps for the given module, skips satisfied ones, and builds a single
log line listing every unmet dep with its reason: "not found" or
"requires <constraint>, have <version>". The action parameter
("Deferring" / "Unloading") lets call sites produce contextually
appropriate messages:

  - Deferring 'test_mod_dep': unmet deps: test_mod (not found)
  - Unloading 'test_mod_dep': unmet deps: test_mod (not found), renderer (requires ^2.0.0, have 1.3.0)

- Replace the silent defer at init and the vague "unmet dependencies"
cascade log in stk_poll() with calls to stk_log_dependency_failures().
2026-03-07 11:34:23 +01:00
anth64 42a96f2bc0 feat(module, stk): dependency ordering, cascade unload, and pending queue
- Refactor the Kahn topological sort into a generic stk_kahn_sort() that
accepts a has_dep callback and an on_cycle callback, eliminating direct
coupling to stk_modules. stk_topo_sort() becomes a thin wrapper using
stk_loaded_has_dep() and stk_log_cycle(). stk_sort_load_order() uses the
same core via stk_batch_has_dep(), which opens tmp files to inspect deps
so simultaneous load events are processed dependency-first without needing
a retry cycle.

- Split stk_module_load() into stk_module_preload(), stk_module_activate(),
stk_module_discard(), and stk_validate_dependencies_single(). preload
handles library loading and metadata only; activate calls init; discard
cleans up without calling shutdown; validate_dependencies_single checks a
single module's deps. stk_module_load() composes these in order and does
not call init if deps are unmet.

- On UNLOAD events in stk_poll(), expand the unload set to include all
transitively dependent loaded modules via stk_collect_dependents(), sort
dependents-first via stk_sort_unload_order(), and unload in that order.
Modules unloaded due to expansion are queued to pending so they reload
automatically when their dependency returns. Remove trim_arrays, now
handled by the compact pass after the unload block.

- On LOAD events with unmet dependencies, add the tmp path to the pending
queue instead of dropping the module. stk_pending_retry() skips already
loaded entries and prunes entries whose file no longer exists. Move the
free_poll label above stk_pending_retry() so retry always runs regardless
of which path exits the event processing block.
2026-03-07 09:38:46 +01:00
anth64 5d758c2998 fix(module.c): validate dependencies before calling init in stk_module_load 2026-03-06 22:41:31 +01:00
anth64 2e2c3d5e9e feat: phase 1 complete - dependency system, cascade unload, pending queue (v1.0.0-pre.1) 2026-03-06 22:13:35 +01:00
anth64 6477cde367 feat(module.c, stk.c): implement pending queue and cascade dependency resolution 2026-03-06 07:52:34 +01:00
anth64 8e9007fdfe refactor(module.c, stk.c): reorder stk_mod_t fields largest to smallest 2026-03-04 23:37:15 +01:00
anth64 6e8df4e0e1 feat(stk.c): add module metadata logging on init, load, reload, and unload 2026-03-04 07:46:29 +01:00
anth64 f4c76f7b5a feat(module.c): log all dependency validation failures before returning error 2026-03-03 23:10:46 +01:00
anth64 5e7b41ab68 feat(module.c): log offending modules on circular dependency detection 2026-03-03 23:03:46 +01:00
anth64 9a4b5ee9ef refactor(stk.h, module.c, stk.c): switch deps to exported array and clean up types
- Move stk_dep_t to public header
- Rename stk_set_module_dependencies_fn to stk_set_module_deps_sym
- Change default deps symbol name from stk_mod_dependencies to stk_mod_deps
- Read deps as direct exported stk_dep_t array instead of function call
- Update sentinel check to .id[0] != '\0'
- Default module version to 0.0.0 if not provided or invalid
- Remove deps_func from union in stk_module_load
2026-03-03 22:53:37 +01:00
anth64 ceb389de0d feat(module.c, stk.c): expose dependency functions and integrate into init and poll
- Make stk_validate_dependencies and stk_topo_sort non static
- Add extern declarations in stk.c
- Run stk_validate_dependencies after module loads in stk_init
- Validation failure is fatal; unload all modules and return error code
- Run stk_topo_sort after validation, sort failure is logged but not fatal
- Add validate_deps label in stk_poll so all load/unload paths run validation
- Add dep error codes to stk_error_string
2026-03-03 22:29:59 +01:00
anth64 6faf33d944 feat(module.c): add topological sort with cycle detection 2026-03-03 22:21:04 +01:00
anth64 46f0f31ed7 feat(module.c): add dependency validation pass 2026-03-03 22:09:24 +01:00
anth64 e48d5f0d5b feat(module.c): add internal version parsing and constraint validation 2026-03-03 21:59:45 +01:00
anth64 dc014292cb refactor(module.c, stk.c): replace parallel arrays with stk_mod_t struct
- Consolidate handles, function pointers, metadata, and deps into single stk_mod_t
- Remove all separate metadata arrays and index mappings
- Simplify init, free, realloc, load, and unload significantly
- stk.c externs reduced to stk_modules and module_count
2026-03-03 21:42:43 +01:00
anth64 cb7c43f8af feat(module.c): add stk_dep_t struct and dependency arrays 2026-03-03 21:23:57 +01:00
anth64 6bddc6a888 refactor(module.c): extract common setter logic into stk_set_fn_name helper 2026-03-03 21:06:37 +01:00
anth64 7d23ddbc11 feat(module.c): add stk_mod_dependencies setter and default symbol name 2026-03-03 20:50:52 +01:00
anth64 983f9b7393 feat(module.c): add optional module metadata support
- Add tight-packed arrays with index mappings for name, version, and description
- Resolve optional metadata symbols at load time via platform_get_symbol
- Add setter functions for metadata symbol name overrides
2026-02-25 22:31:22 +01:00
anth64 c2b9571c2d fix(platform,core,test): fix Windows compatibility issues
- platform_mkdir now checks if directory exists before creating
- Add FILE_ATTRIBUTE_HIDDEN for dot-prefixed directories on Windows
- Create parent mods directory before temp directory
- Move module unload before copy in reload sequence to fix issue on Windows
- Force CMD shell in test makefile on Windows

Test makefile now uses cmd.exe instead of bash on Windows, fixing
syntax errors when running via build.bat.
2026-02-15 22:53:12 +01:00
anth64 110b7ffca8 feat(logging)!: add enhanced logging system
BREAKING CHANGE: stk_log() signature changed to require log level

- Add log levels (ERROR, WARN, INFO, DEBUG) with runtime filtering
- Add timestamps (yyyy-mm-dd HH:MM:SS.mmm format)
- Add stk_set_log_output(), stk_set_log_prefix(), stk_set_log_level()
- Platform-specific timestamp: GetLocalTime (Windows), gettimeofday (POSIX)
- Consolidate duplicate platform includes into POSIX common block
- Setting log output to NULL disables logging.

Default: INFO level, "stk" prefix, stdout output. All internal messages
use appropriate severity levels. Single byte flag controls enable/disable.
2026-02-14 16:59:56 +01:00
anth64 26fb19a7f5 feat(core): add flags bitfield system
- Replace stk_initialized with stk_flags bitfield
- Add STK_FLAG_INITIALIZED (0x01) and STK_FLAG_LOGGING_ENABLED (0x02)
- Add stk_set_logging_enabled() and stk_is_logging_enabled() API
- Single byte for all boolean state and settings

Logging enabled by default, packs all flags into one byte for efficiency.
2026-02-14 12:39:13 +01:00
anth64 bcb1795218 fix(core)!: enforce strict C89 compliance
BREAKING CHANGE: Public API now uses unsigned char instead of uint8_t

- Remove stdint.h dependency (C99 feature, not C89, I am a fucking idiot)
- Replace uint8_t with unsigned char throughout codebase
- Affects stk_init() return type and internal functions
- Corrects unintended C99 dependency, restoring intended C89 compliance
2026-02-14 11:41:41 +01:00
anth64 2c4d27f915 fix(linux): prevent segfault from invalid module indices during rapid reloads
When spamming file changes rapidly, inotify can report stale UNLOAD/RELOAD
events for modules that were already unloaded by previous events in the same
poll cycle. This caused is_mod_loaded() to return -1, which was then cast to
size_t (18446744073709551615) and used as an array index, causing segfaults.

Additionally, event counts were calculated before validation, causing loops to
run more iterations than valid indices were populated, reading garbage values.

Changes:
- stk.c: Check if is_mod_loaded() returns valid index (>= 0) before adding
  to unload/reload lists
- stk.c: Reset and recalculate counts after populating arrays with only valid
  indices to prevent loop overrun
- Skip processing events for modules that are no longer loaded

This completes the Linux stability fixes started in v0.0.2.
2026-02-11 00:17:33 +01:00
anth64 0cbee45ad2 fix(platform): replace strncpy with memmove to silence -Wrestrict warning 2026-02-09 22:53:42 +01:00
anth64 f83f2051ef fix(linux): prevent segfaults during rapid module reloads
Fixes multiple issues causing segfaults when hot-reloading modules
on Linux, particularly when file changes are detected rapidly:

- Enable is_file_ready() check on Linux to prevent loading partially-written
  shared libraries (previously only used on Windows/BSD)
- Fix event deduplication on Linux to actually remove duplicate inotify events
  instead of just marking them, preventing double-free on same module
- Reorder reload operations to unload old module only after successfully
  copying new version, avoiding invalid state when copy fails

Changes:
- platform.c: Remove __linux__ guards around is_file_ready() function
- platform.c: Add compaction step after deduplication to remove -1 entries
- stk.c: Move module unload to after platform_copy_file() in reload loop

These changes make Linux hot-reload as robust as Windows/BSD implementations.
2026-02-09 22:25:02 +01:00
anth64 28dfc89b15 fix(platform): correct filename buffer handling and prevent overflows
- Replace undefined 'len' variable references with 'name_len'
- Add explicit null terminators after memcpy operations
- Move name_len declaration to Windows-specific scope to eliminate unused variable warning on BSD
- Standardize string copy pattern across all platforms: strlen -> clamp -> memcpy -> null terminate
- Fix increment operator placement for clarity (i++ moved outside array indexing)
- Remove duplicate name_len declaration in platform_directory_watch_check

This ensures proper bounds checking and null termination for filenames
on both Windows and BSD systems, preventing potential buffer overflows
when handling long filenames (approaching STK_PATH_MAX).
2026-02-01 02:38:45 +01:00
anth64 11d8c5cd46 fix(platform): fix string truncation warnings on Windows
Replace strncpy with memcpy+nullterm to handle Windows MAX_PATH (259) vs
STK_PATH_MAX (256) mismatch.
2026-02-01 01:35:05 +01:00
anth64 2f4b91c729 refactor(stk): change stk_init() return type to uint8_t
- Change function signature from int to uint8_t for clarity
- Makes return type intent explicit as status flag
2026-01-31 22:40:21 +01:00
anth64 49ae5ed75e fix(compiler): resolve string truncation and use-after-free warnings
- In stk_module_load: Use memcpy with explicit length check instead of strncpy
- In platform_directory_init_scan: Same fix for directory scanning
- In stk_module_realloc_memory: Replace realloc with malloc+memcpy approach
  to avoid potential use-after-free issues and compiler warnings
- All changes maintain same functionality with improved safety
2026-01-31 21:08:38 +01:00
anth64 4bd1f00b5b refactor: transition return types to uint8_t and improve error reporting
- Update module load and memory functions to use fixed-width uint8_t
- Implement STK_MOD_REALLOC_FAILURE for granular memory error tracking
- Clean up logging prefixes in stk_poll for consistency
- Update error string helper to support new module error codes
2026-01-31 19:56:36 +01:00
anth64 69b4907ff2 fix: resolve Windows segfaults by using platform-specific path separators
On Windows, module IDs were failing to load because paths were being
constructed with hardcoded forward slashes. Oops...

- Added platform.h to centralize path separator macros.
- Updated build_path in stk.c to use STK_PATH_SEP_STR instead of "/".
- Cleaned up redundant platform logic in module.c.
2026-01-31 19:03:19 +01:00
anth64 3a06023265 fix: prevent segfault from rapid module writes
Add platform-specific protections against race conditions when
module files are written rapidly (compilation, copying, etc).

Linux (inotify):
- Deduplicate events within a poll cycle to prevent double-unload
- When duplicate RELOAD events occur, earlier events are skipped
  and only the final event is processed

BSD (kqueue):
- Add file readiness check with flock() before processing mtime changes
- Files that aren't ready have their mtime reset, skipping the reload

All Unix platforms:
- Use atomic .tmp + rename for module copying to prevent loading
  partially-written files

Writes that occur during an active reload or when files aren't
ready are skipped. A subsequent write is required to trigger
detection of those changes.

Fixes segfault caused by processing duplicate reload events
(Linux) or copying incomplete files mid-write (BSD).
2026-01-31 15:04:30 +01:00
anth64 8362889d73 refactor: rename index variables for clarity
-Rename 'idx' instances to use 'index'.
2026-01-31 15:04:30 +01:00
anth64 1e97b69fcd feat: add comprehensive error handling with typed error codes
Add strict error handling for stk initialization and platform operations.
stk_init() now fails fast on critical errors and returns typed error codes
that users can handle programmatically.

Changes:
- Add STK_INIT_* error codes for init failures (memory, tmpdir, watch)
- Add STK_PLATFORM_* error codes for platform operation results
- Check platform_mkdir() and fail if temp directory cannot be created
- Check platform_directory_watch_start() and fail if watch cannot initialize
- Add error_cleanup path in platform_directory_watch_start() to properly
  free resources on critical Windows failures.
- Replace all platform error checks with STK_PLATFORM_OPERATION_SUCCESS
- Log FATAL errors with when critical operations fail
- Add warning logs for non-critical failures

Critical failures now return specific error codes:
- STK_INIT_MEMORY_ERROR: Module memory allocation failed
- STK_INIT_TMPDIR_ERROR: Cannot create temp directory
- STK_INIT_WATCH_ERROR: Cannot start directory watching

Individual module load failures remain non-fatal and are handled logged.
2026-01-31 15:04:20 +01:00
anth64 336a096b82 feat: add error handling for module loading
Modules that fail to load no longer crash or leak memory:
- Check return values from stk_module_load_init() and stk_module_load()
- Log errors with specific failure reasons (library load, symbol lookup, init)
- Track successful_loads counter separately from file_count
- Only increment module_count for modules that actually loaded
- Trim allocated arrays when some modules fail to load
- Continue loading other modules when one fails

This prevents crashes from accessing uninitialized module slots and
avoids memory leaks from over-allocation.
2026-01-30 07:41:18 +01:00
anth64 8ea9ac084f fix: swap STK_MOD_RELOAD and STK_MOD_UNLOAD event handlers
Cases were reversed during if-else to switch refactoring, causing segfault
on module shutdown. Oops...
2026-01-30 07:24:34 +01:00
anth64 aba10d7dac fix: sync module types and replace WIP constants
* Types: Corrected stk.c to use stk_init_mod_func and stk_shutdown_mod_func instead of generic types.
* Errors: Replaced -3 placeholder with STK_MOD_INIT_FAILURE.
* Cleanup: Moved typedefs in module.c for consistency.
2026-01-29 23:11:42 +01:00
anth64 6567fceaec chore: formalize module loading error codes
* Define Constants: Added STK_MOD_LIBRARY_LOAD_ERROR and STK_MOD_SYMBOL_NOT_FOUND_ERROR to the public header.
* Update module.c: Swapped out the -1 and -2 placeholders for the new named constants in stk_module_load.
2026-01-29 22:53:11 +01:00
anth64 2fbf4ca24a feat(module): implement module initialization status check
* Add STK_MOD_INIT_SUCCESS and STK_MOD_INIT_FAILURE macros to stk.h.
* Update stk_module_load to validate module initialization before finalizing the load.
* Unload library if the init func fails, return error.
2026-01-29 22:40:25 +01:00
anth64 450f13fa62 refactor(module): separate init and shutdown function pointer types
* Define stk_init_mod_func as int (*)(void) and stk_shutdown_mod_func as void (*)(void).
* Update stk_inits and stk_shutdowns arrays to use the new specific function pointer types.
* Update the symbol lookup union in stk_module_load to support distinct init and shutdown signatures.
* Adjust memory allocation and reallocation logic in stk_module_init_memory and stk_module_realloc_memory to match new type sizes.
2026-01-29 22:29:59 +01:00
anth64 baa75e897f refactor(module): centralize path parsing and add OS-specific separator
- Define STK_PATH_SEP macro to handle Windows and Unix path separators.
- Refactor extract_module_id to use STK_PATH_SEP.
- Simplify stk_module_load by delegating module ID extraction to extract_module_id.
2026-01-29 22:16:48 +01:00
anth64 92e33ff265 refactor(stk): replace if-else chains with switch statements in stk_poll
- Update event processing to use switch statements.
- Clean up redundant goto jumps after memory reallocation.
2026-01-29 21:25:44 +01:00
anth64 64435fd8cd fix(platform): implement atomic hot-reload synchronization
* Resolve STATUS_INVALID_IMAGE_FORMAT on Windows by preventing race conditions during file I/O.
* is_file_ready: Uses GENERIC_WRITE to block if any process (compiler, copy, etc.) is writing to the source. Added GetFileSize check to ensure headers are flushed.
* platform_copy_file: Copies to .tmp and uses MoveFileExA for an atomic swap, hiding the file from the loader until completion.
* Refactor: Unified Win32 and POSIX logic with a single exit point.
2026-01-29 08:00:15 +01:00
anth64 fb80c3a6c5 feat: implement hot-reload polling with dynamic array management
Implement complete hot-reload logic in stk_poll() supporting reload,
load, and unload operations. Module arrays dynamically grow/shrink
with automatic defragmentation to maintain tight memory layout.

- Grow arrays when loads exceed unloads
- Fill holes left by unloads with new modules
- Defragment and trim arrays when unloads exceed loads
- Unload before realloc to minimize peak memory usage
- Replace sprintf with safe C89 build_path() helper
2026-01-28 00:48:01 +01:00