Files @ ccd08a8d8365
Branch filter:

Location: CSY/reowolf/src/runtime2/runtime.rs - annotation

ccd08a8d8365 5.1 KiB application/rls-services+xml Show Source Show as Raw Download as Raw
mh
Preparing component store
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
ccd08a8d8365
use std::sync::Arc;
use std::sync::atomic::AtomicU32;

use crate::protocol::*;

// -----------------------------------------------------------------------------
// Component
// -----------------------------------------------------------------------------

/// Key to a component. Type system somewhat ensures that there can only be one
/// of these. Only with a key one may retrieve privately-accessible memory for
/// a component. Practically just a generational index, like `CompId` is.
#[derive(Copy, Clone)]
pub(crate) struct CompKey(CompId);

/// Generational ID of a component
#[derive(Copy, Clone)]
pub(crate) struct CompId {
    pub index: u32,
    pub generation: u32,
}

impl PartialEq for CompId {
    fn eq(&self, other: &Self) -> bool {
        return self.index.eq(&other.index);
    }
}
impl Eq for CompId {}

/// In-runtime storage of a component
pub(crate) struct RtComp {

}

// -----------------------------------------------------------------------------
// Runtime
// -----------------------------------------------------------------------------

type RuntimeHandle = Arc<Runtime>;

/// Memory that is maintained by "the runtime". In practice it is maintained by
/// multiple schedulers, and this serves as the common interface to that memory.
pub struct Runtime {
    active_elements: AtomicU32, // active components and APIs (i.e. component creators)
}

impl Runtime {
    pub fn new(num_threads: u32, protocol_description: ProtocolDescription) -> Runtime {
        assert!(num_threads > 0, "need a thread to perform work");
        return Runtime{
            active_elements: AtomicU32::new(0),
        };
    }
}

// -----------------------------------------------------------------------------
// Runtime containers
// -----------------------------------------------------------------------------

/// Component storage. Note that it shouldn't be polymorphic, but making it so
/// allows us to test it.
// Requirements:
// 1. Performance "fastness" in order of most important:
//      1. Access (should be just index retrieval)
//      2. Creation (because we want to execute code as fast as possible)
//      3. Destruction (because create-and-run is more important than quick dying)
// 2. Somewhat safe, with most performance spent in the incorrect case
// 3. Thread-safe. Everyone and their dog will be creating and indexing into
//  the components concurrently.
// 4. Assume low contention.
//
// Some trade-offs:
// We could perhaps make component IDs just a pointer to that component. With
// an atomic counter managed by the runtime containing the number of owners
// (always starts at 1). However, this feels like too early to do something like
// that, especially because I would like to do direct messaging. Even though
// sending two u32s is the same as sending a pointer, it feels wrong for now.
//
// So instead we'll have some kind of concurrent store where we can index into.
// This means that it might have to resize. Resizing implies that everyone must
// wait until it is resized.
//
// Furthermore, it would be nice to reuse slots. That is to say: if we create a
// bunch of components and then destroy a couple of them, then the storage we
// reserved for them should be reusable.
//
// We'll go the somewhat simple route for now:
// 1. Each component will get allocated individually (and we'll define exactly
//  what we mean by this sometime later, when we start with the bytecode). This
//  way the components are pointer-stable for their lifetime.
// 2. We need to have some array that contains these pointers. We index into
//  this array with our IDs.
// 3. When we destroy components we call the destructor on the allocated memory
//  and add the index to some kind of freelist. Because only one thread can ever
//  create and/or destroy a component we have an imaginary lock on that
//  particular component's index. The freelist acts like a concurrent stack
//  where we can push/pop. If we ensure that the freelist is the same size as
//  the ID array then we can never run out of size.
// 4. At some point the array ID might be full and have to be resized. If we
//  ensure that there is only one thread which can ever fill up the array (this
//  means we *always* have one slot free, such that we can do a CAS) then we can
//  do a pointer-swap on the base pointer of all storage. This takes care of
//  resizing due to creation.
//
//  However, with a freelist accessed at the same time, we must make sure that
//  we do the copying of the old freelist and the old ID array correctly. While
//  we're creating the new array we might still be destroying components. So
//  one component calls a destructor (not too bad) and then pushes the resulting
//  ID onto the freelist stack (which is bad). We can either somehow forbid
//  destroying during resizing (which feels ridiculous) or try to be smart. Note
//  that destruction might cause later creations as well!
//
//  Since components might have to read a base pointer anyway to arrive at a
//  freelist entry or component pointer, we could set it to null and let the
//  others spinlock (or take a mutex?). So then the resizer will notice the
//
struct CompStore {

}