Skip to content

Fix protecting HB from GC #3062

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 9, 2025
Merged

Conversation

josesimoes
Copy link
Member

@josesimoes josesimoes commented Jan 9, 2025

Description

  • Replaced CLR_RT_ProtectFromGC with pinning buffer HB.
  • Pinned buffer HB where missing it.

Motivation and Context

  • Driver and API calls that access data buffers rely on the content remaining stationary. Certain operations pass pointers to heap blocks (usually arrays), which can be moved by the garbage collector (GC) during asynchronous calls. In most cases, this was managed by using CLR_RT_ProtectFromGC, which prevents the GC from incorrectly collecting the object. However, it does not prevent the object from being moved during heap relocation. Pinning the heap block (HB) is the correct approach. In a few places, this was not properly accounted for.
  • Addresses Heap compaction is not working Home#1354.

How Has This Been Tested?

  • Long rung testing of stress app calling such APIs.

Screenshots

Types of changes

  • Improvement (non-breaking change that improves a feature, code or algorithm)
  • Bug fix (non-breaking change which fixes an issue with code or algorithm)
  • New feature (non-breaking change which adds functionality to code)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Config and build (change in the configuration and build system, has no impact on code or features)
  • Dev Containers (changes related with Dev Containers, has no impact on code or features)
  • Dependencies/declarations (update dependencies or assembly declarations and changes associated, has no impact on code or features)
  • Documentation (changes or updates in the documentation, has no impact on code or features)

Checklist

  • My code follows the code style of this project (only if there are changes in source code).
  • My changes require an update to the documentation (there are changes that require the docs website to be updated).
  • I have updated the documentation accordingly (the changes require an update on the docs in this repo).
  • I have read the CONTRIBUTING document.
  • I have tested everything locally and all new and existing tests passed (only if there are changes in source code).

Summary by CodeRabbit

  • Bug Fixes

    • Improved buffer management and error handling for SPI, I2C, and USB stream operations across multiple device targets.
    • Enhanced resource management with better buffer pinning and cleanup processes.
    • Refined transaction handling for more robust communication protocols.
  • Refactor

    • Restructured code for improved readability and maintainability.
    • Clarified logic in device communication methods.
    • Added more comprehensive error checking and status reporting.

@josesimoes josesimoes added Area: Common libs Everything related with common libraries Platform: STM32 Everything related specifically with ChibiOS platform Platform: NXP Everything related specifically with FreeRTOS Platform: TI-SimpleLink Platform: Azure-RTOS labels Jan 9, 2025
Copy link

coderabbitai bot commented Jan 9, 2025

Walkthrough

The pull request introduces modifications across multiple files in various target platforms, focusing on improving device communication methods for SPI, I2C, and USB interfaces. The changes primarily involve enhancing buffer management, error handling, and resource management for native device communication methods. Modifications include adding buffer pinning for DMA operations, refining transaction handling logic, improving error detection and reporting, and ensuring proper cleanup of resources after device interactions.

Changes

File Change Summary
src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp Updated NativeTransfer method to handle buffer arrays more explicitly, improve data buffer management, and add callback setup for asynchronous operations.
targets/AzureRTOS/ST/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp Enhanced NativeTransmit method with improved transaction handling, error management, and support for synchronous and asynchronous I2C operations.
targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp Added buffer pinning logic for DMA operations and improved cleanup process.
targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.UsbStream/sys_dev_usbstream_native_System_Device_Usb_UsbStream.cpp Enhanced Read and Write methods with buffer pinning and improved resource management.
targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp Restructured NativeTransmit method with improved error handling and transaction processing.
targets/TI_SimpleLink/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp Reordered and clarified code in NativeTransmit method for better readability.

Sequence Diagram

sequenceDiagram
    participant Device
    participant NativeMethod
    participant DMABuffer
    participant ErrorHandler

    NativeMethod->>DMABuffer: Pin Buffer
    NativeMethod->>Device: Initiate Transaction
    alt Successful Transaction
        Device-->>NativeMethod: Return Data
        NativeMethod->>DMABuffer: Unpin Buffer
    else Transaction Error
        Device-->>ErrorHandler: Capture Error
        ErrorHandler->>NativeMethod: Set Error Status
        NativeMethod->>DMABuffer: Unpin Buffer
    end
Loading

Finishing Touches

  • 📝 Generate Docstrings

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🔭 Outside diff range comments (1)
src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp (1)

Line range hint 609-610: Handle Potential Null Dereference of result

After creating the I2cTransferResult object, there is a null check FAULT_ON_NULL(result);. However, subsequent code assumes result is valid. Ensure that result is properly initialized and handle the case where memory allocation fails to prevent null pointer dereferences.

Apply this diff to handle potential null reference:

 CLR_RT_HeapBlock &top = stack.PushValueAndClear();
 NANOCLR_CHECK_HRESULT(
     g_CLR_RT_ExecutionEngine.NewObjectFromIndex(top, g_CLR_RT_WellKnownTypes.m_I2cTransferResult));
 result = top.Dereference();
-FAULT_ON_NULL(result);
+if (result == NULL)
+{
+    NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_MEMORY);
+}
🧰 Tools
🪛 cppcheck (2.10-2)

[error] 74-74: Unmatched '{'. Configuration

(syntaxError)

🧹 Nitpick comments (5)
src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp (1)

222-223: Reconsider Timeout Multiplier Logic

The timeout duration is doubled using estimatedDurationMiliseconds *= 2;. This arbitrary multiplier may not be sufficient for all scenarios, potentially leading to premature timeouts in long transactions. Consider implementing a dynamic scaling factor or allowing configuration of the timeout multiplier to improve reliability.

targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (1)

352-372: Consolidate Bus Index Validation

The bus index validation is spread across multiple switch cases. Consider creating a dedicated function or macro to validate and retrieve the palI2c instance based on the bus index. This improves code readability and maintainability.

Apply this diff to refactor bus index validation:

 NF_PAL_I2C *GetPalI2cInstance(uint8_t busIndex)
 {
     switch (busIndex)
     {
         case 1:
             return &I2C1_PAL;
         case 2:
             return &I2C2_PAL;
         // Add cases for other bus indexes
         default:
             return NULL;
     }
 }

 // Usage in NativeTransmit method
 palI2c = GetPalI2cInstance(busIndex);
 if (palI2c == NULL)
 {
     NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
 }
targets/TI_SimpleLink/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (2)

180-197: Consider adding documentation for buffer handling logic.

While the implementation is robust, adding comments explaining the write buffer handling logic would improve code maintainability.

Add comments like:

 // dereference the write and read SpanByte from the arguments
 writeSpanByte = stack.Arg1().Dereference();
 if (writeSpanByte != NULL)
 {
+    // Get buffer from SpanByte's underlying array
     // get buffer
     writeBuffer = writeSpanByte[SpanByte::FIELD___array].DereferenceArray();
     if (writeBuffer != NULL)
     {
+        // Calculate actual write size based on span length, not array size
         // get the size of the buffer by reading the number of elements in the CLR_RT_HeapBlock_Array
         palI2c->i2cTransaction.writeCount = writeBuffer->m_numOfElements;
     }
 }

288-301: Consider additional safety checks in cleanup.

While the cleanup properly unpins buffers, consider adding additional safety checks:

 if (hr != CLR_E_THREAD_WAITING)
 {
     // un-pin the buffers
-    if (writeBuffer != NULL && writeBuffer->IsPinned())
+    if (writeBuffer != NULL)
+    {
+        // Double-check if buffer is still valid before unpinning
+        CLR_RT_HeapBlock* pThis = stack.This();
+        if (pThis != NULL && writeBuffer->IsPinned())
+        {
+            writeBuffer->Unpin();
+        }
+    }
 }
targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.UsbStream/sys_dev_usbstream_native_System_Device_Usb_UsbStream.cpp (1)

250-250: Consider documenting long-running operation handling.

While the buffer pinning implementation is correct, adding documentation about the long-running operation check would improve code clarity.

Add comments like:

 if (isLongRunning && hr != CLR_E_THREAD_WAITING)
 {
+    // Only unpin buffer if operation is long-running and not waiting for thread completion
     // need to clean up the buffer, if this was not rescheduled
     if (dataBuffer != NULL && dataBuffer->IsPinned())
     {
         dataBuffer->Unpin();
     }
 }

Also applies to: 363-374

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 10dfd61 and 358f99d.

📒 Files selected for processing (6)
  • src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp (1 hunks)
  • targets/AzureRTOS/ST/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (1 hunks)
  • targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (3 hunks)
  • targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.UsbStream/sys_dev_usbstream_native_System_Device_Usb_UsbStream.cpp (4 hunks)
  • targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (1 hunks)
  • targets/TI_SimpleLink/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: nf-interpreter (Check_Code_Style)
  • GitHub Check: nf-interpreter (Nightly build) (Build_STM32_targets ST_NUCLEO64_F091RC)
  • GitHub Check: nf-interpreter (Nightly build) (Build_STM32_targets ORGPAL_PALX)
  • GitHub Check: nf-interpreter (Nightly build) (Build_STM32_targets ORGPAL_PALTHREE)
  • GitHub Check: nf-interpreter (Nightly build) (Check_Build_Options)
  • GitHub Check: nf-interpreter (Check_Build_Options)
🔇 Additional comments (11)
src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp (1)

284-297: Verify Unpinning of Buffers in All Execution Paths

In the NANOCLR_CLEANUP() section, buffers are unpinned if hr != CLR_E_THREAD_WAITING. Ensure that in all possible execution paths, especially in error conditions or exceptions, the buffers are properly unpinned to prevent memory leaks or locked resources.

Run the following script to verify that all exit points correctly unpin the buffers:

✅ Verification successful

Buffer Unpinning Implementation is Correct

The cleanup section properly handles buffer unpinning in all execution paths. The implementation:

  • Only unpins buffers that were previously pinned (using IsPinned() check)
  • Includes NULL checks to prevent invalid operations
  • Correctly skips unpinning when thread is waiting (hr == CLR_E_THREAD_WAITING)
  • Handles both regular array buffers and SpanByte scenarios
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for proper unpinning of writeBuffer and readBuffer in all exit paths.

# Search for all return statements and verify buffer unpinning before them.
rg 'return' -A 5 src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp | grep -B 5 -A 5 'Unpin'

Length of output: 112


Script:

#!/bin/bash
# Get the complete function implementation containing NANOCLR_CLEANUP
ast-grep --pattern 'NANOCLR_NTSTATUS Library_sys_dev_spi_native_System_Device_Spi_SpiDevice_$$$($$$) {
  $$$
}'

# Search for NANOCLR_CLEANUP macro usage and definition
rg "NANOCLR_CLEANUP" -B 5 -A 5

# Look for Pin/Unpin operations
rg "Pin|Unpin" -B 2 -A 2

Length of output: 75924


Script:

#!/bin/bash
# Get the complete implementation of the SPI transfer method
ast-grep --pattern 'HRESULT Library_sys_dev_spi_native_System_Device_Spi_SpiDevice_$$$($$$) {
  $$$
}'

# Look for Pin/Unpin operations in the SPI file
rg "Pin|Unpin" src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp -B 5 -A 5

Length of output: 2967

targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (2)

658-659: Ensure Cache Coherency After DMA Read Operations

After the read operation, cache invalidation is performed for Cortex-M7 processors. Ensure that this operation is also performed for other processors where necessary or confirm that it's not required due to hardware coherence.


663-677: Verify Proper Unpinning of Buffers

In the cleanup section, buffers are unpinned if they were pinned earlier. Ensure that this unpinning occurs even if an exception is thrown before the buffers are unpinned. This can prevent memory leaks or other unintended behavior.

Run the following script to check for unpinned buffers in all exit paths:

✅ Verification successful

Buffer Handling is Safe and Correct

The current implementation properly handles buffer pinning and unpinning:

  • Buffers are only pinned after thorough validation
  • Early exits occur before any pinning operations
  • The cleanup section correctly unpins both buffers in all relevant scenarios
  • The thread waiting check prevents premature unpinning during async operations
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that writeBuffer and readBuffer are unpinned in all exit paths.

# Search for return or leave statements and check for unpinning
rg 'NANOCLR_CLEANUP_END\(\)' -A 10 targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp

Length of output: 160


Script:

#!/bin/bash
# Get the complete function implementation
ast-grep --pattern 'HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice::NativeTransmit$$$'

# Look for early exits
rg "NANOCLR_SET_AND_LEAVE" targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp

Length of output: 472


Script:

#!/bin/bash
# Get the complete function implementation with context
rg -B 10 -A 10 "NativeTransmit" targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp

Length of output: 717


Script:

#!/bin/bash
# Get the complete function implementation with larger context
rg -B 10 -A 100 "HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice::NativeTransmit" targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp

Length of output: 192


Script:

#!/bin/bash
# Search with shorter unique name part and larger context
rg -B 50 -A 100 "NativeTransmit___SystemDeviceI2cI2cTransferResult" targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp

# Look specifically for buffer operations
rg "buffer.*Pin|Pin.*buffer" targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp

Length of output: 5159

targets/AzureRTOS/ST/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (1)

728-732: Ensure Cache Invalidation is Implemented Where Necessary

The cache invalidation after DMA operations is marked as required only for Cortex-M7 processors. Verify whether other processors (e.g., Cortex-M4, Cortex-M33) with data caches require similar invalidation to maintain data coherence.

Consult the processor documentation or run the following script to check for other processors with caches:

✅ Verification successful

Cache Invalidation Implementation is Correct

The comment "only required for Cortex-M7" is accurate. Among the Cortex-M processors used in the codebase (M0, M4, M7), only the Cortex-M7 has a data cache that requires invalidation after DMA operations. Other processors like Cortex-M4 only have instruction cache, and Cortex-M0 has no cache at all, making this operation unnecessary for them.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Identify processors that have data caches enabled.

# List processor definitions that might have data caches
rg 'defined\(Cortex-M[4-7]XX\)' targets/AzureRTOS/ST/ -A 5

Length of output: 60


Script:

#!/bin/bash
# Search for cache-related functions and processor configurations
echo "=== Cache-related functions ==="
rg "cache.*invalidate|invalidate.*cache" -i

echo -e "\n=== Processor configurations ==="
rg "CORTEX_M[0-9]" -i

echo -e "\n=== Cache management implementations ==="
rg "SCB_InvalidateDCache|SCB_CleanDCache" -i

Length of output: 19003

targets/TI_SimpleLink/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (3)

143-155: Well-structured variable declarations!

The code demonstrates good organization with clear separation of buffer-related variables and proper initialization.


199-215: Consistent read buffer handling implementation!

The read buffer handling follows the same robust pattern as write buffer handling, maintaining code consistency.


224-235: Excellent implementation of buffer pinning!

The code properly pins both write and read buffers before DMA operations, effectively protecting them from GC relocation. This implementation aligns perfectly with the PR's objective of replacing CLR_RT_ProtectFromGC with buffer pinning.

targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.UsbStream/sys_dev_usbstream_native_System_Device_Usb_UsbStream.cpp (1)

108-108: Proper buffer pinning implementation in Read method!

The code correctly pins the buffer before DMA operations and implements proper cleanup with thread state verification.

Also applies to: 203-214

targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (3)

475-477: Well-documented write buffer pinning!

The code properly pins the write buffer for DMA operations with clear comments explaining the purpose.


501-503: Consistent read buffer pinning implementation!

The read buffer pinning follows the same well-documented pattern as write buffer pinning.


731-748: Robust cleanup implementation!

The cleanup properly handles both write and read buffers, with appropriate thread state verification before unpinning.

- Replaced CLR_RT_ProtectFromGC with pinning buffer HB.
- Pinned buffer HB where missing it.
@josesimoes josesimoes force-pushed the pinning-data-buffers branch from 358f99d to 87b3308 Compare January 9, 2025 13:25
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp (1)

189-250: Consider adjusting the timeout calculation for edge cases.

The timeout is set to twice the estimated duration, but this might not be sufficient for all scenarios, especially in systems under heavy load or with slower clock speeds.

Consider using a larger multiplier or adding a minimum timeout value:

-estimatedDurationMiliseconds *= 2;
+// Use 3x estimated time or minimum 100ms, whichever is larger
+estimatedDurationMiliseconds = MAX(estimatedDurationMiliseconds * 3, 100);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 358f99d and 87b3308.

📒 Files selected for processing (6)
  • src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp (1 hunks)
  • targets/AzureRTOS/ST/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (1 hunks)
  • targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (6 hunks)
  • targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.UsbStream/sys_dev_usbstream_native_System_Device_Usb_UsbStream.cpp (4 hunks)
  • targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (1 hunks)
  • targets/TI_SimpleLink/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.UsbStream/sys_dev_usbstream_native_System_Device_Usb_UsbStream.cpp
  • targets/TI_SimpleLink/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp
🧰 Additional context used
📓 Learnings (2)
targets/AzureRTOS/ST/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (1)
Learnt from: josesimoes
PR: nanoframework/nf-interpreter#3062
File: targets/AzureRTOS/ST/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp:393-410
Timestamp: 2025-01-09T13:18:50.055Z
Learning: In nanoFramework's I2C implementation for STM32 targets, the palI2c pointer is always assigned to a static PAL instance (I2C1_PAL, I2C2_PAL, etc.) through an exhaustive switch statement. Invalid bus indices are caught by the default case, making NULL checks on palI2c unnecessary after the switch statement.
src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp (1)
Learnt from: josesimoes
PR: nanoframework/nf-interpreter#3062
File: src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp:77-93
Timestamp: 2025-01-09T13:10:31.388Z
Learning: In nanoFramework SPI transactions, NULL buffers are valid cases when there is no data to send or receive. The code should handle NULL buffers by setting corresponding sizes to 0 instead of throwing exceptions.
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: nf-interpreter (Nightly build) (Build_STM32_targets ST_NUCLEO64_F091RC)
  • GitHub Check: nf-interpreter (Nightly build) (Build_STM32_targets ORGPAL_PALX)
  • GitHub Check: nf-interpreter (Nightly build) (Build_STM32_targets ORGPAL_PALTHREE)
  • GitHub Check: nf-interpreter (Check_Code_Style)
  • GitHub Check: nf-interpreter (Nightly build) (Check_Build_Options)
  • GitHub Check: nf-interpreter (Check_Build_Options)
🔇 Additional comments (5)
src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp (2)

77-93: Well-structured variable declarations!

The code follows good practices with proper initialization of pointers and appropriate type usage for different variables.


286-297: Robust cleanup implementation!

The cleanup logic properly handles buffer unpinning and checks the thread state before performing cleanup operations.

targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (1)

Line range hint 1-753: Implementation follows established patterns.

The changes in this file mirror the improvements made in the SPI implementation, including buffer pinning, error handling, and resource cleanup.

targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (1)

Line range hint 1-749: Platform-specific implementation follows established patterns.

The changes align with the improvements made in other I2C implementations, adapted for the SiliconLabs platform.

targets/AzureRTOS/ST/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (1)

392-753: Platform-specific implementation follows established patterns.

The changes align with the improvements made in other I2C implementations, adapted for the ST platform.

nfbot and others added 2 commits January 9, 2025 13:30
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp (1)

106-134: Add error handling for buffer operations.

While the buffer pinning implementation is correct, consider adding error handling for:

  1. GetFirstElementUInt16() operations
  2. Memory allocation for large buffers

Apply this diff to add error handling:

 if (writeBuffer != NULL)
 {
+    // Check if buffer allocation is successful
+    FAULT_ON_NULL(writeBuffer->GetFirstElementUInt16());
     writeData = (unsigned char *)writeBuffer->GetFirstElementUInt16();
     writeSize = writeBuffer->m_numOfElements;
     writeBuffer->Pin();
 }
targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (1)

461-512: Add documentation for DMA requirements.

While the buffer pinning implementation is correct, it would be helpful to add a comment explaining why pinning is required for DMA operations.

Add this comment before pinning operations:

+    // Pin buffers to prevent GC from moving them during DMA operations
     writeBuffer->Pin();
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 87b3308 and eb2cf31.

📒 Files selected for processing (2)
  • src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp (1 hunks)
  • targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (1 hunks)
🧰 Additional context used
📓 Learnings (1)
src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp (1)
Learnt from: josesimoes
PR: nanoframework/nf-interpreter#3062
File: src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp:77-93
Timestamp: 2025-01-09T13:10:31.388Z
Learning: In nanoFramework SPI transactions, NULL buffers are valid cases when there is no data to send or receive. The code should handle NULL buffers by setting corresponding sizes to 0 instead of throwing exceptions.
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: nf-interpreter (Nightly build) (Build_STM32_targets ST_NUCLEO64_F091RC)
  • GitHub Check: nf-interpreter (Nightly build) (Build_STM32_targets ORGPAL_PALX)
  • GitHub Check: nf-interpreter (Nightly build) (Build_STM32_targets ORGPAL_PALTHREE)
  • GitHub Check: nf-interpreter (Check_Code_Style)
  • GitHub Check: nf-interpreter (Nightly build) (Check_Build_Options)
  • GitHub Check: nf-interpreter (Check_Build_Options)
🔇 Additional comments (4)
src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp (3)

77-94: Well-structured variable declarations!

Good organization of variables with clear separation between SpanByte and Array handling. Proper initialization of pointers to NULL and sizes to 0.


135-188: Correct implementation of SpanByte buffer handling!

The implementation correctly:

  • Handles NULL buffers by setting sizes to 0
  • Manages buffer offsets properly
  • Implements buffer pinning at the right point

288-300: Robust cleanup implementation!

The cleanup section correctly:

  • Checks thread state before cleanup
  • Verifies pinned state before unpinning
  • Handles both buffers independently
targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp (1)

733-747: Solid cleanup implementation!

The cleanup section correctly:

  • Checks thread state before cleanup
  • Safely unpins buffers
  • Follows the same robust pattern as the SPI implementation

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp (2)

109-120: Add error handling for GetFirstElementUInt16()

While the buffer pinning is correctly implemented, consider adding error handling for GetFirstElementUInt16() to ensure robustness:

 writeBuffer = stack.Arg1().DereferenceArray();
 if (writeBuffer != NULL)
 {
     // grab the pointer to the array by getting the first element of the array
-    writeData = (unsigned char *)writeBuffer->GetFirstElementUInt16();
+    HRESULT hr = writeBuffer->GetFirstElementUInt16((CLR_UINT16*&)writeData);
+    NANOCLR_CHECK_HRESULT(hr);

     // get the size of the buffer by reading the number of elements in the HeapBlock array
     writeSize = writeBuffer->m_numOfElements;

     // pin the buffer
     writeBuffer->Pin();
 }

222-223: Consider defining a constant for the timeout multiplier

The timeout calculation uses a magic number (2) for the multiplier. Consider defining this as a named constant to improve code maintainability:

+    // Timeout multiplier for long-running operations
+    static const uint32_t TIMEOUT_MULTIPLIER = 2;
+
     // Use twice the estimated Duration as timeout
-    estimatedDurationMiliseconds *= 2;
+    estimatedDurationMiliseconds *= TIMEOUT_MULTIPLIER;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eb2cf31 and cbf00f6.

📒 Files selected for processing (1)
  • src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp (1 hunks)
🧰 Additional context used
📓 Learnings (1)
src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp (1)
Learnt from: josesimoes
PR: nanoframework/nf-interpreter#3062
File: src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp:77-93
Timestamp: 2025-01-09T13:10:31.388Z
Learning: In nanoFramework SPI transactions, NULL buffers are valid cases when there is no data to send or receive. The code should handle NULL buffers by setting corresponding sizes to 0 instead of throwing exceptions.
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: nf-interpreter (Nightly build) (Build_STM32_targets ST_NUCLEO64_F091RC)
  • GitHub Check: nf-interpreter (Nightly build) (Build_STM32_targets ORGPAL_PALX)
  • GitHub Check: nf-interpreter (Nightly build) (Build_STM32_targets ORGPAL_PALTHREE)
  • GitHub Check: nf-interpreter (Check_Code_Style)
  • GitHub Check: nf-interpreter (Nightly build) (Check_Build_Options)
  • GitHub Check: nf-interpreter (Check_Build_Options)
🔇 Additional comments (3)
src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp (3)

77-94: Well-structured variable declarations!

The variables are properly initialized with appropriate types and clear separation between buffer pointers and data pointers.


137-188: Excellent implementation of SpanByte handling!

The code demonstrates thorough handling of:

  • Proper offset and length management from SpanByte
  • Correct NULL buffer handling
  • Buffer pinning for GC protection

286-302: Robust cleanup implementation!

The cleanup section demonstrates excellent resource management:

  • Proper thread state checking
  • Safe buffer unpinning with pinned state verification
  • Comprehensive handling of both read and write buffers

@josesimoes josesimoes merged commit f86e48f into nanoframework:main Jan 9, 2025
28 checks passed
@josesimoes josesimoes deleted the pinning-data-buffers branch January 9, 2025 14:54
@coderabbitai coderabbitai bot mentioned this pull request Jan 9, 2025
13 tasks
@coderabbitai coderabbitai bot mentioned this pull request Feb 22, 2025
13 tasks
josesimoes added a commit that referenced this pull request Mar 17, 2025
***NO_CI***

(cherry picked from commit f86e48f)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: Common libs Everything related with common libraries Platform: Azure-RTOS Platform: NXP Everything related specifically with FreeRTOS Platform: STM32 Everything related specifically with ChibiOS platform Platform: TI-SimpleLink Type: bug Type: enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants