Compare commits
2 Commits
d4d748e153
...
63f785563d
Author | SHA1 | Date | |
---|---|---|---|
63f785563d | |||
1cd355a8e8 |
@ -9,11 +9,12 @@
|
||||
|
||||
#pragma once
|
||||
#include <luna/Heap.h>
|
||||
#include <luna/SharedPtr.h>
|
||||
|
||||
namespace os
|
||||
{
|
||||
/**
|
||||
* @brief Wrapper for callable objects.
|
||||
* @brief Wrapper for callable objects with no arguments.
|
||||
*
|
||||
* Certain callable types such as capture lambdas don't have a named type, thus they can't be passed to functions as
|
||||
* arguments. The Action type acts as a callable wrapper for such functions, allowing them to be passed as arguments
|
||||
@ -40,7 +41,16 @@ namespace os
|
||||
*/
|
||||
Action(Action&& other) : m_action(other.m_action)
|
||||
{
|
||||
other.m_action = nullptr;
|
||||
other.m_action = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a new Action object, copying it from another one.
|
||||
*
|
||||
* @param other The old Action object to copy from.
|
||||
*/
|
||||
Action(const Action& other) : m_action(other.m_action)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
@ -52,7 +62,8 @@ namespace os
|
||||
*/
|
||||
template <typename T> Action(T&& function)
|
||||
{
|
||||
m_action = new (std::nothrow) ActionImpl<T>(move(function));
|
||||
m_action =
|
||||
adopt_shared_if_nonnull((ActionBase*)new (std::nothrow) ActionImpl<T>(move(function))).release_value();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -65,8 +76,8 @@ namespace os
|
||||
*/
|
||||
template <typename T> Action& operator=(T&& function)
|
||||
{
|
||||
if (m_action) delete m_action;
|
||||
m_action = new (std::nothrow) ActionImpl<T>(move(function));
|
||||
m_action =
|
||||
adopt_shared_if_nonnull((ActionBase*)new (std::nothrow) ActionImpl<T>(move(function))).release_value();
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -79,13 +90,8 @@ namespace os
|
||||
return m_action->call();
|
||||
}
|
||||
|
||||
~Action()
|
||||
{
|
||||
if (m_action) delete m_action;
|
||||
}
|
||||
|
||||
private:
|
||||
class ActionBase
|
||||
class ActionBase : public Shareable
|
||||
{
|
||||
public:
|
||||
virtual void call() = 0;
|
||||
@ -108,6 +114,110 @@ namespace os
|
||||
T m_function;
|
||||
};
|
||||
|
||||
ActionBase* m_action;
|
||||
SharedPtr<ActionBase> m_action;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Wrapper for callable objects.
|
||||
*
|
||||
* Certain callable types such as capture lambdas don't have a named type, thus they can't be passed to functions as
|
||||
* arguments. The Function type acts as a callable wrapper for such functions, allowing them to be passed as
|
||||
* arguments to any function.
|
||||
*/
|
||||
template <class... Args> class Function
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new empty Function object.
|
||||
*
|
||||
* Since it is not wrapping any callable object, this object is invalid and attempting to invoke its
|
||||
* (nonexistent) callable object will result in a crash at runtime.
|
||||
*/
|
||||
Function()
|
||||
{
|
||||
m_action = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a new Function object, moving it from another one.
|
||||
*
|
||||
* @param other The old Function object to move from. This object will become invalid.
|
||||
*/
|
||||
Function(Function&& other) : m_action(other.m_action)
|
||||
{
|
||||
other.m_action = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a new Function object, copying it from another one.
|
||||
*
|
||||
* @param other The old Function object to copy from.
|
||||
*/
|
||||
Function(const Function& other) : m_action(other.m_action)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a new Function object from a callable object.
|
||||
*
|
||||
* @tparam T The type of the callable object. Since this can be guessed by template deduction, the object
|
||||
* doesn't actually need a type name.
|
||||
* @param function The callable object to wrap.
|
||||
*/
|
||||
template <typename T> Function(T&& function)
|
||||
{
|
||||
m_action = adopt_shared_if_nonnull((FunctionBase*)new (std::nothrow) FunctionImpl<T>(move(function)))
|
||||
.release_value();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assign a new callable object to this Function.
|
||||
*
|
||||
* @tparam T The type of the callable object. Since this can be guessed by template deduction, the object
|
||||
* doesn't actually need a type name.
|
||||
* @param function The callable object to wrap.
|
||||
* @return Action& A reference to this object, as required by operator=().
|
||||
*/
|
||||
template <typename T> Function& operator=(T&& function)
|
||||
{
|
||||
m_action = adopt_shared_if_nonnull((FunctionBase*)new (std::nothrow) FunctionImpl<T>(move(function)))
|
||||
.release_value();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Call the underlying object.
|
||||
*/
|
||||
void operator()(Args... args)
|
||||
{
|
||||
expect(m_action, "os::Function called with no underlying callable object");
|
||||
return m_action->call(args...);
|
||||
}
|
||||
|
||||
private:
|
||||
class FunctionBase : public Shareable
|
||||
{
|
||||
public:
|
||||
virtual void call(Args... args) = 0;
|
||||
virtual ~FunctionBase() = default;
|
||||
};
|
||||
|
||||
template <typename T> class FunctionImpl final : public FunctionBase
|
||||
{
|
||||
public:
|
||||
FunctionImpl(T&& function) : m_function(move(function))
|
||||
{
|
||||
}
|
||||
|
||||
void call(Args... args) override
|
||||
{
|
||||
return m_function(args...);
|
||||
}
|
||||
|
||||
private:
|
||||
T m_function;
|
||||
};
|
||||
|
||||
SharedPtr<FunctionBase> m_action;
|
||||
};
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ namespace os
|
||||
* is the file descriptor registered, and the second argument is the type of event (POLLIN or POLLHUP)
|
||||
* @return Result<void> Whether the operation succeeded.
|
||||
*/
|
||||
Result<void> register_fd_listener(int fd, void (*listener)(int, int));
|
||||
Result<void> register_fd_listener(int fd, Function<int, int> listener);
|
||||
|
||||
/**
|
||||
* @brief Register a new POSIX signal handler.
|
||||
@ -59,7 +59,7 @@ namespace os
|
||||
* @param handler The function to call when this signal is caught.
|
||||
* @return Result<void> Whether the operation succeeded.
|
||||
*/
|
||||
Result<void> register_signal_handler(int sig, void (*handler)(int));
|
||||
Result<void> register_signal_handler(int sig, Function<int> handler);
|
||||
|
||||
/**
|
||||
* @brief Run the event loop until it is asked to quit.
|
||||
@ -76,8 +76,8 @@ namespace os
|
||||
void quit(int status = 0);
|
||||
|
||||
private:
|
||||
HashMap<int, void (*)(int, int)> m_fd_listeners;
|
||||
HashMap<int, void (*)(int)> m_signal_handlers;
|
||||
HashMap<int, Function<int, int>> m_fd_listeners;
|
||||
HashMap<int, Function<int>> m_signal_handlers;
|
||||
Vector<struct pollfd> m_pollfds;
|
||||
|
||||
static void handle_signal(int sig);
|
||||
|
@ -44,15 +44,14 @@ namespace os
|
||||
return *s_the;
|
||||
}
|
||||
|
||||
// FIXME: Support lambdas (by using os::Action). This means that os::Action needs variable parameter support.
|
||||
Result<void> EventLoop::register_fd_listener(int fd, void (*listener)(int, int))
|
||||
Result<void> EventLoop::register_fd_listener(int fd, Function<int, int> listener)
|
||||
{
|
||||
TRY(m_fd_listeners.try_set(fd, listener));
|
||||
TRY(m_fd_listeners.try_set(fd, move(listener)));
|
||||
TRY(m_pollfds.try_append({ .fd = fd, .events = POLLIN, .revents = 0 }));
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> EventLoop::register_signal_handler(int sig, void (*handler)(int))
|
||||
Result<void> EventLoop::register_signal_handler(int sig, Function<int> handler)
|
||||
{
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = EventLoop::handle_signal;
|
||||
@ -60,7 +59,7 @@ namespace os
|
||||
sigemptyset(&sa.sa_mask);
|
||||
check(sigaction(sig, &sa, nullptr) == 0);
|
||||
|
||||
TRY(m_signal_handlers.try_set(sig, handler));
|
||||
TRY(m_signal_handlers.try_set(sig, move(handler)));
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -84,7 +83,7 @@ namespace os
|
||||
read(m_signal_pipe[0], &sig, sizeof(int));
|
||||
|
||||
auto handler = m_signal_handlers.try_get(sig);
|
||||
if (handler.has_value()) { handler.value()(sig); }
|
||||
if (handler.has_value()) { (*handler.value_ptr())(sig); }
|
||||
}
|
||||
|
||||
for (usize i = 0; i < m_fd_listeners.size(); i++)
|
||||
@ -93,7 +92,7 @@ namespace os
|
||||
if (pfd.revents)
|
||||
{
|
||||
auto handler = m_fd_listeners.try_get(pfd.fd);
|
||||
if (handler.has_value()) handler.value()(pfd.fd, pfd.revents);
|
||||
if (handler.has_value()) (*handler.value_ptr())(pfd.fd, pfd.revents);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,8 +35,6 @@ static void sigchld_handler(int)
|
||||
ui::App::the().set_should_close(true);
|
||||
}
|
||||
|
||||
TerminalWidget* s_main = nullptr;
|
||||
|
||||
Result<void> TerminalWidget::init(char* const* args)
|
||||
{
|
||||
m_font = ui::Font::default_font();
|
||||
@ -62,17 +60,10 @@ Result<void> TerminalWidget::init(char* const* args)
|
||||
|
||||
fcntl(m_pty, F_SETFL, O_NONBLOCK);
|
||||
|
||||
// FIXME: Find a better solution for this. What if the caller needs several TerminalWidgets in one app? We can't
|
||||
// just use a singleton, can we?
|
||||
os::EventLoop::the().register_fd_listener(m_pty, [](int, int) {
|
||||
check(s_main);
|
||||
s_main->process();
|
||||
});
|
||||
os::EventLoop::the().register_fd_listener(m_pty, [this](int, int) { this->process(); });
|
||||
|
||||
m_child_pid = child;
|
||||
|
||||
s_main = this;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user