summaryrefslogtreecommitdiff
path: root/rust/kernel/drm/syncobj.rs
blob: 10eed05eb27ad53a03f0aa1abe74c7a52abba4ed (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// SPDX-License-Identifier: GPL-2.0 OR MIT

//! DRM Sync Objects
//!
//! C header: [`include/linux/drm/drm_syncobj.h`](../../../../include/linux/drm/drm_syncobj.h)

use crate::{bindings, dma_fence::*, drm, error::Result, prelude::*};

/// A DRM Sync Object
///
/// # Invariants
/// ptr is a valid pointer to a drm_syncobj and we own a reference to it.
pub struct SyncObj {
    ptr: *mut bindings::drm_syncobj,
}

impl SyncObj {
    /// Looks up a sync object by its handle for a given `File`.
    pub fn lookup_handle(file: &impl drm::file::GenericFile, handle: u32) -> Result<SyncObj> {
        // SAFETY: The arguments are all valid per the type invariants.
        let ptr = unsafe { bindings::drm_syncobj_find(file.raw() as *mut _, handle) };

        if ptr.is_null() {
            Err(ENOENT)
        } else {
            Ok(SyncObj { ptr })
        }
    }

    /// Returns the DMA fence associated with this sync object, if any.
    pub fn fence_get(&self) -> Option<Fence> {
        let fence = unsafe { bindings::drm_syncobj_fence_get(self.ptr) };
        if fence.is_null() {
            None
        } else {
            // SAFETY: The pointer is non-NULL and drm_syncobj_fence_get acquired an
            // additional reference.
            Some(unsafe { Fence::from_raw(fence) })
        }
    }

    /// Replaces the DMA fence with a new one, or removes it if fence is None.
    pub fn replace_fence(&self, fence: Option<&Fence>) {
        unsafe {
            bindings::drm_syncobj_replace_fence(
                self.ptr,
                fence.map_or(core::ptr::null_mut(), |a| a.raw()),
            )
        };
    }

    /// Adds a new timeline point to the syncobj.
    pub fn add_point(&self, chain: FenceChain, fence: &Fence, point: u64) {
        // SAFETY: All arguments should be valid per the respective type invariants.
        // This takes over the FenceChain ownership.
        unsafe { bindings::drm_syncobj_add_point(self.ptr, chain.into_raw(), fence.raw(), point) };
    }
}

impl Drop for SyncObj {
    fn drop(&mut self) {
        // SAFETY: We own a reference to this syncobj.
        unsafe { bindings::drm_syncobj_put(self.ptr) };
    }
}

impl Clone for SyncObj {
    fn clone(&self) -> Self {
        // SAFETY: `ptr` is valid per the type invariant and we own a reference to it.
        unsafe { bindings::drm_syncobj_get(self.ptr) };
        SyncObj { ptr: self.ptr }
    }
}

// SAFETY: drm_syncobj operations are internally locked.
unsafe impl Sync for SyncObj {}
unsafe impl Send for SyncObj {}