Bug fixes and new docs#55
Merged
Merged
Conversation
…sion
This commit implements three key optimizations for the mutex protecting
image table access in Python plugins:
1. Priority Inheritance for Mutex (C core)
- Modified plugin_driver_create() to use pthread_mutexattr_setprotocol()
with PTHREAD_PRIO_INHERIT
- Prevents priority inversion when lower-priority plugin threads hold
the mutex while the real-time PLC scan cycle thread is waiting
2. Move Conversion Logic Outside Critical Section (modbus_master_memory.py)
- Added new optimized functions that separate data conversion from
buffer access:
* convert_modbus_data_to_iec_values() - pre-convert before mutex
* write_preconverted_iec_values() - write under mutex
* read_raw_iec_values() - read under mutex
* convert_raw_iec_to_modbus() - convert after mutex release
- Legacy functions kept for backward compatibility
3. Batch Write Preparations (modbus_master_plugin.py)
- READ operations: Pre-convert all Modbus data to IEC values before
acquiring mutex, then write all pre-converted values under single
mutex acquisition
- WRITE operations: Collect all due write points, read all raw IEC
values under single mutex acquisition, then convert and perform
Modbus writes outside the mutex
These optimizations reduce mutex hold time by ensuring only actual buffer
access operations occur within the critical section, while CPU-intensive
conversion work happens outside.
Co-Authored-By: Thiago Alves <thiagoralves@gmail.com>
Addresses Copilot review comment: Log when convert_modbus_data_to_iec_values() returns None to aid debugging. Uses a concise message with IEC address and length without dumping the full modbus_data list to avoid log noise. Co-Authored-By: Thiago Alves <thiagoralves@gmail.com>
…imizations Optimize mutex usage to minimize hold time and prevent priority inversion
Co-Authored-By: Thiago Alves <thiagoralves@gmail.com>
…-bool-input Add missing write_bool_input method to SafeBufferAccess
This commit adds runtime support for Python Function Blocks, enabling PLC programs to include function blocks written in Python that communicate with the runtime via shared memory. Changes: - Add core/src/plc_app/include/iec_python.h: Header declaring Python FB loader functions (create_shm_name, python_block_loader) - Add core/src/plc_app/python_loader.c: Implementation ported from v3, adapted to use v4's logging API (log_info, log_error) - Update scripts/compile.sh: Include Python header in generated code compilation and link python_loader with pthread and rt libraries The Python FB loader creates shared memory regions for input/output data exchange and spawns Python processes that run the user's function block code. This matches the behavior of OpenPLC Runtime v3. Co-Authored-By: Thiago Alves <thiagoralves@gmail.com>
The python_loader.c was calling log_info() and log_error() directly, but these functions are defined in plc_main, not in libplc.so. Since plc_main is not linked with -rdynamic, these symbols would not be resolved at runtime. This commit implements Option B (function pointers/callbacks) to fix the issue: - Add static function pointers for logging in python_loader.c - Add fallback logging to stderr when loggers are not set - Add python_loader_set_loggers() function to inject logging callbacks - Update iec_python.h with the setter function declaration - Update symbols_init() in image_tables.c to wire up logging callbacks after loading libplc.so This approach matches the existing plugin system pattern where logging functions are passed via callbacks rather than relying on symbol export. Co-Authored-By: Thiago Alves <thiagoralves@gmail.com>
Per review feedback, since python_loader.c is always compiled into libplc.so and symbols_init() always runs before any Python FB code executes, the logging callbacks will always be set. Therefore, the fallback logging to stderr is unnecessary. Changes: - Remove fallback_log, py_log_info_fallback, py_log_error_fallback functions - Remove NULL checks in LOG_INFO/LOG_ERROR macros - Simplify macros to directly call the function pointers - Remove stdarg.h include (no longer needed) Co-Authored-By: Thiago Alves <thiagoralves@gmail.com>
…nction-blocks Add Python Function Blocks support
- Add lock_memory() function that calls mlockall(MCL_CURRENT | MCL_FUTURE) - Call lock_memory() after set_realtime_priority() in plc_cycle_thread() - Add sys/mman.h include for mlockall support This prevents the kernel from swapping out memory pages during PLC execution, eliminating unpredictable latency spikes caused by page faults in the scan cycle. Requires container to have memlock ulimit set to unlimited (--ulimit memlock=-1). Co-Authored-By: Thiago Alves <thiagoralves@gmail.com>
…y-locking Add memory locking for deterministic PLC execution
- Remove print_stats_thread that was polluting logs every 5 seconds - Add STATS command to unix socket for fetching timing statistics - Add thread-safe mutex protection for plc_timing_stats access - Add get_timing_stats_snapshot() for safe concurrent reads - Add format_timing_stats_response() to format stats as JSON - Add stats_plc() method to RuntimeManager - Modify handle_status() to include timing_stats in response - Maintain backward compatibility: status field unchanged for old editors - Fix missing return statement in stop_plc exception handler - Disable R0902 and R1732 pylint warnings in pre-commit config Co-Authored-By: Thiago Alves <thiagoralves@gmail.com>
Use PRId64 from inttypes.h instead of %ld for portable int64_t formatting. This fixes build failures on 32-bit ARM platforms where int64_t is 'long long int' rather than 'long int'. Co-Authored-By: Thiago Alves <thiagoralves@gmail.com>
…status-response Move timing stats from logs to status response
This adds an after_request hook to the REST API blueprint that includes the X-OpenPLC-Runtime-Version header with value 'v4' in all API responses. This enables the OpenPLC Editor to detect which runtime version it is connecting to and show an error if there is a version mismatch between the selected target and the actual runtime. Co-Authored-By: Thiago Alves <thiagoralves@gmail.com>
…ersion-header Add X-OpenPLC-Runtime-Version header to all API responses
- Add optional include_stats parameter to /api/status endpoint (default false) - Only fetch timing stats when include_stats=true, avoiding mutex acquisition - Remove verbose command logging from unix_socket.c (only log unrecognized commands) - This reduces log flooding and avoids unnecessary mutex contention on the critical PLC scan cycle when stats are not needed Co-Authored-By: Thiago Alves <thiagoralves@gmail.com>
…atus-stats-polling Add include_stats parameter to status endpoint and reduce log verbosity
- Update README.md to document that native C/C++ plugins are now fully supported - Fix incorrect type comment in plugin_config.h (0=python, 1=native) - Update DEVELOPMENT.md plugin section with accurate lifecycle description - Document native plugin args lifetime (must copy during init) - Update Python import examples to use correct 'from shared import' syntax - Add native plugin examples to See Also section Co-Authored-By: Thiago Alves <thiagoralves@gmail.com>
…ugin-driver-docs Update plugin driver documentation to reflect native plugin support
- Add plugin_driver_cycle_start() and plugin_driver_cycle_end() functions - Integrate cycle hooks into PLC scan cycle in plc_state_manager.c - Call cycle_start before PLC logic execution, cycle_end after - Plugins opt-in by implementing cycle_start/cycle_end; opt-out by not implementing - Only active (enabled + running) native plugins are called - Update README.md with comprehensive cycle hooks documentation - Add cycle hook functions to API Reference section Co-Authored-By: Thiago Alves <thiagoralves@gmail.com>
Co-Authored-By: Thiago Alves <thiagoralves@gmail.com>
…-native-cycle-hooks Implement native plugin cycle hooks for real-time PLC synchronization
- Fix close_unix_socket() signature mismatch: header declared with no parameters but implementation took int server_fd parameter - Update empty () declarations to (void) in headers and definitions for C standards compliance: - setup_unix_socket() - watchdog_init() - scan_cycle_time_start() - scan_cycle_time_end() - Update function pointer typedefs in plugin_driver.h to use (void) - Make store_on_buffer and retrieve_from_buffer static in log.c These changes ensure the code compiles on stricter compilers that treat -Wstrict-prototypes and -Wold-style-definition as errors. Co-Authored-By: Thiago Alves <thiagoralves@gmail.com>
…-unix-socket-signature Fix function prototype declarations for cross-platform compatibility
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pull request significantly updates the documentation for the OpenPLC Runtime plugin system to reflect full support for both Python and native C/C++ plugins. The changes clarify the architecture, configuration, and development process for both plugin types, provide detailed examples, and introduce new features such as per-plugin Python virtual environments and real-time synchronization hooks for native plugins.
Plugin System Architecture and Support:
Native C/C++ Plugin API and Usage:
cycle_start,cycle_end) for real-time synchronization with the PLC scan cycle. [1] [2] [3]Python Plugin Enhancements:
sharedmodule for type safety, buffer access, and logging in Python plugins. Added information about per-plugin virtual environment support and clarified best practices for safe buffer and logging access. [1] [2] [3] [4]Plugin Configuration and Lifecycle:
plugins.confconfiguration file format to include the newvenv_pathfield for Python plugins and updated examples for both plugin types. Clarified the plugin lifecycle and memory management requirements for both Python and native plugins. [1] [2] [3] [4]Other Improvements:
These updates provide a clear, accurate, and practical guide for developing, configuring, and integrating both Python and native C/C++ plugins within the OpenPLC Runtime.