ComputationalRadiationPhysics / redGrapes

Resource-based, Declarative task-Graphs for Parallel, Event-driven Scheduling :grapes:

Home Page:https://redgrapes.rtfd.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Provide access guards to restrict resource usage at compile-time

michaelsippel opened this issue · comments

Currently, the user has to specify the resource access information for each task and the
task implementation accesses the data though a capture. This makes it unable to restrict
the actual code which enables errors from wrong access annotations.

A possible solution to make this more safe would be to wrap the data of the resource with different access-guards depending on the chosen access, which only implements the allowed functions or const-ness.
For this to work, the resources shouldn't be captured but instead accessed through function parameters, so they get type-checked.

Unsafe version:

auto data = std::make_shared<int>();
rg::IOResource resource;

mgr.emplace_task(
    [data]{ *data = 123; },
    TaskProperties::Builder().resources({ resource.write(); })
); 

With access guards:

auto resource = rg::GuardedIOResource<int>();
mgr.emplace_task(
    [] ( rg::IOResourceWriteGuard<int> data ){ *data = 123; },
    TaskProperties::Builder().resources( resource.write() )
);

The Guarded-Resource object holds a shared pointer to the data and creates access guards through the read() / write() functions, which implement firstly the creation
of appropriate task-properties for this access and secondly the allowed interface for
this access. In the case of read/write, it would implement a dereference operator which
returns a T const & in the case of the read-guard and T& for write-guard.

This would remove possible lifetime issues and erroneous access information.

The following will not compile:

redGrapes::IOResource< int > r1;
mgr.emplace_task(
    []( auto r1 )
    {
        *r1 = 123;
    },
    r1.read()
);

with the message

error: assignment of read-only location 'r1.redGrapes::ioresource::ReadGuard<int>::operator*()'
   31 |             *r1 = 123;
      |             ~~~~^~~~~

This is also possible with field resources, although the index restrictions can only be checked at runtime.

redGrapes::FieldResource<
    std::array< std::array<int, 64>, 64 >
> array(
    new std::array< std::array<int, 64>, 64 >()
);

mgr.emplace_task(
    [&mgr]( auto array )
    {
        array[{0,0}] = 1;

        mgr.emplace_task(
            []( auto array )
            {
                // ok
                int x = array[{16,5}];

                // will throw std::out_of_bounds
                int y = array[{0,0}];
            },
            array.at({16,5}).read()
        );
    },
    array.write().area({0,0}, {64, 64})
);