Skip to content
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

Fix unix changing from real-time to normal policy #39

Merged
merged 2 commits into from
Apr 29, 2024

Conversation

kmdade
Copy link
Contributor

@kmdade kmdade commented Apr 28, 2024

Thank you for authoring this very helpful library.

I noticed that nothing was happening when attempting to modify the policy of a real-time thread, and I believe I have identified the issue.

Changes

  • A unit test is added to demonstrate the previously failing behavior.
  • The function set_thead_priority_and_policy() is updated to also call pthread_setschedparam when setting a "normal" policy so that the thread schedule policy is updated in addition to the nice value.

Additional Notes

I develop on MacOS and Ubuntu, and have tested on both platforms. I admittedly did not familiarize myself with the overall cross-platform test plan, and will gladly follow any instructions. Suggested improvements to implementation or style are welcome, thank you for considering these changes.

Summary by CodeRabbit

  • New Features

    • Enhanced thread priority management to set static priority 0 for normal priority threads and adjust relative priority through niceness.
  • Tests

    • Added a test to verify correct behavior when switching between realtime and normal thread policies, ensuring appropriate capabilities are required.
    • Updated and added various test scenarios related to thread policy management.

No effect when changing from real-time to normal policy.
Copy link

coderabbitai bot commented Apr 28, 2024

Walkthrough

The recent updates refine thread priority management in Unix systems by setting a fixed priority for normal threads and adjusting relative priority via niceness. A new test ensures changes between realtime and normal policies require appropriate capabilities, enhancing system robustness and compliance.

Changes

File Path Change Summary
src/unix.rs Adjusted thread priority handling and added tests for policy changes requiring specific capabilities.

🐇✨
In the land of code, where threads intertwine,
A rabbit hopped through, making changes so fine.
Priority set, and niceness well-tuned,
With tests to ensure nothing's presumed.
Hop, hop, hop, on soft silent paws,
CodeRabbit improves without pause! 🌟
🐇💻


Recent Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between 17539c0 and 72bdeb7.
Files selected for processing (1)
  • src/unix.rs (2 hunks)
Additional Context Used
AST-based Instructions (13)
src/unix.rs (13)

[warning] 45-57: Found use of unsafe code. Unsafe code should be avoided whenever possible. Instead, prefer safe code and use unsafe code only when necessary.
Context: unsafe {
cfg_if::cfg_if! {
if #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "android"))] {
*libc::__errno()
} else if #[cfg(target_os = "linux")] {
*libc::__errno_location()
} else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] {
*libc::__error()
} else {
compile_error!("Your OS is probably not supported.")
}
}
}
Note: [CWE-242]: Use of Inherently Dangerous Function [REFERENCES]
- https://doc.rust-lang.org/std/keyword.unsafe.html


[warning] 61-73: Found use of unsafe code. Unsafe code should be avoided whenever possible. Instead, prefer safe code and use unsafe code only when necessary.
Context: unsafe {
cfg_if::cfg_if! {
if #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "android"))] {
*libc::__errno() = number;
} else if #[cfg(target_os = "linux")] {
*libc::__errno_location() = number;
} else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] {
*libc::__error() = number;
} else {
compile_error!("Your OS is probably not supported.")
}
}
}
Note: [CWE-242]: Use of Inherently Dangerous Function [REFERENCES]
- https://doc.rust-lang.org/std/keyword.unsafe.html


[warning] 114-114: Found use of unsafe code. Unsafe code should be avoided whenever possible. Instead, prefer safe code and use unsafe code only when necessary.
Context: unsafe { MaybeUninit::libc::sched_param::zeroed().assume_init() }
Note: [CWE-242]: Use of Inherently Dangerous Function [REFERENCES]
- https://doc.rust-lang.org/std/keyword.unsafe.html


[warning] 150-158: Found use of unsafe code. Unsafe code should be avoided whenever possible. Instead, prefer safe code and use unsafe code only when necessary.
Context: unsafe {
libc::syscall(
libc::SYS_sched_getattr,
current_thread,
&mut sched_attr as *mut _,
std::mem::size_of::() as u32,
flags,
)
}
Note: [CWE-242]: Use of Inherently Dangerous Function [REFERENCES]
- https://doc.rust-lang.org/std/keyword.unsafe.html


[warning] 364-364: Found use of unsafe code. Unsafe code should be avoided whenever possible. Instead, prefer safe code and use unsafe code only when necessary.
Context: unsafe { libc::sched_get_priority_max(policy.to_posix()) }
Note: [CWE-242]: Use of Inherently Dangerous Function [REFERENCES]
- https://doc.rust-lang.org/std/keyword.unsafe.html


[warning] 369-369: Found use of unsafe code. Unsafe code should be avoided whenever possible. Instead, prefer safe code and use unsafe code only when necessary.
Context: unsafe { libc::sched_get_priority_min(policy.to_posix()) }
Note: [CWE-242]: Use of Inherently Dangerous Function [REFERENCES]
- https://doc.rust-lang.org/std/keyword.unsafe.html


[warning] 530-530: Found use of unsafe code. Unsafe code should be avoided whenever possible. Instead, prefer safe code and use unsafe code only when necessary.
Context: unsafe { libc::syscall(libc::SYS_sched_setattr, tid, &sched_attr as *const _, 0) as i32 }
Note: [CWE-242]: Use of Inherently Dangerous Function [REFERENCES]
- https://doc.rust-lang.org/std/keyword.unsafe.html


[warning] 585-591: Found use of unsafe code. Unsafe code should be avoided whenever possible. Instead, prefer safe code and use unsafe code only when necessary.
Context: unsafe {
libc::pthread_setschedparam(
native,
policy.to_posix(),
&params as *const libc::sched_param,
)
}
Note: [CWE-242]: Use of Inherently Dangerous Function [REFERENCES]
- https://doc.rust-lang.org/std/keyword.unsafe.html


[warning] 601-607: Found use of unsafe code. Unsafe code should be avoided whenever possible. Instead, prefer safe code and use unsafe code only when necessary.
Context: unsafe {
libc::pthread_setschedparam(
native,
policy.to_posix(),
&params as *const libc::sched_param,
)
}
Note: [CWE-242]: Use of Inherently Dangerous Function [REFERENCES]
- https://doc.rust-lang.org/std/keyword.unsafe.html


[warning] 615-615: Found use of unsafe code. Unsafe code should be avoided whenever possible. Instead, prefer safe code and use unsafe code only when necessary.
Context: unsafe { libc::setpriority(libc::PRIO_PROCESS, 0, fixed_priority) }
Note: [CWE-242]: Use of Inherently Dangerous Function [REFERENCES]
- https://doc.rust-lang.org/std/keyword.unsafe.html


[warning] 672-688: Found use of unsafe code. Unsafe code should be avoided whenever possible. Instead, prefer safe code and use unsafe code only when necessary.
Context: unsafe {
let mut policy = 0i32;
let mut params = ScheduleParams { sched_priority: 0 }.into_posix();

    let ret = libc::pthread_getschedparam(
        native,
        &mut policy as *mut libc::c_int,
        &mut params as *mut libc::sched_param,
    );
    match ret {
        0 => Ok((
            ThreadSchedulePolicy::from_posix(policy)?,
            ScheduleParams::from_posix(params),
        )),
        e => Err(Error::OS(e)),
    }
}

Note: [CWE-242]: Use of Inherently Dangerous Function [REFERENCES]
- https://doc.rust-lang.org/std/keyword.unsafe.html


[warning] 806-806: Found use of unsafe code. Unsafe code should be avoided whenever possible. Instead, prefer safe code and use unsafe code only when necessary.
Context: unsafe { libc::pthread_self() }
Note: [CWE-242]: Use of Inherently Dangerous Function [REFERENCES]
- https://doc.rust-lang.org/std/keyword.unsafe.html


[warning] 865-865: Found use of unsafe code. Unsafe code should be avoided whenever possible. Instead, prefer safe code and use unsafe code only when necessary.
Context: unsafe { libc::getpriority(0, 0) }
Note: [CWE-242]: Use of Inherently Dangerous Function [REFERENCES]
- https://doc.rust-lang.org/std/keyword.unsafe.html

Additional comments not posted (1)
src/unix.rs (1)

870-870: The changes to set_deadline_policy look good and are well-integrated with the rest of the system.


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>.
    • 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 generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @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.

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 as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration 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: 2

Out of diff range and nitpick comments (1)
src/unix.rs (1)

Line range hint 45-57: Minimize and document the use of unsafe code.

There are multiple instances of unsafe code throughout the file, primarily used for low-level system interactions. While some of this is necessary, it's important to ensure that each use of unsafe is justified, minimal, and accompanied by comments explaining why it is needed and what specific precautions were taken to avoid common pitfalls. This practice helps maintain the safety and readability of the code.

Also applies to: 61-73, 114-114, 150-158, 364-364, 369-369, 530-530, 585-591, 601-607, 617-617, 677-693, 811-811, 870-870

src/unix.rs Outdated
Comment on lines 599 to 614
// Normal priority threads must be set with static priority 0.
let params = ScheduleParams { sched_priority: 0 }.into_posix();

let ret = unsafe {
libc::pthread_setschedparam(
native,
policy.to_posix(),
&params as *const libc::sched_param,
)
};

match ret {
0 => Ok(()),
e => Err(Error::OS(e)),
}?;

// Normal priority threads adjust relative priority through niceness.
Copy link

@coderabbitai coderabbitai bot Apr 28, 2024

Choose a reason for hiding this comment

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

Consider simplifying the error handling in the normal thread priority setting.

The current implementation uses a match statement to handle the return value of pthread_setschedparam, followed by a separate error check for setpriority. This could be streamlined by consolidating the error handling into a single block, improving readability and maintainability. Here's a proposed refactor:

let ret = unsafe {
    libc::pthread_setschedparam(
        native,
        policy.to_posix(),
        &params as *const libc::sched_param,
    )
};
if ret != 0 {
    return Err(Error::OS(ret));
}

set_errno(0);
let ret = unsafe { libc::setpriority(libc::PRIO_PROCESS, 0, fixed_priority) };
if ret != 0 {
    return Err(Error::OS(errno()));
}

Ok(())

Copy link
Owner

Choose a reason for hiding this comment

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

I think this is a good suggestion.

Copy link

Choose a reason for hiding this comment

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

@iddm, thank you for your feedback! I'm glad you found the suggestion helpful. If you have any more questions or need further assistance, feel free to ask. Happy coding! 😊


If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!

src/unix.rs Show resolved Hide resolved
@iddm
Copy link
Owner

iddm commented Apr 28, 2024

Hi, @kmdade!
Thank you very much for the kind words and your contribution! I find it valid, and it is an overlook on my side. There is, however, only one stylistic comment, which also applies to the code above yours (mine). Please take a look at the comment made by CodeRabbit AI.

@kmdade kmdade force-pushed the fix-unix-changing-between-policies branch from f36ad97 to 72bdeb7 Compare April 28, 2024 23:09
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: 2

Comment on lines +599 to +621
// Normal priority threads must be set with static priority 0.
let params = ScheduleParams { sched_priority: 0 }.into_posix();

let ret = unsafe { libc::setpriority(libc::PRIO_PROCESS, 0, fixed_priority) };
if ret == 0 {
return Ok(());
let ret = unsafe {
libc::pthread_setschedparam(
native,
policy.to_posix(),
&params as *const libc::sched_param,
)
};

if ret != 0 {
return Err(Error::OS(ret));
}

match errno() {
0 => Ok(()),
e => Err(Error::OS(e)),
// Normal priority threads adjust relative priority through niceness.
set_errno(0);
let ret = unsafe { libc::setpriority(libc::PRIO_PROCESS, 0, fixed_priority) };
if ret != 0 {
return Err(Error::OS(errno()));
}

Ok(())
Copy link

Choose a reason for hiding this comment

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

Consider consolidating error handling for clarity and maintainability.

The current implementation handles errors from pthread_setschedparam and setpriority in separate blocks. This could be streamlined by consolidating the error handling into a single block, improving readability and maintainability. Here's a proposed refactor:

let ret = unsafe {
    libc::pthread_setschedparam(
        native,
        policy.to_posix(),
        &params as *const libc::sched_param,
    )
};
if ret != 0 {
    return Err(Error::OS(ret));
}

set_errno(0);
let ret = unsafe { libc::setpriority(libc::PRIO_PROCESS, 0, fixed_priority) };
if ret != 0 {
    return Err(Error::OS(errno()));
}

Ok(())

Comment on lines +834 to +869
#[test]
fn change_between_realtime_and_normal_policies_requires_capabilities() {
use crate::ThreadPriorityOsValue;

const TEST_PRIORITY: u8 = 15;

let realtime_policy = ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Fifo);
let normal_policy = ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Other);

// While we may desire an OS-specific priority, the reported value is always crossplatform.
let desired_priority = ThreadPriority::Os(ThreadPriorityOsValue(TEST_PRIORITY as _));
let expected_priority = ThreadPriority::Crossplatform(ThreadPriorityValue(TEST_PRIORITY));

let thread = std::thread::current();
thread
.set_priority_and_policy(realtime_policy, desired_priority)
.expect("to set realtime fifo policy");

assert_eq!(thread.get_schedule_policy(), Ok(realtime_policy));
assert_eq!(thread.get_priority(), Ok(expected_priority));

thread
.set_priority_and_policy(normal_policy, desired_priority)
.expect("to set normal other policy");

assert_eq!(thread.get_schedule_policy(), Ok(normal_policy));

// On linux, normal priority threads always have static priority 0. Instead the "nice" value is used.
#[cfg(not(target_os = "linux"))]
assert_eq!(thread.get_priority(), Ok(expected_priority));
#[cfg(target_os = "linux")]
{
let nice = unsafe { libc::getpriority(0, 0) };
assert_eq!(nice, TEST_PRIORITY as i32);
}
}
Copy link

Choose a reason for hiding this comment

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

Expand the test coverage in change_between_realtime_and_normal_policies_requires_capabilities.

The current test validates the basic functionality of changing policies and priorities. However, it could be beneficial to include more edge cases, such as invalid priorities or unsupported policies, to ensure robustness. Would you like me to help by adding these test cases?

@kmdade
Copy link
Contributor Author

kmdade commented Apr 28, 2024

The suggested change is applied.

@kmdade kmdade requested a review from iddm April 28, 2024 23:16
@iddm iddm merged commit 1135f2e into iddm:master Apr 29, 2024
10 checks passed
@iddm
Copy link
Owner

iddm commented Apr 29, 2024

Thank you! https://crates.io/crates/thread-priority/1.1.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants