1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2025-02-21 21:57:01 +00:00

perf: use condition variables during tr thread startup (#2737)

* perf: use condition variables during tr thread startup
This commit is contained in:
Charles Kerr 2022-03-04 14:43:56 -08:00 committed by GitHub
parent 0cd3eb26ff
commit 8d8ea2f4df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 32 additions and 25 deletions

View file

@ -7,7 +7,6 @@
#include <cstring> /* memset() */
#include <ctime>
#include <list>
#include <set>
#include <string_view>
#include <vector>

View file

@ -6,6 +6,7 @@
#include <algorithm> // std::partial_sort(), std::min(), std::max()
#include <cerrno> /* ENOENT */
#include <climits> /* INT_MAX */
#include <condition_variable>
#include <csignal>
#include <cstdint>
#include <cstdlib>
@ -592,11 +593,11 @@ static void tr_sessionInitImpl(void* /*vdata*/);
struct init_data
{
bool done;
bool messageQueuingEnabled;
tr_session* session;
char const* config_dir;
tr_variant* clientSettings;
std::condition_variable_any done_cv;
};
tr_session* tr_sessionInit(char const* config_dir, bool messageQueuingEnabled, tr_variant* clientSettings)
@ -626,19 +627,22 @@ tr_session* tr_sessionInit(char const* config_dir, bool messageQueuingEnabled, t
tr_eventInit(session);
TR_ASSERT(session->events != nullptr);
/* run the rest in the libtransmission thread */
auto data = init_data{};
data.done = false;
data.session = session;
data.config_dir = config_dir;
data.messageQueuingEnabled = messageQueuingEnabled;
data.clientSettings = clientSettings;
tr_runInEventThread(session, tr_sessionInitImpl, &data);
while (!data.done)
// run it in the libtransmission thread
if (tr_amInEventThread(session))
{
tr_wait_msec(50);
tr_sessionInitImpl(&data);
}
else
{
auto lock = session->unique_lock();
tr_runInEventThread(session, tr_sessionInitImpl, &data);
data.done_cv.wait(lock); // wait for the session to be ready
}
return session;
@ -771,7 +775,7 @@ static void tr_sessionInitImpl(void* vdata)
/* cleanup */
tr_variantFree(&settings);
data->done = true;
data->done_cv.notify_one();
}
static void turtleBootstrap(tr_session* /*session*/, struct tr_turtle_info* /*turtle*/);
@ -1133,22 +1137,26 @@ static void sessionSetImpl(void* vdata)
tr_sessionSetAntiBruteForceEnabled(session, boolVal);
}
data->done = true;
data->done_cv.notify_one();
}
void tr_sessionSet(tr_session* session, tr_variant* settings)
{
struct init_data data;
data.done = false;
auto data = init_data{};
data.session = session;
data.clientSettings = settings;
/* run the rest in the libtransmission thread */
tr_runInEventThread(session, sessionSetImpl, &data);
// run it in the libtransmission thread
while (!data.done)
if (tr_amInEventThread(session))
{
tr_wait_msec(100);
sessionSetImpl(&data);
}
else
{
auto lock = session->unique_lock();
tr_runInEventThread(session, sessionSetImpl, &data);
data.done_cv.wait(lock);
}
}
@ -1958,7 +1966,7 @@ void tr_sessionClose(tr_session* session)
while (!session->isClosed && !deadlineReached(deadline))
{
dbgmsg("waiting for the libtransmission thread to finish");
tr_wait_msec(100);
tr_wait_msec(10);
}
/* "shared" and "tracker" have live sockets,
@ -1987,7 +1995,7 @@ void tr_sessionClose(tr_session* session)
{
static bool forced = false;
dbgmsg("waiting for libtransmission thread to finish... now %zu deadline %zu", (size_t)time(nullptr), (size_t)deadline);
tr_wait_msec(100);
tr_wait_msec(10);
if (deadlineReached(deadline) && !forced)
{

View file

@ -16,13 +16,11 @@
#include <cstdint> // uintX_t
#include <ctime>
#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <string_view>
#include <tuple>
#include <unordered_set>
#include <vector>
#include "transmission.h"

View file

@ -162,6 +162,7 @@ struct tr_event_handle
using work_queue_t = std::list<callback>;
work_queue_t work_queue;
std::condition_variable work_queue_cv;
std::mutex work_queue_mutex;
event* work_queue_event = nullptr;
@ -210,6 +211,10 @@ static void libeventThreadFunc(tr_event_handle* events)
events->session->evdns_base = dns_base;
events->session->events = events;
// tell the thread that's waiting in tr_eventInit()
// that this thread is ready for business
events->work_queue_cv.notify_one();
// loop until `tr_eventClose()` kills the loop
event_base_loop(base, EVLOOP_NO_EXIT_ON_EMPTY);
@ -234,15 +239,12 @@ void tr_eventInit(tr_session* session)
auto* const events = new tr_event_handle();
events->session = session;
auto lock = std::unique_lock(events->work_queue_mutex);
auto thread = std::thread(libeventThreadFunc, events);
events->thread_id = thread.get_id();
thread.detach();
// wait until the libevent thread is running
while (session->events == nullptr)
{
tr_wait_msec(100);
}
events->work_queue_cv.wait(lock);
}
void tr_eventClose(tr_session* session)