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

Implement a #[vtable] macro #322

Merged
merged 6 commits into from
Jul 5, 2022
Merged

Conversation

nbdd0121
Copy link
Member

Use a single #[vtable] macro to replace the current boilerplating of ToUse, USE_NONE, declare_file_operations` required for declaring and implementing traits that maps to Linux's pure vtables and contains optional methods.

This'll be more natural and less noisy than the current approach, and it paves the way for other vtables such as the one in #208 so that we don't need a ToUse, USE_NONE and a macro for each vtable trait.

Little note that this just scans the tokens so cannot handle case like

#[vtable]
impl Foo for Bar<{1 + 1}> {}

but this is very rare. I think we can live with this for now; we can always migrate to proper parsing later if we ever get syn vendored.

@ksquirrel

This comment has been minimized.

@ksquirrel
Copy link
Member

Review of a5003f241719:

  • ✔️ Commit a5003f2: Looks fine!

@nbdd0121
Copy link
Member Author

nbdd0121 commented Jun 1, 2021

I see this pattern in #264 again so we definitely want a single macro abstraction for all vtables.

@wedsonaf
Copy link

wedsonaf commented Jun 1, 2021

As you know, this is something that I wanted to do for file_operations and I do think it is more usable than what we have, however:

  1. We only really need this when the kernel behaves differently depending on the presence/absence (being null/non-null) of a function pointer. This is the case for file operations: we can't always replicate the kernel behaviour in our default implementations. I'm not sure how prevalent this is, we'd have to analyse it on a case-by-base basis. When we can easily replicate kernel behaviour with our default handlers though, it is much simpler to just use a regular trait and always generate non-null function pointers. No need for macros (procedural or otherwise). Do you know if Add SPI Abstraction #264 really need this?
  2. In the file_operations case, a single (generic) function may result in more than one function function. See for example read and write -- these functions can populate the read/read_iter and write/write_iter function pointers at the programmer's choosing: they may not always want both implemented. How does your macro handle this?
  3. I'm sorry to say this, but at the moment I think we're better off with the existing implementation. It's much simpler to follow than a procedural macro. In my view, the gains in usability ATM do not outweigh the added complexity.

@nbdd0121
Copy link
Member Author

nbdd0121 commented Jun 1, 2021

  1. We only really need this when the kernel behaves differently depending on the presence/absence (being null/non-null) of a function pointer. This is the case for file operations: we can't always replicate the kernel behaviour in our default implementations. I'm not sure how prevalent this is, we'd have to analyse it on a case-by-base basis. When we can easily replicate kernel behaviour with our default handlers though, it is much simpler to just use a regular trait and always generate non-null function pointers. No need for macros (procedural or otherwise). Do you know if Add SPI Abstraction #264 really need this?

I don't know if #264 need this, but #208 certainly do.

  1. In the file_operations case, a single (generic) function may result in more than one function function. See for example read and write -- these functions can populate the read/read_iter and write/write_iter function pointers at the programmer's choosing: they may not always want both implemented. How does your macro handle this?

Are there reasons not to implement read_iter/write_iter? The current trait design essentially guarantees that it either both or none are supported. Without specialization, it makes no sense to support one but not another. If we really want to let the implementor decide, then generics should not be used.

If we do want them to opt out (rather than opt in), we can just add a manual const HAS_READ_ITER: bool = true; and ask the implementor to define const HAS_READ_ITER: bool = false; to opt out. This way it makes it clear that they do not want to have read_iter/write_iter instead of forgetting to putting them in the declaration.

  1. I'm sorry to say this, but at the moment I think we're better off with the existing implementation. It's much simpler to follow than a procedural macro. In my view, the gains in usability ATM do not outweigh the added complexity.

I would suggest the opposite. I would also argue that it is also less complex than the current declarative macro. I got confused when I first saw the ToUse type, const and macro; it is much simpler to say, put on the #[vtable] attribute when you implement this. If people want to know why it is necessary, the vtable macro description provides a central source of information about the design choice, not a dozen of macros each doing exactly the same thing.

This procedural macro is simpler to use, less error prone, less code, less boilerplate, and generate a good documentation. 60 lines of boilerplate for each vtable and hours of debugging caused by forgetting to add the name of method to the declare_*! macro, vs. 80 lines of proc macro, I think I am strongly in favor of the latter.

@nbdd0121
Copy link
Member Author

nbdd0121 commented Jun 1, 2021

I don't understand why you're so against proc macros, but I want to make one point: any complexities in proc macros are used to reduce complexities elsewhere. As long as the reduced complexities outweigh the introduced complexities, we should definitely go for it.

As for this case, given that there we are going to have at least 2 (maybe 3) trait users and a couple impl users of this macro, and certainly more in the future, I believe the macro certainly reduces the overall complexity.

@niklasmohrin niklasmohrin mentioned this pull request Jul 28, 2021
11 tasks
const_items = "const USE_VTABLE_ATTR: () = ();".to_owned();

for f in functions {
write!(const_items, "const HAS_{}: bool = true;", f.to_uppercase()).unwrap();
Copy link
Member

Choose a reason for hiding this comment

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

line 66 adds a doc comment about the const value, which is missing in this line.

Copy link
Member Author

Choose a reason for hiding this comment

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

It's intentional to have doc comment only in trait but not in impls.

Copy link
Member

Choose a reason for hiding this comment

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

Than I misread. Then nevermind

@nbdd0121 nbdd0121 force-pushed the macros branch 2 times, most recently from fa059e1 to bcb1aed Compare July 2, 2022 22:14
@@ -9,6 +9,7 @@

#![allow(dead_code)]

use crate::prelude::*;
Copy link

Choose a reason for hiding this comment

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

nit: are you including the prelude just for vtable? If so, I think it's better to add macros::vtable to the list below.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it should generally be fine to include prelude. I could remove the Error and Result import so that this import is used more than just vtable.

Copy link

Choose a reason for hiding this comment

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

Even if you want to include prelude::*, you should add it to the line below for consistency.

Now, given the choice of adding macros::vtable or prelude::*, I think the former is preferable because we don't pollute the namespace with more symbols than needed. (prelude is meant for drivers.)

You're obviously welcome to disagree with our handling or prelude, but in that case I'd argue that you're unnecessarily conflating issues: let's open another PR or issue to discuss that if you'd like. I'm ready to merge this once we come to an agreement on the use clause.

rust/macros/vtable.rs Outdated Show resolved Hide resolved
Use a single `#[vtable]` macro to replace the current boilerplating
of `ToUse`, `USE_NONE`, `declare_file_operations` required for
declaring and implementing traits that maps to Linux's pure vtables and
contains optional methods.

Signed-off-by: Gary Guo <[email protected]>
@wedsonaf wedsonaf merged commit ec966c7 into Rust-for-Linux:rust Jul 5, 2022
@wedsonaf
Copy link

wedsonaf commented Jul 5, 2022

Thank you, @nbdd0121!

ojeda pushed a commit that referenced this pull request Dec 16, 2024
On Raspberry Pis without onboard USB hub frequent device reconnects
can trigger a interrupt storm after DWC2 entered host clock gating.
This is caused by a race between _dwc2_hcd_suspend() and the port
interrupt, which sets port_connect_status. The issue occurs if
port_connect_status is still 1, but there is no connection anymore:

usb 1-1: USB disconnect, device number 25
dwc2 3f980000.usb: _dwc2_hcd_suspend: port_connect_status: 1
dwc2 3f980000.usb: Entering host clock gating.
Disabling IRQ #66
irq 66: nobody cared (try booting with the "irqpoll" option)
CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 6.12.0-gc1bb81b13202-dirty #322
Hardware name: BCM2835
Call trace:
 unwind_backtrace from show_stack+0x10/0x14
 show_stack from dump_stack_lvl+0x50/0x64
 dump_stack_lvl from __report_bad_irq+0x38/0xc0
 __report_bad_irq from note_interrupt+0x2ac/0x2f4
 note_interrupt from handle_irq_event+0x88/0x8c
 handle_irq_event from handle_level_irq+0xb4/0x1ac
 handle_level_irq from generic_handle_domain_irq+0x24/0x34
 generic_handle_domain_irq from bcm2836_chained_handle_irq+0x24/0x28
 bcm2836_chained_handle_irq from generic_handle_domain_irq+0x24/0x34
 generic_handle_domain_irq from generic_handle_arch_irq+0x34/0x44
 generic_handle_arch_irq from __irq_svc+0x88/0xb0
 Exception stack(0xc1d01f20 to 0xc1d01f68)
 1f20: 0004ef3c 00000001 00000000 00000000 c1d09780 c1f6bb5c c1d04e54 c1c60ca8
 1f40: c1d04e94 00000000 00000000 c1d092a8 c1f6af20 c1d01f70 c1211b98 c1212f40
 1f60: 60000013 ffffffff
 __irq_svc from default_idle_call+0x1c/0xb0
 default_idle_call from do_idle+0x21c/0x284
 do_idle from cpu_startup_entry+0x28/0x2c
 cpu_startup_entry from kernel_init+0x0/0x12c
handlers:
 [<e3a25c00>] dwc2_handle_common_intr
 [<58bf98a3>] usb_hcd_irq
Disabling IRQ #66

So avoid this by reading the connection status directly.

Fixes: 113f86d ("usb: dwc2: Update partial power down entering by system suspend")
Signed-off-by: Stefan Wahren <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Greg Kroah-Hartman <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

4 participants