From patchwork Tue Jul 23 18:09:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 13740252 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id B3D9DC3DA63 for ; Tue, 23 Jul 2024 18:11:45 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 3A6366B009C; Tue, 23 Jul 2024 14:11:45 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 37D376B009D; Tue, 23 Jul 2024 14:11:45 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 21D766B009E; Tue, 23 Jul 2024 14:11:45 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0011.hostedemail.com [216.40.44.11]) by kanga.kvack.org (Postfix) with ESMTP id 03B2F6B009C for ; Tue, 23 Jul 2024 14:11:44 -0400 (EDT) Received: from smtpin06.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay02.hostedemail.com (Postfix) with ESMTP id 9E81E12033C for ; Tue, 23 Jul 2024 18:11:44 +0000 (UTC) X-FDA: 82371810528.06.146627C Received: from sin.source.kernel.org (sin.source.kernel.org [145.40.73.55]) by imf12.hostedemail.com (Postfix) with ESMTP id 581BD40010 for ; Tue, 23 Jul 2024 18:11:41 +0000 (UTC) Authentication-Results: imf12.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=jzRMYXdL; spf=pass (imf12.hostedemail.com: domain of dakr@kernel.org designates 145.40.73.55 as permitted sender) smtp.mailfrom=dakr@kernel.org; dmarc=pass (policy=none) header.from=kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1721758255; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=degiQLL6SW/nvK42Iyzxff+yJMKE2WSy3me3PkqPOec=; b=a10qzPqty0AGA9RW+09cRp7fdV9hqgD4Y+ZTWDm4l920YaM8hc5igrKAEnl5pAeskhQdLa 6gRrQwh7OZ9GUCjfdrRBRj8o5cLjkzwAQR05YJmEwtnK9wFzZkA4jQqflspuWATGrtZ8MW xYup3IU8xvA1ncnFq0fo5ZZVSfQQ7Yg= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1721758255; a=rsa-sha256; cv=none; b=mISMqr0Z46R2diPYed+qf5kJgEqrrjRyLOZCkVKLoZvmdF4mRf5OfdBO65tG9wUMXWKlKC DzUVGY9p9brVEZIpz3hmvYFqNT5IlrwZjJQlYo873iFdhbq6OF/uHeH8cuxcH7I1+amF2c 7G8q2UjkFJMUAdEkx6B1nUb4Qh7f/b0= ARC-Authentication-Results: i=1; imf12.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=jzRMYXdL; spf=pass (imf12.hostedemail.com: domain of dakr@kernel.org designates 145.40.73.55 as permitted sender) smtp.mailfrom=dakr@kernel.org; dmarc=pass (policy=none) header.from=kernel.org Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by sin.source.kernel.org (Postfix) with ESMTP id 385F8CE0E9C; Tue, 23 Jul 2024 18:11:39 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 22C00C4AF0A; Tue, 23 Jul 2024 18:11:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1721758298; bh=EADnfi1fGvsx4VhAV2Fq3TLA5MaiZGvO/PM1XNctkMk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jzRMYXdLknWKU0suCrVLj8MEFGuTCk7/uXsRG/mzuUaad6aFwdImo0hpVVrtIv7kH 0Rv1AXFLqi29AxP5TBXGlkF16TDnKbx4X3Cv8xPp6L3L5gcMSys9a9enKH5QrtEEMf GJWj+dRnU8pYOsxpsuvVbiLkTaJi+K3Av/YRPwhEiiXcDNbenfTiCEhgLVg/NRN6j3 vne/BLvKZRqxoVtlZ5qZ+4hIl7cVphYA1vSQMzC9xXLrnOFcCIMPXShVFDDPiSm+ZF 5ga/F3VxiqKohPR51k3FZes5jjxBRQtQqLSQ61rf6jJindASfC6V14JtEaD0+fBpHf cwIojKBj2UxmA== From: Danilo Krummrich To: ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@samsung.com, aliceryhl@google.com, akpm@linux-foundation.org Cc: daniel.almeida@collabora.com, faith.ekstrand@collabora.com, boris.brezillon@collabora.com, lina@asahilina.net, mcanal@igalia.com, zhiw@nvidia.com, acurrid@nvidia.com, cjia@nvidia.com, jhubbard@nvidia.com, airlied@redhat.com, ajanulgu@redhat.com, lyude@redhat.com, linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-mm@kvack.org, Danilo Krummrich Subject: [PATCH v2 08/23] rust: types: implement `Unique` Date: Tue, 23 Jul 2024 20:09:57 +0200 Message-ID: <20240723181024.21168-9-dakr@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240723181024.21168-1-dakr@kernel.org> References: <20240723181024.21168-1-dakr@kernel.org> MIME-Version: 1.0 X-Stat-Signature: qj8pjjo4g65orb6dq5zjmmnp8xygeimb X-Rspamd-Queue-Id: 581BD40010 X-Rspam-User: X-Rspamd-Server: rspam08 X-HE-Tag: 1721758301-925137 X-HE-Meta: U2FsdGVkX1/UhBkacKd1HZrRHeTM9cLfmJInAWrwY68GnTj8b6oQS8WqU4TPwcEperw5QIMeOwi2WjZoJF5snmqpaxIwoQUHf1tCdLJ4NboQYvIBWQEBj0BFyDNRsSs4gI4I4/HYfLbjTleU85Ks1ZrZNTdQEZSSC3RKzOrg/cJ9kXsDWlLmPlDPCWWWK605fqtK2lxE5b5X4ImkHkYOJo067w9XcWXOFgbebruwJPadHuBJhj+RbfD11Y8tN/L7j3gkSlUQPuyxR0LF9mESvKx6BYky7+6a4ZXCSgvyr45oXqu+h3bUBHRd9LL46+fwQTFeH6oXN4m3/PJDoyOmNmFWmBS8tV4yWWZYzpLEfk3hulTMVElEpMXGqQ7ShGxopXZhtpNw8endBIfPmOHjvJeTouPWBqgk0hOuta+pAE6tw3TTwxKrA8CEFAebwbE5Xi4e05sWEt3vHOO8EhXXWHHrL9vxMv4aKQ2FE465dUNdCTWzpDFqHC+3L5iGbZ8H/AHPZ3/ZuWzwUr6AT9TsNw6EJf8icQZGjnOAOIHAZOWzF+g4ioiLZadYEDlwsPqDSQ0E74I5qsTs2xcEKJZHjoPEtlASy/L4bzqZdkx8gGHMKZyEIPJVwpFeciOmaZJg9HSFkj8pexHtkhtA8EX5VBU97S91pvoR38mvTAMm3xOzOu1ZpLar3cdFC6pBZk1Qh0mjgbTAD1CnQAjpIZPFLyPIClZsLnl0un11TPkNdyC0wTc+649kj2DAytu/P+yV9wZjQM/XEKUiHp1Sof5QE0eItyNIxRNMlZ8+0H7qZ987ZLrMOnXLAmRock3kfeKwoc57ZvXRU5Cjjv3i6ysbn0/I2ElXM+i6uh6ulYAtu4tStaDg6zyGFYds+R6t+LFk4y1QGufryDz9w96T5PiO2+MNnXoSuqZX/uzzD4RWyr66IlpuUJ4SKNbAwy26XUiuecTAug1SkKerE97E9na PZYZ1TgH r2N4RvT7/jxsadm5qzAVQ2QWQhYmJr9DoRYX/MfJYWSia98eUsfWqlEoZWpzP9HLp44ur7YucO1vy/9CW/kR20dMxHzUNJBfnw475F+Uz3omVvm2HTEpbKCWRd0v7wM3pOiLd/l6iMpNpidOfa3r1vKfnvQzY4uUJnfzyKvaTI4tGC6CrLPHwjXEkrfvQxIyh5ClLrmp72iBvKblb2nobpqcmRSIO3kisAHRrdUl9cit516f0O5BYjBuQ3Za4Qx7worVoO7tkDLxDweRoqniqUJ3pt4xk+vOy9fWo+qLSHoqQKxtd/ilp0g0RLxWrBdHqOXkxn5J9qFk3lP8= X-Bogosity: Ham, tests=bogofilter, spamicity=0.037709, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: Implement the `Unique` type as a prerequisite for `Box` and `Vec` introduced in subsequent patches. `Unique` serves as wrapper around a `NonNull`, but indicates that the possessor of this wrapper owns the referent. This type already exists in Rust's core library, but, unfortunately, is exposed as unstable API and hence shouldn't be used in the kernel. This implementation of `Unique` is almost identical, but mostly stripped down to the functionality we need for `Box` and `Vec`. Additionally, all unstable features are removed and / or replaced by stable ones. Signed-off-by: Danilo Krummrich --- rust/kernel/types.rs | 183 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 2e7c9008621f..9cd20fe41c20 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -409,3 +409,186 @@ pub enum Either { /// Constructs an instance of [`Either`] containing a value of type `R`. Right(R), } + +/// A wrapper around a raw non-null `*mut T` that indicates that the possessor +/// of this wrapper owns the referent. Useful for building abstractions like +/// `Box`, `Vec`, `String`, and `HashMap`. +/// +/// Unlike `*mut T`, `Unique` behaves "as if" it were an instance of `T`. +/// It implements `Send`/`Sync` if `T` is `Send`/`Sync`. It also implies +/// the kind of strong aliasing guarantees an instance of `T` can expect: +/// the referent of the pointer should not be modified without a unique path to +/// its owning Unique. +/// +/// If you're uncertain of whether it's correct to use `Unique` for your purposes, +/// consider using `NonNull`, which has weaker semantics. +/// +/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer +/// is never dereferenced. This is so that enums may use this forbidden value +/// as a discriminant -- `Option>` has the same size as `Unique`. +/// However the pointer may still dangle if it isn't dereferenced. +/// +/// Unlike `*mut T`, `Unique` is covariant over `T`. This should always be correct +/// for any type which upholds Unique's aliasing requirements. +#[repr(transparent)] +pub struct Unique { + pointer: NonNull, + // NOTE: this marker has no consequences for variance, but is necessary + // for dropck to understand that we logically own a `T`. + // + // For details, see: + // https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data + _marker: PhantomData, +} + +/// `Unique` pointers are `Send` if `T` is `Send` because the data they +/// reference is unaliased. Note that this aliasing invariant is +/// unenforced by the type system; the abstraction using the +/// `Unique` must enforce it. +unsafe impl Send for Unique {} + +/// `Unique` pointers are `Sync` if `T` is `Sync` because the data they +/// reference is unaliased. Note that this aliasing invariant is +/// unenforced by the type system; the abstraction using the +/// `Unique` must enforce it. +unsafe impl Sync for Unique {} + +impl Unique { + /// Creates a new `Unique` that is dangling, but well-aligned. + /// + /// This is useful for initializing types which lazily allocate, like + /// `Vec::new` does. + /// + /// Note that the pointer value may potentially represent a valid pointer to + /// a `T`, which means this must not be used as a "not yet initialized" + /// sentinel value. Types that lazily allocate must track initialization by + /// some other means. + #[must_use] + #[inline] + pub const fn dangling() -> Self { + Unique { + pointer: NonNull::dangling(), + _marker: PhantomData, + } + } +} + +impl Unique { + /// Creates a new `Unique`. + /// + /// # Safety + /// + /// `ptr` must be non-null. + #[inline] + pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { + // SAFETY: the caller must guarantee that `ptr` is non-null. + unsafe { + Unique { + pointer: NonNull::new_unchecked(ptr), + _marker: PhantomData, + } + } + } + + /// Creates a new `Unique` if `ptr` is non-null. + #[allow(clippy::manual_map)] + #[inline] + pub fn new(ptr: *mut T) -> Option { + if let Some(pointer) = NonNull::new(ptr) { + Some(Unique { + pointer, + _marker: PhantomData, + }) + } else { + None + } + } + + /// Acquires the underlying `*mut` pointer. + #[must_use = "`self` will be dropped if the result is not used"] + #[inline] + pub const fn as_ptr(self) -> *mut T { + self.pointer.as_ptr() + } + + /// Dereferences the content. + /// + /// The resulting lifetime is bound to self so this behaves "as if" + /// it were actually an instance of T that is getting borrowed. If a longer + /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`. + /// + /// # Safety + /// + /// Safety requirements for this function are inherited from [NonNull::as_ref]. + /// + #[must_use] + #[inline] + pub const unsafe fn as_ref(&self) -> &T { + // SAFETY: the caller must guarantee that `self` meets all the + // requirements for a reference. + unsafe { self.pointer.as_ref() } + } + + /// Mutably dereferences the content. + /// + /// The resulting lifetime is bound to self so this behaves "as if" + /// it were actually an instance of T that is getting borrowed. If a longer + /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`. + /// + /// # Safety + /// + /// Safety requirements for this function are inherited from [NonNull::as_mut]. + #[must_use] + #[inline] + pub unsafe fn as_mut(&mut self) -> &mut T { + // SAFETY: the caller must guarantee that `self` meets all the + // requirements for a mutable reference. + unsafe { self.pointer.as_mut() } + } + + /// Casts to a pointer of another type. + #[must_use = "`self` will be dropped if the result is not used"] + #[inline] + pub fn cast(self) -> Unique { + Unique::from(self.pointer.cast()) + } + + /// Acquires the underlying `*mut` pointer. + #[must_use = "`self` will be dropped if the result is not used"] + #[inline] + pub const fn as_non_null(self) -> NonNull { + self.pointer + } +} + +impl Clone for Unique { + #[inline] + fn clone(&self) -> Self { + *self + } +} + +impl Copy for Unique {} + +impl From<&mut T> for Unique { + /// Converts a `&mut T` to a `Unique`. + /// + /// This conversion is infallible since references cannot be null. + #[inline] + fn from(reference: &mut T) -> Self { + Self::from(NonNull::from(reference)) + } +} + +impl From> for Unique { + /// Converts a `NonNull` to a `Unique`. + /// + /// This conversion is infallible since `NonNull` cannot be null. + #[inline] + fn from(pointer: NonNull) -> Self { + Unique { + pointer, + _marker: PhantomData, + } + } +}