Max OS 0.3
Loading...
Searching...
No Matches
resource_bridge.cpp
Go to the documentation of this file.
1
10
11using namespace MaxOS;
12using namespace MaxOS::processes;
13using namespace MaxOS::processes::resources;
14using namespace MaxOS::common;
15using namespace MaxOS::memory;
16using namespace MaxOS::KPI;
17
21BridgeHandler::BridgeHandler(string const& shared_name, Process* owner_process)
22: m_owner_process(owner_process)
23{
24
25 // Get the shared memory region
26 auto shared_memory = (SharedMemory*)GlobalResourceRegistry::get_registry(resource_type_t::SHARED_MEMORY)->get_resource(shared_name);
27 ASSERT(shared_memory != nullptr, "Shared memory resource not found\n");
28
29 // Copy into the kernel
30 ASSERT(shared_memory->size() == SERVICE_SHARED_MEM_SIZE, "Shared memory resource size mismatch\n");
31 auto address = MemoryManager::s_kernel_memory_manager->vmm()->load_shared_memory(shared_memory->physical_address(), SERVICE_SHARED_MEM_SIZE);
32
33 // Setup the message region
34 m_message_ring = (service_message_ring_t*)address;
35
36 // Setup the data region
37 m_data_region = (uintptr_t)address + MESSAGE_SIZE;
38 setup_region(m_data_region, DATA_SIZE);
39}
40
41
42BridgeHandler::~BridgeHandler() = default;
43
53size_t BridgeHandler::store_data(const void *buffer, size_t size, bool reserve_only) {
54
55 // Nothing to store
56 if (!size)
57 return 0;
58
59 bool is_mapped = size >= MAX_COPY_SIZE;
60
61 // Set up the storage
62 void* data;
63 if (is_mapped) {
65 MemoryManager::switch_active_memory_manager(m_owner_process->memory_manager);
66 data = m_owner_process->memory_manager->vmm()->load_range_from_process(caller->vmm(), buffer, size);
67 MemoryManager::switch_active_memory_manager(caller);
68 } else {
69 m_lock.lock();
70 data = allocate(size);
71 m_lock.unlock();
72 }
73 ASSERT(data != nullptr, "Could not allocate memory for bridge\n");
74
75 // Copy the data
76 if (!reserve_only && !is_mapped)
77 memcpy(data, buffer, size);
78
79 // If not mapped then its an offset into the process's own virtual address for the shared mem
80 return (size_t)data - (is_mapped ? 0 : m_data_region);
81
82}
83
89service_resource_message_t* BridgeHandler::aquire_slot() {
90
91 // Find a spot
92 while (true) {
93
94 // Get the data
95 size_t head = __atomic_load_n(&m_message_ring->head, __ATOMIC_RELAXED);
96 size_t tail = __atomic_load_n(&m_message_ring->tail, __ATOMIC_ACQUIRE);
97
98 ASSERT((head < MESSAGE_SLOTS && tail < MESSAGE_SLOTS), "invalid queue indexes for resource bridge");
99
100 // No available spots to claim
101 size_t next = (head + 1) % MESSAGE_SLOTS;
102 if (next == tail) {
104 continue;
105 }
106
107 // Try to claim a spot
108 if(!__atomic_compare_exchange_n(&m_message_ring->head, &head, next,true,__ATOMIC_ACQ_REL,__ATOMIC_RELAXED))
109 continue;
110
111 // Claim slot
112 size_t slot = head;
113 return &m_message_ring->ring_buffer[slot];
114 }
115}
116
123 return __atomic_fetch_add(&m_next_id, 1, __ATOMIC_RELAXED);
124}
125
126
127
139int64_t BridgeHandler::send_to_bridge(size_t id, ServiceResourceCommand command, const void *buffer, size_t size, size_t flags) {
140
141 // Copy data into shared region
142 bool is_read = command == ServiceResourceCommand::R_READ; // || command == BridgeResourceCommand::R_READ_ATTR;
143 bool is_page_mapped = size >= MAX_COPY_SIZE;
144 size_t offset = store_data(buffer, size, is_read);
145
146 // Construct the message
147 auto slot = aquire_slot();
148 __atomic_store_n(&slot->sending_pid, GlobalScheduler::current_process()->pid(), __ATOMIC_RELAXED);
149 __atomic_store_n(&slot->resource_id, id, __ATOMIC_RELAXED);
150 __atomic_store_n(&slot->flags, flags, __ATOMIC_RELAXED);
151 __atomic_store_n(&slot->command, (uint8_t)command, __ATOMIC_RELAXED);
152 __atomic_store_n(&slot->data_size, size, __ATOMIC_RELAXED);
153 __atomic_store_n(&slot->data_offset, offset, __ATOMIC_RELAXED);
154 __atomic_store_n(&slot->data_page_mapped, is_page_mapped, __ATOMIC_RELAXED);
155 __atomic_store_n(&slot->response, 0, __ATOMIC_RELAXED);
156 __atomic_store_n(&slot->state, (uint8_t)ServiceMessageSlotState::REQUEST, __ATOMIC_RELEASE);
157
158 // Wait for a response
159 while (__atomic_load_n(&slot->state, __ATOMIC_ACQUIRE) == (uint8_t)ServiceMessageSlotState::REQUEST)
161
162 // Read request
163 if (is_read && !is_page_mapped)
164 memcpy((void*)buffer, (void*)m_data_region + offset, size);
165
166 // Free resources
167 if (size != 0) {
168 if (is_page_mapped) {
170 MemoryManager::switch_active_memory_manager(m_owner_process->memory_manager);
171 m_owner_process->memory_manager->vmm()->unload_range_from_process((void*)offset, size);
172 MemoryManager::switch_active_memory_manager(caller);
173 }
174 else {
175 m_lock.lock();
176 unallocate((void*)m_data_region + offset);
177 m_lock.unlock();
178 }
179 }
180
181 // Get the response and then release the slot
182 int64_t response = __atomic_load_n(&slot->response, __ATOMIC_RELAXED);
183 __atomic_store_n(&slot->state, (uint8_t)ServiceMessageSlotState::FREE,__ATOMIC_RELEASE);
184
185 return response;
186}
187
188
189BridgeResource::BridgeResource(const string &name, size_t flags, resource_type_t type)
190: Resource(name, flags, type)
191{
192}
193
194BridgeResource::~BridgeResource() = default;
195
201void BridgeResource::open(size_t flags) {
202 m_handler -> send_to_bridge(m_id, ServiceResourceCommand::R_OPEN, 0,0, flags);
203}
204
210void BridgeResource::close(size_t flags) {
211 m_handler -> send_to_bridge(m_id, ServiceResourceCommand::R_CLOSE, 0,0, flags);
212}
213
223int BridgeResource::read(void *buffer, size_t size, size_t flags) {
224 return m_handler -> send_to_bridge(m_id, ServiceResourceCommand::R_READ, buffer, size, flags);
225}
226
235int BridgeResource::write(const void *buffer, size_t size, size_t flags) {
236 return m_handler -> send_to_bridge(m_id, ServiceResourceCommand::R_WRITE, buffer, size, flags);
237}
238
239void BridgeResource::attach_wrapper(BridgeHandler *wrapper) {
240
241 m_handler = wrapper;
242 m_id = wrapper->allocate_id();
243
244}
245
252
253 // Let the bridge get the object on its end
254 return m_handler -> send_to_bridge(m_id, ServiceResourceCommand::S_GET, name().c_str(),name().length() + 1, 0) > 0;
255
256
257}
258
263
264 // Let the bridge construct the object on its end
265 m_handler -> send_to_bridge(m_id, ServiceResourceCommand::S_CREATE, name().c_str(),name().length() + 1, 0);
266
267}
268
269
270BridgeResourceRegistry::BridgeResourceRegistry(const string &shared_name, size_t resource_id)
271: ResourceRegistry((resource_type_t)resource_id),
272 m_handler(shared_name, GlobalScheduler::current_process())
273{
274
275}
276
277BridgeResourceRegistry::~BridgeResourceRegistry() = default;
278
280
281 // Resource already opened
282 auto resource = BaseResourceRegistry::get_resource(name);
283 if(resource != nullptr)
284 return resource;
285
286 // Setup a temporary resource
287 auto attempt_resource = new BridgeResource(name, 0, m_type);
288 attempt_resource->attach_wrapper(&m_handler);
289
290 // Try open on the server
291 if (attempt_resource->get_on_bridge()) {
292 register_resource(attempt_resource);
293 return attempt_resource;
294 }
295
296 // Must have failed to get on server
297 delete attempt_resource;
298 return nullptr;
299}
300
308Resource* BridgeResourceRegistry::create_resource(const string &name, size_t flags, uintptr_t data) {
309
310 // Create the resource
311 auto resource = new BridgeResource(name, flags, m_type);
312
313 // Creation failed
314 if(!register_resource(resource)) {
315 delete resource;
316 return nullptr;
317 }
318
319 // Handoff setup to bridge
320 resource->attach_wrapper(&m_handler);
321 resource->create_on_bridge();
322 return resource;
323}
Handles memory allocation and deallocation.
static MemoryManager * s_kernel_memory_manager
The memory manager for any kernel processes and all kernel allocations.
void unload_range_from_process(const void *start_address, size_t size)
Unload a shared range of pages from this vmm.
Definition virtual.cpp:602
void * load_range_from_process(VirtualMemoryManager *other_vmm, const void *start_address, size_t size)
Loads the pages from a virtual memory region in another vmm into this one.
Definition virtual.cpp:552
void * load_shared_memory(const string &name)
Load shared memory into the VMM's address space.
Definition virtual.cpp:487
void unallocate(void *pointer) final
Frees a block of memory.
Definition bump.cpp:212
void * allocate(size_t size) final
Allocates a block of memory.
Definition bump.cpp:144
void setup_region(uintptr_t address, size_t length) final
Setup a region to be bump memory managed, creates a free chunk represent the whole region.
Definition bump.cpp:122
The global scheduler that manages all processes and threads across all cores.
Definition scheduler.h:28
static Process * current_process()
Gets the process on the currently executing core.
static Thread * current_thread()
Gets the thread on the currently executing core.
A process that can be scheduled by the Scheduler, wraps & manages threads as well as its own address ...
Definition process.h:94
uint64_t pid() const
Gets the pid of the process.
Definition process.cpp:429
memory::MemoryManager * memory_manager
The manager for memory used by this process.
Definition process.h:121
A block memory that is mapped into multiple processes.
Definition ipc.h:45
void yield()
Pass execution to the next ready thread.
Definition process.cpp:103
resource_type_t m_type
The resource type that this registry manages.
Definition resource.h:40
virtual Resource * get_resource(const string &name)
Gets a resource from the registry by name.
Definition resource.cpp:52
bool register_resource(Resource *resource)
Registers a resource in the registry.
Definition resource.cpp:76
A handler to manage resource commands over shared memory.
BridgeHandler(string const &shared_name, Process *owner_process)
Constructs a handler to manage resource commands over shared memory.
size_t allocate_id()
Allocates an ID to identify a resource on the bridge.
int64_t send_to_bridge(size_t id, KPI::ServiceResourceCommand command, const void *buffer, size_t size, size_t flags)
Send a command and its associated data to the endpoint associated with this resource.
Resource * get_resource(const string &name) final
Gets a resource from the registry by name.
Resource * create_resource(const string &name, size_t flags, uintptr_t data) final
Create a new resource on the bridge.
A generic wrapper for a Resource that exists on a userspace server which exposes its operations as Re...
void close(size_t flags) final
Closes the resource.
void create_on_bridge()
Passes the creation of a resource to the bridge.
int write(const void *buffer, size_t size, size_t flags) final
write a certain amount of bytes to a resource
void open(size_t flags) final
Opens the resource.
int read(void *buffer, size_t size, size_t flags) final
Reads data from the resource.
bool get_on_bridge()
Attempt to get a resource on a bridge endpoint that may not be registered yet.
static BaseResourceRegistry * get_registry(resource_type_t type)
Gets a registry of a type.
Definition resource.cpp:161
A resource registry for a specific resource type.
Definition resource.h:61
KPI::Resource Resource
Alias to make the libsyscore Resource accessible here.
Definition resource.h:26
KPI::ResourceType resource_type_t
Alias to make the libsyscore ResourceType accessible here.
Definition resource.h:25
Defines scheduler resource classes for wrapping userspace bridge Resources in the Global Scheduler,...