mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 00:14:32 -08:00
[kernel] Track capability reference counts
First pass at reference-counting capabilities.
This commit is contained in:
@@ -20,6 +20,8 @@ cap_table::create(obj::kobject *target, j6_cap_t caps)
|
|||||||
{
|
{
|
||||||
j6_handle_t new_handle = make_handle(m_count);
|
j6_handle_t new_handle = make_handle(m_count);
|
||||||
|
|
||||||
|
util::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
m_caps.insert({
|
m_caps.insert({
|
||||||
new_handle,
|
new_handle,
|
||||||
j6_handle_invalid,
|
j6_handle_invalid,
|
||||||
@@ -29,12 +31,17 @@ cap_table::create(obj::kobject *target, j6_cap_t caps)
|
|||||||
target,
|
target,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (target)
|
||||||
|
target->handle_retain();
|
||||||
|
|
||||||
return new_handle;
|
return new_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
j6_handle_t
|
j6_handle_t
|
||||||
cap_table::derive(j6_handle_t base, j6_cap_t caps)
|
cap_table::derive(j6_handle_t base, j6_cap_t caps)
|
||||||
{
|
{
|
||||||
|
util::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
capability *existing = m_caps.find(base);
|
capability *existing = m_caps.find(base);
|
||||||
if (!existing)
|
if (!existing)
|
||||||
return j6_handle_invalid;
|
return j6_handle_invalid;
|
||||||
@@ -52,11 +59,43 @@ cap_table::derive(j6_handle_t base, j6_cap_t caps)
|
|||||||
existing->object,
|
existing->object,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (existing->object)
|
||||||
|
existing->object->handle_retain();
|
||||||
|
|
||||||
return new_handle;
|
return new_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
capability *
|
capability *
|
||||||
cap_table::find(j6_handle_t id)
|
cap_table::find_without_retain(j6_handle_t id)
|
||||||
{
|
{
|
||||||
return m_caps.find(id);
|
return m_caps.find(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
capability *
|
||||||
|
cap_table::retain(j6_handle_t id)
|
||||||
|
{
|
||||||
|
util::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
|
capability *cap = m_caps.find(id);
|
||||||
|
if (!cap)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
++cap->holders;
|
||||||
|
return cap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cap_table::release(j6_handle_t id)
|
||||||
|
{
|
||||||
|
util::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
|
capability *cap = m_caps.find(id);
|
||||||
|
if (!cap)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (--cap->holders == 0) {
|
||||||
|
if (cap->object)
|
||||||
|
cap->object->handle_release();
|
||||||
|
m_caps.erase(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,8 +33,16 @@ public:
|
|||||||
/// Create a new capability from an existing one.
|
/// Create a new capability from an existing one.
|
||||||
j6_handle_t derive(j6_handle_t id, j6_cap_t caps);
|
j6_handle_t derive(j6_handle_t id, j6_cap_t caps);
|
||||||
|
|
||||||
/// Get the capability referenced by a handle
|
/// Get the capability referenced by a handle.
|
||||||
capability * find(j6_handle_t id);
|
capability * retain(j6_handle_t id);
|
||||||
|
|
||||||
|
/// Release a retained capability when it is no longer being used.
|
||||||
|
void release(j6_handle_t id);
|
||||||
|
|
||||||
|
/// Get the capability referenced by a handle, without increasing
|
||||||
|
/// its refcount. WARNING: You probably want retain(), using a capability
|
||||||
|
/// (or the object it points to) without retaining it is dangerous.
|
||||||
|
capability * find_without_retain(j6_handle_t id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using map_type = util::inplace_map<j6_handle_t, capability, j6_handle_invalid>;
|
using map_type = util::inplace_map<j6_handle_t, capability, j6_handle_invalid>;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include <new>
|
||||||
|
|
||||||
#include <util/no_construct.h>
|
#include <util/no_construct.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
@@ -119,28 +121,44 @@ process::thread_exited(thread *th)
|
|||||||
void
|
void
|
||||||
process::add_handle(j6_handle_t handle)
|
process::add_handle(j6_handle_t handle)
|
||||||
{
|
{
|
||||||
|
capability *c = g_cap_table.retain(handle);
|
||||||
|
kassert(c, "Trying to add a non-existant handle to a process!");
|
||||||
|
|
||||||
|
if (c) {
|
||||||
|
util::scoped_lock lock {m_handles_lock};
|
||||||
m_handles.add(handle);
|
m_handles.add(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
process::remove_handle(j6_handle_t id)
|
|
||||||
{
|
|
||||||
return m_handles.remove(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
process::has_handle(j6_handle_t id)
|
process::remove_handle(j6_handle_t handle)
|
||||||
{
|
{
|
||||||
return m_handles.contains(id);
|
util::scoped_lock lock {m_handles_lock};
|
||||||
|
bool removed = m_handles.remove(handle);
|
||||||
|
lock.release();
|
||||||
|
|
||||||
|
if (removed)
|
||||||
|
g_cap_table.release(handle);
|
||||||
|
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
process::has_handle(j6_handle_t handle)
|
||||||
|
{
|
||||||
|
util::scoped_lock lock {m_handles_lock};
|
||||||
|
return m_handles.contains(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
process::list_handles(j6_handle_descriptor *handles, size_t len)
|
process::list_handles(j6_handle_descriptor *handles, size_t len)
|
||||||
{
|
{
|
||||||
|
util::scoped_lock lock {m_handles_lock};
|
||||||
|
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
for (j6_handle_t handle : m_handles) {
|
for (j6_handle_t handle : m_handles) {
|
||||||
|
|
||||||
capability *cap = g_cap_table.find(handle);
|
capability *cap = g_cap_table.find_without_retain(handle);
|
||||||
kassert(cap, "Found process handle that wasn't in the cap table");
|
kassert(cap, "Found process handle that wasn't in the cap table");
|
||||||
if (!cap) continue;
|
if (!cap) continue;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
/// Definition of process kobject types
|
/// Definition of process kobject types
|
||||||
|
|
||||||
#include <j6/cap_flags.h>
|
#include <j6/cap_flags.h>
|
||||||
#include <util/map.h>
|
|
||||||
#include <util/node_map.h>
|
#include <util/node_map.h>
|
||||||
#include <util/vector.h>
|
#include <util/vector.h>
|
||||||
|
|
||||||
@@ -114,6 +113,7 @@ private:
|
|||||||
util::vector<thread*> m_threads;
|
util::vector<thread*> m_threads;
|
||||||
|
|
||||||
util::node_set<j6_handle_t, j6_handle_invalid, heap_allocated> m_handles;
|
util::node_set<j6_handle_t, j6_handle_invalid, heap_allocated> m_handles;
|
||||||
|
util::spinlock m_handles_lock;
|
||||||
|
|
||||||
enum class state : uint8_t { running, exited };
|
enum class state : uint8_t { running, exited };
|
||||||
state m_state;
|
state m_state;
|
||||||
|
|||||||
@@ -184,10 +184,22 @@ for id, scope, method in syscalls.methods:
|
|||||||
cog.outl()
|
cog.outl()
|
||||||
|
|
||||||
if "noreturn" in method.options:
|
if "noreturn" in method.options:
|
||||||
|
if handles:
|
||||||
|
cog.outl(f""" static_assert(false, "Cannot define a `noreturn` syscall that holds handles.");""")
|
||||||
cog.outl(f""" {name}({", ".join(args)});""")
|
cog.outl(f""" {name}({", ".join(args)});""")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
cog.outl(" j6_status_t _retval;")
|
||||||
|
cog.outl(" {")
|
||||||
cog.outl(f""" profiler<syscall_profiles, {id}> profile {{"{name}"}};""")
|
cog.outl(f""" profiler<syscall_profiles, {id}> profile {{"{name}"}};""")
|
||||||
cog.outl(f""" return {name}({", ".join(args)});""")
|
cog.outl(f""" _retval = {name}({", ".join(args)});""")
|
||||||
|
cog.outl(" }\n")
|
||||||
|
|
||||||
|
for type, arg, caps in handles:
|
||||||
|
cog.outl(f" release_handle({arg});")
|
||||||
|
|
||||||
|
cog.outl(f""" return _retval;""")
|
||||||
|
|
||||||
cog.outl("}")
|
cog.outl("}")
|
||||||
cog.outl("\n")
|
cog.outl("\n")
|
||||||
]]]*/
|
]]]*/
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ j6_status_t get_handle(j6_handle_t id, j6_cap_t caps, T *&object)
|
|||||||
return j6_status_ok;
|
return j6_status_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
capability *capdata = g_cap_table.find(id);
|
capability *capdata = g_cap_table.retain(id);
|
||||||
if (!capdata || capdata->type != T::type)
|
if (!capdata || capdata->type != T::type)
|
||||||
return j6_err_invalid_arg;
|
return j6_err_invalid_arg;
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ inline j6_status_t get_handle<obj::kobject>(j6_handle_t id, j6_cap_t caps, obj::
|
|||||||
return j6_status_ok;
|
return j6_status_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
capability *capdata = g_cap_table.find(id);
|
capability *capdata = g_cap_table.retain(id);
|
||||||
if (!capdata)
|
if (!capdata)
|
||||||
return j6_err_invalid_arg;
|
return j6_err_invalid_arg;
|
||||||
|
|
||||||
@@ -68,4 +68,7 @@ inline j6_status_t get_handle<obj::kobject>(j6_handle_t id, j6_cap_t caps, obj::
|
|||||||
return j6_status_ok;
|
return j6_status_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void release_handle(j6_handle_t id) { g_cap_table.release(id); }
|
||||||
|
inline void release_handle(j6_handle_t *id) { g_cap_table.release(*id); }
|
||||||
|
|
||||||
} // namespace syscalls
|
} // namespace syscalls
|
||||||
|
|||||||
Reference in New Issue
Block a user