Skip to content

Request: Send + Sync version of a Handle #207

Open
@joshlf

Description

@joshlf

For data structures that want to be concurrent and only expose handles, the fact that crossbeam Handles are neither Send nor Sync is an issue. For example, in elfmalloc, we'd like to have allocator handles which are, at the very least, Sync so that you can share them between threads by calling clone from a new thread, but the fact that Handles are not Sync has prevented us from doing that without resorting to unsafe code.

The problem comes down to the fact that Handles use immutable methods in thread-unsafe ways. You could imagine a handle where the pin and is_pinned methods were mutable, leaving clone as the only immutable method, which would be implemented as self.collector().register(). In fact, in order to sidestep this issue, that's exactly what I'm doing right now for elfmalloc:

/// A `Sync` handle on an epoch GC instance.
/// 
/// A `SyncHandle` is a handle on an epoch GC instance which is `Sync`. It is
/// meant to make it easier to work correctly with `Handle`s in a thread-safe
/// manner.
/// 
/// `Handles` are not `Sync` because they keep thread-unsafe references to a
/// `Local` under the hood. `SyncHandle` sidesteps that issue by ensuring that
/// the only immutable method is clone, which is careful not to use the `Handle`
/// stored internally - only the `Arc<Collector>`, which *is* thread-safe.
pub struct SyncHandle {
    handle: Handle,
    collector: Arc<Collector>,
}

impl SyncHandle {
    pub fn new() -> SyncHandle {
        let collector = Arc::new(Collector::new());
        SyncHandle {
            handle: collector.register(),
            collector,
        }
    }

    pub fn pin(&mut self) -> Guard {
        self.handle.pin()
    }
}

impl Clone for SyncHandle {
    fn clone(&self) -> SyncHandle {
        let handle = self.collector.register();
        SyncHandle {
            handle,
            collector: self.collector.clone(),
        }
    }
}

unsafe impl Sync for SyncHandle {}

It would also be nice if such a handle could be Send, although I'm not sure how that would be done with the current Local-based design.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions