mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-25 05:55:13 +00:00
LibThread: Introduce a new threading library
This library is meant to provide C++-style wrappers over lower level APIs such as syscalls and pthread_* functions, as well as utilities for easily running pieces of logic on different threads.
This commit is contained in:
parent
d5f3487203
commit
e1a6f8a27d
Notes:
sideshowbarker
2024-07-19 12:31:27 +09:00
Author: https://github.com/bugaevc Commit: https://github.com/SerenityOS/serenity/commit/e1a6f8a27d7 Pull-request: https://github.com/SerenityOS/serenity/pull/486 Reviewed-by: https://github.com/awesomekling
9 changed files with 211 additions and 3 deletions
|
@ -3,7 +3,7 @@ DEFINES += -DUSERLAND
|
|||
all: $(APP)
|
||||
|
||||
$(APP): $(OBJS)
|
||||
$(LD) -o $(APP) $(LDFLAGS) $(OBJS) -lgui -ldraw -laudio -lipc -lvt -lpcidb -lcore -lc
|
||||
$(LD) -o $(APP) $(LDFLAGS) $(OBJS) -lgui -ldraw -laudio -lipc -lthread -lvt -lpcidb -lcore -lc
|
||||
|
||||
.cpp.o:
|
||||
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
|
||||
|
|
|
@ -19,10 +19,11 @@ build_targets=""
|
|||
build_targets="$build_targets ../DevTools/IPCCompiler"
|
||||
build_targets="$build_targets ../DevTools/FormCompiler"
|
||||
|
||||
# Build LibC, LibCore and LibIPC before IPC servers, since they depend on it.
|
||||
# Build LibC, LibCore, LibIPC and LibThread before IPC servers, since they depend on them.
|
||||
build_targets="$build_targets ../Libraries/LibC"
|
||||
build_targets="$build_targets ../Libraries/LibCore"
|
||||
build_targets="$build_targets ../Libraries/LibIPC"
|
||||
build_targets="$build_targets ../Libraries/LibThread"
|
||||
|
||||
# Build IPC servers before their client code to ensure the IPC definitions are available.
|
||||
build_targets="$build_targets ../Servers/AudioServer"
|
||||
|
|
48
Libraries/LibThread/BackgroundAction.cpp
Normal file
48
Libraries/LibThread/BackgroundAction.cpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
#include <LibThread/BackgroundAction.h>
|
||||
#include <LibThread/Thread.h>
|
||||
#include <LibCore/CLock.h>
|
||||
#include <AK/Queue.h>
|
||||
|
||||
static CLockable<Queue<Function<void()>>>* s_all_actions;
|
||||
static LibThread::Thread* s_background_thread;
|
||||
|
||||
static int background_thread_func()
|
||||
{
|
||||
while (true) {
|
||||
Function<void()> work_item;
|
||||
{
|
||||
LOCKER(s_all_actions->lock());
|
||||
|
||||
if (!s_all_actions->resource().is_empty())
|
||||
work_item = s_all_actions->resource().dequeue();
|
||||
}
|
||||
if (work_item)
|
||||
work_item();
|
||||
else
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
static void init()
|
||||
{
|
||||
s_all_actions = new CLockable<Queue<Function<void()>>>();
|
||||
s_background_thread = new LibThread::Thread(background_thread_func);
|
||||
s_background_thread->set_name("Background thread");
|
||||
s_background_thread->start();
|
||||
}
|
||||
|
||||
CLockable<Queue<Function<void()>>>& LibThread::BackgroundActionBase::all_actions()
|
||||
{
|
||||
if (s_all_actions == nullptr)
|
||||
init();
|
||||
return *s_all_actions;
|
||||
}
|
||||
|
||||
LibThread::Thread& LibThread::BackgroundActionBase::background_thread()
|
||||
{
|
||||
if (s_background_thread == nullptr)
|
||||
init();
|
||||
return *s_background_thread;
|
||||
}
|
75
Libraries/LibThread/BackgroundAction.h
Normal file
75
Libraries/LibThread/BackgroundAction.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Function.h>
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/Queue.h>
|
||||
#include <AK/RefCounted.h>
|
||||
#include <LibCore/CEventLoop.h>
|
||||
#include <LibCore/CLock.h>
|
||||
#include <LibCore/CObject.h>
|
||||
#include <LibThread/Thread.h>
|
||||
|
||||
namespace LibThread {
|
||||
|
||||
template<typename Result>
|
||||
class BackgroundAction;
|
||||
|
||||
class BackgroundActionBase {
|
||||
template<typename Result>
|
||||
friend class BackgroundAction;
|
||||
|
||||
private:
|
||||
BackgroundActionBase() {}
|
||||
|
||||
static CLockable<Queue<Function<void()>>>& all_actions();
|
||||
static Thread& background_thread();
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
class BackgroundAction final : public CObject
|
||||
, public RefCounted<BackgroundAction<Result>>
|
||||
, private BackgroundActionBase {
|
||||
|
||||
C_OBJECT(BackgroundAction);
|
||||
|
||||
public:
|
||||
static NonnullRefPtr<BackgroundAction<Result>> create(
|
||||
Function<Result()> action,
|
||||
Function<void(Result)> on_complete = nullptr
|
||||
)
|
||||
{
|
||||
return adopt(*new BackgroundAction(move(action), move(on_complete)));
|
||||
}
|
||||
|
||||
virtual ~BackgroundAction() {}
|
||||
|
||||
private:
|
||||
|
||||
BackgroundAction(Function<Result()> action, Function<void(Result)> on_complete)
|
||||
: CObject(background_thread())
|
||||
, m_action(move(action))
|
||||
, m_on_complete(move(on_complete))
|
||||
{
|
||||
LOCKER(all_actions().lock());
|
||||
|
||||
this->ref();
|
||||
all_actions().resource().enqueue([this] {
|
||||
m_result = m_action();
|
||||
if (m_on_complete) {
|
||||
CEventLoop::main().post_event(*this, make<CDeferredInvocationEvent>([this](CObject&) {
|
||||
m_on_complete(m_result.release_value());
|
||||
this->deref();
|
||||
}));
|
||||
CEventLoop::main().wake();
|
||||
} else
|
||||
this->deref();
|
||||
});
|
||||
}
|
||||
|
||||
Function<Result()> m_action;
|
||||
Function<void(Result)> m_on_complete;
|
||||
Optional<Result> m_result;
|
||||
};
|
||||
|
||||
}
|
21
Libraries/LibThread/Makefile
Normal file
21
Libraries/LibThread/Makefile
Normal file
|
@ -0,0 +1,21 @@
|
|||
include ../../Makefile.common
|
||||
|
||||
OBJS = \
|
||||
Thread.o \
|
||||
BackgroundAction.o
|
||||
|
||||
LIBRARY = libthread.a
|
||||
DEFINES += -DUSERLAND
|
||||
|
||||
all: $(LIBRARY)
|
||||
|
||||
$(LIBRARY): $(OBJS)
|
||||
@echo "LIB $@"; $(AR) rcs $@ $(OBJS) $(LIBS)
|
||||
|
||||
.cpp.o:
|
||||
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
|
||||
|
||||
-include $(OBJS:%.o=%.d)
|
||||
|
||||
clean:
|
||||
@echo "CLEAN"; rm -f $(LIBRARY) $(OBJS) *.d
|
39
Libraries/LibThread/Thread.cpp
Normal file
39
Libraries/LibThread/Thread.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#include <LibThread/Thread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
LibThread::Thread::Thread(Function<int()> action)
|
||||
: CObject(nullptr)
|
||||
, m_action(move(action))
|
||||
{
|
||||
}
|
||||
|
||||
LibThread::Thread::~Thread()
|
||||
{
|
||||
if (m_tid != -1) {
|
||||
dbg() << "trying to destroy a running thread!";
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
void LibThread::Thread::start()
|
||||
{
|
||||
int rc = create_thread([](void* arg) {
|
||||
Thread* self = static_cast<Thread*>(arg);
|
||||
int exit_code = self->m_action();
|
||||
self->m_tid = -1;
|
||||
exit_thread(exit_code);
|
||||
return exit_code;
|
||||
}, static_cast<void*>(this));
|
||||
|
||||
ASSERT(rc > 0);
|
||||
dbg() << "Started a thread, tid = " << rc;
|
||||
m_tid = rc;
|
||||
}
|
||||
|
||||
void LibThread::Thread::quit(int code)
|
||||
{
|
||||
ASSERT(m_tid == gettid());
|
||||
|
||||
m_tid = -1;
|
||||
exit_thread(code);
|
||||
}
|
23
Libraries/LibThread/Thread.h
Normal file
23
Libraries/LibThread/Thread.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Function.h>
|
||||
#include <LibCore/CObject.h>
|
||||
|
||||
namespace LibThread {
|
||||
|
||||
class Thread final : public CObject {
|
||||
C_OBJECT(Thread);
|
||||
|
||||
public:
|
||||
explicit Thread(Function<int()> action);
|
||||
virtual ~Thread();
|
||||
|
||||
void start();
|
||||
void quit(int code = 0);
|
||||
|
||||
private:
|
||||
Function<int()> m_action;
|
||||
int m_tid { -1 };
|
||||
};
|
||||
|
||||
}
|
|
@ -22,6 +22,7 @@ LDFLAGS = \
|
|||
-L$(SERENITY_BASE_DIR)/Libraries/LibM \
|
||||
-L$(SERENITY_BASE_DIR)/Libraries/LibDraw \
|
||||
-L$(SERENITY_BASE_DIR)/Libraries/LibGUI \
|
||||
-L$(SERENITY_BASE_DIR)/Libraries/LibThread \
|
||||
-L$(SERENITY_BASE_DIR)/Libraries/LibVT \
|
||||
-L$(SERENITY_BASE_DIR)/Libraries/LibAudio
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ clean:
|
|||
|
||||
$(APPS) : % : %.o $(OBJS)
|
||||
@echo "LD $@"
|
||||
@$(LD) -o $@ $(LDFLAGS) $< -lc -lgui -ldraw -laudio -lipc -lcore -lpcidb
|
||||
@$(LD) -o $@ $(LDFLAGS) $< -lc -lgui -ldraw -laudio -lipc -lthread -lcore -lpcidb
|
||||
|
||||
%.o: %.cpp
|
||||
@echo "CXX $<"
|
||||
|
|
Loading…
Add table
Reference in a new issue