// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2025 Google LLC.
use kernel::{
list::{AtomicTracker, List, ListArc, ListLinks, TryNewListArc},
prelude::*,
seq_file::SeqFile,
seq_print,
sync::lock::{spinlock::SpinLockBackend, Guard},
sync::{Arc, LockedBy, SpinLock},
};
use crate::{
defs::*,
error::BinderError,
process::{NodeRefInfo, Process, ProcessInner},
thread::Thread,
transaction::Transaction,
BinderReturnWriter, DArc, DLArc, DTRWrap, DeliverToRead,
};
use core::mem;
mod wrapper;
pub(crate) use self::wrapper::CritIncrWrapper;
#[derive(Debug)]
pub(crate) struct CouldNotDeliverCriticalIncrement;
/// Keeps track of how this node is scheduled.
///
/// There are two ways to schedule a node to a work list. Just schedule the node itself, or
/// allocate a wrapper that references the node and schedule the wrapper. These wrappers exists to
/// make it possible to "move" a node from one list to another - when `do_work` is called directly
/// on the `Node`, then it's a no-op if there's also a pending wrapper.
///
/// Wrappers are generally only needed for zero-to-one refcount increments, and there are two cases
/// of this: weak increments and strong increments. We call such increments "critical" because it
/// is critical that they are delivered to the thread doing the increment. Some examples:
///
/// * One thread makes a zero-to-one strong increment, and another thread makes a zero-to-one weak
/// increment. Delivering the node to the thread doing the weak increment is wrong, since the
/// thread doing the strong increment may have ended a long time ago when the command is actually
/// processed by userspace.
///
/// * We have a weak reference and are about to drop it on one thread. But then another thread does
/// a zero-to-one strong increment. If the strong increment gets sent to the thread that was
/// about to drop the weak reference, then the strong increment could be processed after the
/// other thread has already exited, which would be too late.
///
/// Note that trying to create a `ListArc` to the node can succeed even if `has_normal_push` is
/// set. This is because another thread might just have popped the node from a todo list, but not
/// yet called `do_work`. However, if `has_normal_push` is false, then creating a `ListArc` should
/// always succeed.
///
/// Like the other fields in `NodeInner`, the delivery state is protected by the process lock.
struct DeliveryState {
/// Is the `Node` currently scheduled?
has_pushed_node: bool,
/// Is a wrapper currently scheduled?
///
/// The wrapper is used only for strong zero2one increments.
has_pushed_wrapper: bool,
/// Is the currently scheduled `Node` scheduled due to a weak zero2one increment?
///
/// Weak zero2one operations are always scheduled using the `Node`.
has_weak_zero2one: bool,
/// Is the currently scheduled wrapper/`Node` scheduled due to a strong zero2one increment?
///
/// If `has_pushed_wrapper` is set, then the strong zero2one increment was scheduled using the
/// wrapper. Otherwise, `has_pushed_node` must be set and it was scheduled using the `Node`.
has_strong_zero2one: bool,
}
impl DeliveryState {
fn should_normal_push(&self) -> bool {
!self.has_pushed_node && !self.has_pushed_wrapper
}
fn did_normal_push(&mut self) {
assert!(self.should_normal_push());
self.has_pushed_node = true;
}
fn should_push_weak_zero2one(&self) -> bool {
!self.has_weak_zero2one && !self.has_strong_zero2one
}
fn can_push_weak_zero2one_normally(&self) -> bool {
!self.has_pushed_node
}
fn did_push_weak_zero2one(&mut self) {
assert!(self.should_push_weak_zero2one());
assert!(self.can_push_weak_zero2one_normally());
self.has_pushed_node = true;
self.has_weak_zero2one = true;
}
fn should_push_strong_zero2one(&self) -> bool {
!self.has_strong_zero2one
}
fn can_push_strong_zero2one_normally(&self) -> bool {
!self.has_pushed_node
}
fn did_push_strong_zero2one(&mut self) {
assert!(self.should_push_strong_zero2one());
assert!(self.can_push_strong_zero2one_normally());
self.has_pushed_node = true;
self.has_strong_zero2one = true;
}
fn did_push_strong_zero2one_wrapper(&mut self) {
assert!(self.should_push_strong_zero2one());
assert!(!self.can_push_strong_zero2one_normally());
self.has_pushed_wrapper = true;
self.has_strong_zero2one = true;
}
}
struct CountState {
/// The reference count.
count: usize,
/// Whether the process that owns this node thinks that we hold a refcount on it. (Note that
/// even if count is greater than one, we only increment it once in the owning process.)
has_count: