Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion include/envoy/thread/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

#include "common/common/thread_annotations.h"

#include "absl/strings/string_view.h"
#include "absl/types/optional.h"

namespace Envoy {
namespace Thread {

Expand Down Expand Up @@ -36,6 +39,11 @@ class Thread {
public:
virtual ~Thread() = default;

/**
* Returns the name of the thread.
*/
virtual std::string name() const PURE;

/**
* Join on thread exit.
*/
Expand All @@ -44,6 +52,13 @@ class Thread {

using ThreadPtr = std::unique_ptr<Thread>;

// Options specified during thread creation.
struct Options {
std::string name_;
};

using OptionsOptConstRef = const absl::optional<Options>&;

/**
* Interface providing a mechanism for creating threads.
*/
Expand All @@ -54,8 +69,10 @@ class ThreadFactory {
/**
* Create a thread.
* @param thread_routine supplies the function to invoke in the thread.
* @param name supplies a name for the thread. May be truncated per platform limits.
Comment thread
jmarantz marked this conversation as resolved.
Outdated
*/
virtual ThreadPtr createThread(std::function<void()> thread_routine) PURE;
virtual ThreadPtr createThread(std::function<void()> thread_routine,
OptionsOptConstRef options = absl::nullopt) PURE;

/**
* Return the current system thread ID
Expand Down
3 changes: 2 additions & 1 deletion source/common/access_log/access_log_manager_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,8 @@ void AccessLogFileImpl::write(absl::string_view data) {
}

void AccessLogFileImpl::createFlushStructures() {
flush_thread_ = thread_factory_.createThread([this]() -> void { flushThreadFunc(); });
flush_thread_ = thread_factory_.createThread([this]() -> void { flushThreadFunc(); },
Thread::Options{"AccessLogFlush"});
flush_timer_->enableTimer(flush_interval_msec_);
}

Expand Down
77 changes: 63 additions & 14 deletions source/common/common/posix/thread_impl.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include "common/common/assert.h"
#include "common/common/thread_impl.h"

#include "absl/strings/str_cat.h"
#include "absl/synchronization/notification.h"

#if defined(__linux__)
#include <sys/syscall.h>
#endif
Expand All @@ -24,26 +27,72 @@ int64_t getCurrentThreadId() {

} // namespace

ThreadImplPosix::ThreadImplPosix(std::function<void()> thread_routine)
: thread_routine_(std::move(thread_routine)) {
RELEASE_ASSERT(Logger::Registry::initialized(), "");
const int rc = pthread_create(
&thread_handle_, nullptr,
[](void* arg) -> void* {
static_cast<ThreadImplPosix*>(arg)->thread_routine_();
return nullptr;
},
this);
RELEASE_ASSERT(rc == 0, "");
}
// See https://www.man7.org/linux/man-pages/man3/pthread_setname_np.3.html.
// The maximum thread name is 16 bytes including the terminating nul byte,
// so we need to truncate the string_view to 15 bytes.
#define PTHREAD_MAX_LEN_INCLUDING_NULL_BYTE 16
Comment thread
jmarantz marked this conversation as resolved.
Outdated

/**
* Wrapper for a pthread thread. We don't use std::thread because it eats exceptions and leads to
* unusable stack traces.
*/
class ThreadImplPosix : public Thread {
public:
ThreadImplPosix(std::function<void()> thread_routine, OptionsOptConstRef options)
: thread_routine_(std::move(thread_routine)) {
if (options) {
name_ = (std::string(options->name_.substr(0, PTHREAD_MAX_LEN_INCLUDING_NULL_BYTE - 1)));
}
RELEASE_ASSERT(Logger::Registry::initialized(), "");
const int rc = pthread_create(
&thread_handle_, nullptr,
[](void* arg) -> void* {
auto* thread = static_cast<ThreadImplPosix*>(arg);

// Block at thread start waiting for setup to be complete in the initiating thread.
// For example, we want to set the debug name of the thread.
Comment thread
jmarantz marked this conversation as resolved.
Outdated
thread->start_.WaitForNotification();

thread->thread_routine_();
return nullptr;
},
this);
RELEASE_ASSERT(rc == 0, "");
if (!name_.empty()) {
const int set_name_rc = pthread_setname_np(thread_handle_, name_.c_str());
RELEASE_ASSERT(set_name_rc == 0, absl::StrCat("Error ", set_name_rc, " setting name '", name_,
"': ", strerror(set_name_rc)));
#ifndef NDEBUG
// Verify that the name got written into the thread as expected.
char buf[PTHREAD_MAX_LEN_INCLUDING_NULL_BYTE];
const int get_name_rc = pthread_getname_np(thread_handle_, buf, sizeof(buf));
RELEASE_ASSERT(get_name_rc == 0, absl::StrCat("Error ", get_name_rc, " setting name '", name_,
"': ", strerror(get_name_rc)));
#endif
}
start_.Notify();
}

std::string name() const override { return name_; }

// Thread::Thread
void join() override;

private:
std::function<void()> thread_routine_;
pthread_t thread_handle_;
std::string name_;
absl::Notification start_;
};

void ThreadImplPosix::join() {
const int rc = pthread_join(thread_handle_, nullptr);
RELEASE_ASSERT(rc == 0, "");
}

ThreadPtr ThreadFactoryImplPosix::createThread(std::function<void()> thread_routine) {
return std::make_unique<ThreadImplPosix>(thread_routine);
ThreadPtr ThreadFactoryImplPosix::createThread(std::function<void()> thread_routine,
OptionsOptConstRef options) {
return std::make_unique<ThreadImplPosix>(thread_routine, options);
}

ThreadId ThreadFactoryImplPosix::currentThreadId() { return ThreadId(getCurrentThreadId()); }
Expand Down
18 changes: 1 addition & 17 deletions source/common/common/posix/thread_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,13 @@
namespace Envoy {
namespace Thread {

/**
* Wrapper for a pthread thread. We don't use std::thread because it eats exceptions and leads to
* unusable stack traces.
*/
class ThreadImplPosix : public Thread {
public:
ThreadImplPosix(std::function<void()> thread_routine);

// Thread::Thread
void join() override;

private:
std::function<void()> thread_routine_;
pthread_t thread_handle_;
};

/**
* Implementation of ThreadFactory
*/
class ThreadFactoryImplPosix : public ThreadFactory {
public:
// Thread::ThreadFactory
ThreadPtr createThread(std::function<void()> thread_routine) override;
ThreadPtr createThread(std::function<void()> thread_routine, OptionsOptConstRef options) override;
ThreadId currentThreadId() override;
};

Expand Down
61 changes: 39 additions & 22 deletions source/common/common/win32/thread_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,45 @@
namespace Envoy {
namespace Thread {

ThreadImplWin32::ThreadImplWin32(std::function<void()> thread_routine)
: thread_routine_(thread_routine) {
RELEASE_ASSERT(Logger::Registry::initialized(), "");
thread_handle_ = reinterpret_cast<HANDLE>(::_beginthreadex(
nullptr, 0,
[](void* arg) -> unsigned int {
static_cast<ThreadImplWin32*>(arg)->thread_routine_();
return 0;
},
this, 0, nullptr));
RELEASE_ASSERT(thread_handle_ != 0, "");
}

ThreadImplWin32::~ThreadImplWin32() { ::CloseHandle(thread_handle_); }

void ThreadImplWin32::join() {
const DWORD rc = ::WaitForSingleObject(thread_handle_, INFINITE);
RELEASE_ASSERT(rc == WAIT_OBJECT_0, "");
}

ThreadPtr ThreadFactoryImplWin32::createThread(std::function<void()> thread_routine) {
return std::make_unique<ThreadImplWin32>(thread_routine);
/**
* Wrapper for a win32 thread. We don't use std::thread because it eats exceptions and leads to
* unusable stack traces.
*/
class ThreadImplWin32 : public Thread {
public:
ThreadImplWin32(std::function<void()> thread_routine, OptionsOptConstRef options)
: thread_routine_(thread_routine) {
UNREFERENCED_PARAMETER(options); // TODO(jmarantz): set the thread name for task manager, etc.
RELEASE_ASSERT(Logger::Registry::initialized(), "");
thread_handle_ = reinterpret_cast<HANDLE>(::_beginthreadex(
nullptr, 0,
[](void* arg) -> unsigned int {
static_cast<ThreadImplWin32*>(arg)->thread_routine_();
return 0;
},
this, 0, nullptr));
RELEASE_ASSERT(thread_handle_ != 0, "");
}

~ThreadImplWin32() { ::CloseHandle(thread_handle_); }

// Thread::Thread
void join() override {
const DWORD rc = ::WaitForSingleObject(thread_handle_, INFINITE);
RELEASE_ASSERT(rc == WAIT_OBJECT_0, "");
}

// Needed for WatcherImpl for the QueueUserAPC callback context
HANDLE handle() const { return thread_handle_; }

private:
std::function<void()> thread_routine_;
HANDLE thread_handle_;
};

ThreadPtr ThreadFactoryImplWin32::createThread(std::function<void()> thread_routine,
OptionsOptConstRef options) {
return std::make_unique<ThreadImplWin32>(thread_routine, name);
}

ThreadId ThreadFactoryImplWin32::currentThreadId() {
Expand Down
22 changes: 1 addition & 21 deletions source/common/common/win32/thread_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,13 @@
namespace Envoy {
namespace Thread {

/**
* Wrapper for a win32 thread. We don't use std::thread because it eats exceptions and leads to
* unusable stack traces.
*/
class ThreadImplWin32 : public Thread {
public:
ThreadImplWin32(std::function<void()> thread_routine);
~ThreadImplWin32();

// Thread::Thread
void join() override;

// Needed for WatcherImpl for the QueueUserAPC callback context
HANDLE handle() const { return thread_handle_; }

private:
std::function<void()> thread_routine_;
HANDLE thread_handle_;
};

/**
* Implementation of ThreadFactory
*/
class ThreadFactoryImplWin32 : public ThreadFactory {
public:
// Thread::ThreadFactory
ThreadPtr createThread(std::function<void()> thread_routine) override;
ThreadPtr createThread(std::function<void()> thread_routine, OptionsOptConstRef options) override;
ThreadId currentThreadId() override;
};

Expand Down
3 changes: 2 additions & 1 deletion source/common/filesystem/win32/watcher_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ WatcherImpl::WatcherImpl(Event::Dispatcher& dispatcher, Api::Api& api)
thread_exit_event_ = ::CreateEvent(nullptr, false, false, nullptr);
ASSERT(thread_exit_event_ != NULL);
keep_watching_ = true;
watch_thread_ = thread_factory_.createThread([this]() -> void { watchLoop(); });
Thread::Options options{absl::StrCat("watch:", dispatcher_->name())};
watch_thread_ = thread_factory_.createThread([this]() -> void { watchLoop(); }, options);
}

WatcherImpl::~WatcherImpl() {
Expand Down
3 changes: 2 additions & 1 deletion source/common/grpc/google_async_client_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ static constexpr int DefaultBufferLimitBytes = 1024 * 1024;
}

GoogleAsyncClientThreadLocal::GoogleAsyncClientThreadLocal(Api::Api& api)
: completion_thread_(api.threadFactory().createThread([this] { completionThread(); })) {}
: completion_thread_(api.threadFactory().createThread([this] { completionThread(); },
Thread::Options{"GoogleAsyncClient"})) {}
Comment thread
jmarantz marked this conversation as resolved.
Outdated

GoogleAsyncClientThreadLocal::~GoogleAsyncClientThreadLocal() {
// Force streams to shutdown and invoke TryCancel() to start the drain of
Expand Down
5 changes: 3 additions & 2 deletions source/server/worker_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,9 @@ void WorkerImpl::removeFilterChains(uint64_t listener_tag,

void WorkerImpl::start(GuardDog& guard_dog) {
ASSERT(!thread_);
thread_ =
api_.threadFactory().createThread([this, &guard_dog]() -> void { threadRoutine(guard_dog); });
Thread::Options options{absl::StrCat("worker:", dispatcher_->name())};
Comment thread
jmarantz marked this conversation as resolved.
Outdated
thread_ = api_.threadFactory().createThread(
[this, &guard_dog]() -> void { threadRoutine(guard_dog); }, options);
}

void WorkerImpl::initializeStats(Stats::Scope& scope) { dispatcher_->initializeStats(scope); }
Expand Down
Loading