From patchwork Thu Aug 1 00:02:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 13749347 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 C41BFC3DA7F for ; Thu, 1 Aug 2024 00:07:42 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 577826B009E; Wed, 31 Jul 2024 20:07:42 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 528206B00A0; Wed, 31 Jul 2024 20:07:42 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 3C7BC6B00A1; Wed, 31 Jul 2024 20:07:42 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0017.hostedemail.com [216.40.44.17]) by kanga.kvack.org (Postfix) with ESMTP id 1738B6B009E for ; Wed, 31 Jul 2024 20:07:42 -0400 (EDT) Received: from smtpin03.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay10.hostedemail.com (Postfix) with ESMTP id C45CAC07B7 for ; Thu, 1 Aug 2024 00:07:41 +0000 (UTC) X-FDA: 82401737922.03.781AD1E Received: from sin.source.kernel.org (sin.source.kernel.org [145.40.73.55]) by imf19.hostedemail.com (Postfix) with ESMTP id 84EDE1A002A for ; Thu, 1 Aug 2024 00:07:39 +0000 (UTC) Authentication-Results: imf19.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=qnKAY9mZ; spf=pass (imf19.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=1722470785; 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=aGeqMyC7GCy/MfpZbpdsFcxVZpw4WIh6a2U4e8v46BY=; b=1ury2kFnuyqnIbRIMrfn3pKChCOhaa+v8V5oXJpr4KAf4TZSaGn6QurEXxbcqwnRcBY/8f jh8swQ0UjevYlJMT+AWgu3s6glxw4iiu4g+VlMZ7mRTtQvyVj8sl5g4spxExwNSbshoTKd X6pbB2wtXkCPd067LoQm8b3ElsXhUbE= ARC-Authentication-Results: i=1; imf19.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=qnKAY9mZ; spf=pass (imf19.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-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1722470785; a=rsa-sha256; cv=none; b=TQGBjrIKYzkBozbDBZn3ASt3DITEXbNtEEahMpARhjgTDOqnzMfH/IBQlx/OAjBdqnUFqM PP5+D0Le9GEpyWMbyTwfSGPn6ix50cGYkX/gRcea3a+VqQlC7ZD7LXMW3Csx5/YfAGOvZu 1MbBIYJrH+uWfNTyUvOSCXlBjzPnY9Y= Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by sin.source.kernel.org (Postfix) with ESMTP id E36BDCE182B; Thu, 1 Aug 2024 00:07:36 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 36BCCC32786; Thu, 1 Aug 2024 00:07:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1722470856; bh=5FSlmk8uiC802CZQ4+q6oRgODjrvttEYMjmd4A1Q0DE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qnKAY9mZbcsCbF9DQaUa7rRNVkMDSwbsrxRFtaDrjtQt3Z/cIgbs1zut+BbliJAdK 02zGAuUF/fWyyxTRKQsHtznT6ozKJVeCvoW6+EVV5DfMN/BsmrXoW8MDT4rnA6yBHa /xgrWKbCzvTKFyWD5m8918wkQETNmEB/b782b6+QRu1BaCATYSzYyk6WxBBcOYirm6 Nh09pNPRyA8MaYDBRunWAOM1xS0zxtrXTYOQ8xxgNDWI3Nii4kDZsDh38BsVlJmtMW wMRyTscpofeJMM43u+vrlx/0ibjWjkfqt0hOGPoqEyR1vFiX/wae3AYVEDy9JjsDw+ S2pfumYJIRWCA== 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 v3 08/25] rust: types: implement `Unique` Date: Thu, 1 Aug 2024 02:02:07 +0200 Message-ID: <20240801000641.1882-9-dakr@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240801000641.1882-1-dakr@kernel.org> References: <20240801000641.1882-1-dakr@kernel.org> MIME-Version: 1.0 X-Rspamd-Server: rspam06 X-Rspamd-Queue-Id: 84EDE1A002A X-Stat-Signature: 3idsub64yewpwkd7pqxqemnja9izpbty X-Rspam-User: X-HE-Tag: 1722470859-36515 X-HE-Meta: U2FsdGVkX18UDdA+S3x1BF6jstfxgudQM2AdWxEIENTLuiQyrBHjTZ3XhEOToOfve8ZgC0FWKsuPN3mqbHXGuokQsAEQp4H+0ce3uCGg0I4y1C2EJo8iWCSNAVF5q4xyKc91XZ5kv24oDgmn+/Yy5DnuyLrmj28BdYlU11GHYijohJN4bPBb/9gUs/82iB8k2MZdVu7xJef3Hizcc+2RSlHmmrd044vE/Ea1lQ7gPEFMtnTY8NXtxtOzydSs1DAQ4q7p1olNsu2uUPDby1YG18kAPT8wG08Zur2r4DrloJRQFn94LBWCUtHd7QEFVDw06KWD77XY8J50+zk67GIVZHDSaDPbPGgilYzWJcEvx/m4iy3NCn/KHhpRI2A9498vFX/Q/0UbsOGGlXQpsiZ8LLUMt/UbRcC41eksp+pQBx+2r2RJNsVz8EI5g8+gO8tfRpkbbdH0x7wubASosaoPxcSR2QH5Mfb+5B51rQgbk0ar2dlRRkKtNYkw6yy/3ng22cUJiyvmZ9vEtOwpuXNYjjFEDmPd3J9ktpi0XUGWw1XX98rAGJZSq/xeOlAuCRRxXVv8fcDQuSWfPuAv6AbBP2jde+KIcBSN3ZK+DQZ4mAlOBLGntw+kTilYKDTjP2VuUCvkUaIcXDknJhHiEyVBtYvJSapb9iOpSNV+FqJsFjy7o/ZRhRsyFC4qF9OeXu9ls3QqNT1xXhvWSkXTOb2y7oKdAd42QNqVzZhjwcxsf5XiL/Rpvi81VyCpf7MoX4p4WEr72qs4sRNtLjtnuTTJYfSMFjCares6aaQFZRe+l/8izv1+e9W9PCN8RoJwmdW+EOuyuX4eMULvGgf5i/2ds0h0DhYtuEPS5xW2rClIv1nwvBLRsbWBfSdQQcbptitiM3YIRSFeiyy7OkCMwFeOH6Hrb51OtyDCBTYZQ8wG867pVlG1M43QateiNwzkBFoyeSZ1o/OxQtJp/JOoGAN uP83kqGA 9xdoUFpBgDhpJ/ZAzEdIcwntHRYzt6jzZHltiuif8sFeBdtaFGgJUwlsH3s/KvqxTc/xaZrh659jbKiD3cnycgIGDb/xvCtaHS6cgvV8lw1tNf73JykougK/R66JUIWpVE5kFpaqljHNIZemqCusrvLiM+F0Cp0VjXXDfPklsU78tLEeionVuBqEskFQklP8G6EL5f35BQqFM1LILKEpYqtNMaI6yCt2TYSO6CogP7GsIWSMLue6SZKw8GhekP+YdrRA19PHw/O+mtkMbZO2HpahwkQ2q/vf90q2YmJF4d6rmWCW8JDz+W9/eo6yqQ/bvh1fmxCY52tY2OME= X-Bogosity: Ham, tests=bogofilter, spamicity=0.012997, 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 bd189d646adb..7cf89067b5fc 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -473,3 +473,186 @@ unsafe impl AsBytes for str {} // does not have any uninitialized portions either. unsafe impl AsBytes for [T] {} unsafe impl AsBytes for [T; N] {} + +/// 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, + } + } +}