You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
295 lines
6.8 KiB
295 lines
6.8 KiB
#include "watchos.h"
|
|
#include "Event.h"
|
|
#include "EventListener.h"
|
|
#include "IRunnable.h"
|
|
|
|
struct KernelHandle
|
|
{
|
|
kernel_handle_t handle;
|
|
kernel_handle_destructor_t destructor;
|
|
void* object;
|
|
uint references;
|
|
uint32_t well_known = 0;
|
|
};
|
|
|
|
struct KernelTask
|
|
{
|
|
kernel_handle_t handle;
|
|
Task* task;
|
|
};
|
|
|
|
struct KernelEventSubscription
|
|
{
|
|
kernel_handle_t handle;
|
|
well_known_handle_t source_mask;
|
|
uint16_t event_mask;
|
|
EventListener* listener;
|
|
};
|
|
|
|
Kernel* g_kernel;
|
|
|
|
void destruct_task(kernel_handle_t handle, void* object)
|
|
{
|
|
Task* task = static_cast<Task*>(object);
|
|
g_kernel->unregisterTask(task);
|
|
delete static_cast<Task*>(task);
|
|
}
|
|
|
|
void destruct_event(kernel_handle_t, void* object)
|
|
{
|
|
delete static_cast<Event*>(object);
|
|
}
|
|
|
|
void destruct_event_subscription(kernel_handle_t, void* object)
|
|
{
|
|
KernelEventSubscription* sub = static_cast<KernelEventSubscription*>(object);
|
|
g_kernel->unsubscribeEvent(sub);
|
|
delete static_cast<KernelEventSubscription*>(sub);
|
|
}
|
|
|
|
Kernel::Kernel()
|
|
{
|
|
g_kernel = this;
|
|
|
|
for (int i = 0; i < KERNEL_MAX_HANDLES; i++)
|
|
{
|
|
m_handle[i] = nullptr;
|
|
}
|
|
|
|
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
|
|
{
|
|
m_task[i] = nullptr;
|
|
}
|
|
|
|
for (int i = 0; i < KERNEL_MAX_EVENT_SUBSCRIPTIONS; i++)
|
|
{
|
|
m_event_subscription[i] = nullptr;
|
|
}
|
|
}
|
|
|
|
kernel_handle_t Kernel::allocHandle(byte type, void* object, kernel_handle_destructor_t destructor, uint32_t well_known)
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_HANDLES; i++)
|
|
{
|
|
if (m_handle[i] == nullptr)
|
|
{
|
|
m_handle[i] = new KernelHandle();
|
|
m_handle[i]->handle = (type << 24) | m_next_handle++;
|
|
m_handle[i]->destructor = destructor;
|
|
m_handle[i]->object = object;
|
|
m_handle[i]->references = 0;
|
|
m_handle[i]->well_known = well_known;
|
|
return m_handle[i]->handle;
|
|
}
|
|
}
|
|
watchos::panic("Exceeded KERNEL_MAX_HANDLES");
|
|
}
|
|
|
|
void Kernel::freeHandle(kernel_handle_t handle)
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_HANDLES; i++)
|
|
{
|
|
if (m_handle[i] != nullptr && m_handle[i]->handle == handle)
|
|
{
|
|
if (m_handle[i]->destructor != nullptr)
|
|
{
|
|
(m_handle[i]->destructor)(handle, m_handle[i]->object);
|
|
}
|
|
delete m_handle[i];
|
|
m_handle[i] = nullptr;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void* Kernel::getHandle(kernel_handle_t handle)
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_HANDLES; i++)
|
|
{
|
|
if (m_handle[i] != nullptr && m_handle[i]->handle == handle)
|
|
{
|
|
return m_handle[i]->object;
|
|
}
|
|
}
|
|
watchos::panic("Attempt to access invalid Kernel handle");
|
|
}
|
|
|
|
kernel_handle_t Kernel::getHandleForWellKnown(well_known_handle_t well_known)
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_HANDLES; i++)
|
|
{
|
|
if (m_handle[i] != nullptr && m_handle[i]->well_known == well_known)
|
|
{
|
|
return m_handle[i]->handle;
|
|
}
|
|
}
|
|
watchos::panic("Attempt to get handle for invalid well-known id: %#010x", well_known);
|
|
}
|
|
|
|
void Kernel::useHandle(kernel_handle_t handle)
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_HANDLES; i++)
|
|
{
|
|
if (m_handle[i] != nullptr && m_handle[i]->handle == handle)
|
|
{
|
|
m_handle[i]->references++;
|
|
return;
|
|
}
|
|
}
|
|
|
|
watchos::panic("Attempt to increase ref count on invalid Kernel handle");
|
|
}
|
|
|
|
void Kernel::releaseHandle(kernel_handle_t handle)
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_HANDLES; i++)
|
|
{
|
|
if (m_handle[i] != nullptr && m_handle[i]->handle == handle)
|
|
{
|
|
m_handle[i]->references--;
|
|
|
|
if (m_handle[i]->references == 0)
|
|
{
|
|
freeHandle(handle);
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
watchos::panic("Attempt to release invalid Kernel handle");
|
|
}
|
|
|
|
kernel_handle_t Kernel::registerTask(Task* task, well_known_handle_t wk_handle)
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
|
|
{
|
|
if (m_task[i] == nullptr)
|
|
{
|
|
m_task[i] = new KernelTask();
|
|
m_task[i]->handle = allocHandle(WATCHOS_HANDLE_TYPE_TASK, task, (kernel_handle_destructor_t)destruct_task, wk_handle);
|
|
m_task[i]->task = task;
|
|
useHandle(m_task[i]->handle);
|
|
return m_task[i]->handle;
|
|
}
|
|
}
|
|
|
|
watchos::panic("Exceeded KERNEL_MAX_TASKS");
|
|
}
|
|
|
|
void Kernel::unregisterTask(Task* task)
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
|
|
{
|
|
if (m_task[i] != nullptr && m_task[i]->task == task)
|
|
{
|
|
delete m_task[i]->task;
|
|
delete m_task[i];
|
|
m_task[i] = nullptr;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Kernel::initialize()
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
|
|
{
|
|
if (m_task[i] != nullptr)
|
|
{
|
|
m_task[i]->task->initialize();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Kernel::start()
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
|
|
{
|
|
if (m_task[i] != nullptr)
|
|
{
|
|
m_task[i]->task->start();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Kernel::suspend()
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
|
|
{
|
|
if (m_task[i] != nullptr)
|
|
{
|
|
m_task[i]->task->suspend();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Kernel::pushEvent(well_known_handle_t source, uint16_t event, byte param1, byte param2)
|
|
{
|
|
Event* e = new Event();
|
|
e->source = source;
|
|
e->event = event;
|
|
e->param1 = param1;
|
|
e->param2 = param2;
|
|
kernel_handle_t handle = allocHandle(WATCHOS_HANDLE_TYPE_EVENT, e, (kernel_handle_destructor_t)destruct_event);
|
|
useHandle(handle);
|
|
|
|
for (int i = 0; i < KERNEL_MAX_EVENT_SUBSCRIPTIONS; i++)
|
|
{
|
|
if (m_event_subscription[i] != nullptr &&
|
|
(m_event_subscription[i]->source_mask & source) == source &&
|
|
(m_event_subscription[i]->event_mask & event) == event)
|
|
{
|
|
m_event_subscription[i]->listener->pushEvent(handle);
|
|
}
|
|
}
|
|
|
|
// Now release our reference to it, if we've passed it to anyone they have open references.
|
|
// If nothing matched, that was the last reference and we'll just clean it up right away.
|
|
releaseHandle(handle);
|
|
}
|
|
|
|
kernel_handle_t Kernel::subscribeEvent(EventListener* listener, well_known_handle_t source_mask, uint16_t event_mask)
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_EVENT_SUBSCRIPTIONS; i++)
|
|
{
|
|
if (m_event_subscription[i] == nullptr)
|
|
{
|
|
m_event_subscription[i] = new KernelEventSubscription();
|
|
m_event_subscription[i]->source_mask = source_mask;
|
|
m_event_subscription[i]->event_mask = event_mask;
|
|
m_event_subscription[i]->listener = listener;
|
|
m_event_subscription[i]->handle = allocHandle(WATCHOS_HANDLE_TYPE_EVENT_SUBSCRIPTION, m_event_subscription[i], (kernel_handle_destructor_t)destruct_event_subscription);
|
|
useHandle(m_event_subscription[i]->handle);
|
|
return m_event_subscription[i]->handle;
|
|
}
|
|
}
|
|
watchos::panic("Exceeded KERNEL_MAX_EVENT_SUBSCRIPTIONS");
|
|
}
|
|
|
|
void Kernel::unsubscribeEvent(KernelEventSubscription* subscription)
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_EVENT_SUBSCRIPTIONS; i++)
|
|
{
|
|
if (m_event_subscription[i] != nullptr && m_event_subscription[i] == subscription)
|
|
{
|
|
m_event_subscription[i] = nullptr;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Kernel::tick()
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
|
|
{
|
|
if (m_task[i] != nullptr)
|
|
{
|
|
IRunnable* runnable = dynamic_cast<IRunnable*>(m_task[i]->task);
|
|
if (runnable != nullptr)
|
|
{
|
|
runnable->tick();
|
|
}
|
|
}
|
|
}
|
|
}
|