Skip to content

Commit

Permalink
WIP src: begin support for shared_ptr
Browse files Browse the repository at this point in the history
Initially adding shared_ptr to ns_thread::create for test
implementation.
  • Loading branch information
trevnorris committed Feb 23, 2024
1 parent 744a3f4 commit 6e3a95e
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 0 deletions.
20 changes: 20 additions & 0 deletions include/nsuv-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1748,6 +1748,17 @@ int ns_thread::create(void (*cb)(ns_thread*, void*), std::nullptr_t) {
return create(cb, NSUV_CAST_NULLPTR);
}

template <typename D_T>
int ns_thread::create(ns_thread_cb_sp<D_T> cb, std::shared_ptr<D_T> data) {
thread_cb_ptr_ = reinterpret_cast<void (*)()>(cb);
thread_cb_sp_ = data;

return uv_thread_create(
&thread_,
&create_proxy_sp_<decltype(cb), D_T>,
this);
}

int ns_thread::create_ex(const uv_thread_options_t* params,
ns_thread_cb cb) {
thread_cb_ptr_ = reinterpret_cast<void (*)()>(cb);
Expand Down Expand Up @@ -1829,6 +1840,15 @@ void ns_thread::create_proxy_(void* arg) {
cb_(wrap, static_cast<D_T*>(wrap->thread_cb_data_));
}

template <typename CB_T, typename D_T>
void ns_thread::create_proxy_sp_(void* arg) {
auto* wrap = static_cast<ns_thread*>(arg);
auto* cb_ = reinterpret_cast<CB_T>(wrap->thread_cb_ptr_);
cb_(wrap, std::static_pointer_cast<D_T>(wrap->thread_cb_sp_));
// Make sure to not hang onto a reference of the shared_ptr.
wrap->thread_cb_sp_ = nullptr;
}

int util::addr_size(const struct sockaddr* addr) {
if (addr == nullptr) {
return 0;
Expand Down
8 changes: 8 additions & 0 deletions include/nsuv.h
Original file line number Diff line number Diff line change
Expand Up @@ -877,12 +877,17 @@ class ns_rwlock {
class ns_thread {
public:
NSUV_CB_FNS(ns_thread_cb, ns_thread*)
template <typename D_T>
using ns_thread_cb_sp = void(ns_thread*, std::shared_ptr<D_T>);

NSUV_INLINE NSUV_WUR int create(ns_thread_cb cb);
template <typename D_T>
NSUV_INLINE NSUV_WUR int create(ns_thread_cb_d<D_T> cb, D_T* data);
NSUV_INLINE NSUV_WUR int create(void (*cb)(ns_thread*, void*),
std::nullptr_t);
template <typename D_T>
NSUV_INLINE NSUV_WUR int create(ns_thread_cb_sp<D_T> cb,
std::shared_ptr<D_T> data);
NSUV_INLINE NSUV_WUR int create_ex(const uv_thread_options_t* params,
ns_thread_cb cb);
template <typename D_T>
Expand All @@ -904,10 +909,13 @@ class ns_thread {

private:
NSUV_PROXY_FNS(create_proxy_, void* arg)
template <typename CB_T, typename D_T>
static void create_proxy_sp_(void* arg);

uv_thread_t thread_;
void (*thread_cb_ptr_)() = nullptr;
void* thread_cb_data_ = nullptr;
std::shared_ptr<void> thread_cb_sp_ = { nullptr };
};

} // namespace nsuv
Expand Down
58 changes: 58 additions & 0 deletions test/test-thread.cc
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,32 @@ static void thread_entry(ns_thread* thread, size_t* arg) {
TEST_CASE("thread_create", "[thread]") {
ns_thread thread;
size_t arg[] = { 42 };
thread_called = 0;
ASSERT_EQ(0, thread.create(thread_entry, arg));
ASSERT_EQ(0, thread.join());
ASSERT_EQ(1, thread_called);
ASSERT(thread.equal(uv_thread_self()));
}


static void thread_entry_sp(ns_thread* thread, std::shared_ptr<size_t> arg) {
CHECK(!thread->equal(uv_thread_self()));
CHECK(*arg == 42);
thread_called++;
}


TEST_CASE("thread_create_sp", "[thread]") {
ns_thread thread;
std::shared_ptr<size_t> arg = std::make_shared<size_t>(42);
thread_called = 0;
ASSERT_EQ(0, thread.create(thread_entry_sp, arg));
ASSERT_EQ(0, thread.join());
ASSERT_EQ(1, thread_called);
ASSERT(thread.equal(uv_thread_self()));
}


static void tls_thread(ns_thread* arg) {
CHECK(nullptr == uv_key_get(&tls_key));
uv_key_set(&tls_key, arg);
Expand Down Expand Up @@ -200,6 +219,37 @@ static void thread_check_stack(ns_thread*, uv_thread_options_t* arg) {
}


static void thread_check_stack_sp(ns_thread*,
std::shared_ptr<uv_thread_options_t> arg) {
#if defined(__APPLE__)
size_t expected;
expected = arg == nullptr ? 0 :
(reinterpret_cast<uv_thread_options_t*>(arg.get()))->stack_size;
/* 512 kB is the default stack size of threads other than the main thread
* on MacOS. */
if (expected == 0)
expected = 512 * 1024;
CHECK(pthread_get_stacksize_np(pthread_self()) >= expected);
#elif defined(__linux__) && defined(__GLIBC__)
size_t expected;
struct rlimit lim;
size_t stack_size;
pthread_attr_t attr;
CHECK(0 == getrlimit(RLIMIT_STACK, &lim));
if (lim.rlim_cur == RLIM_INFINITY)
lim.rlim_cur = 2 << 20; /* glibc default. */
CHECK(0 == pthread_getattr_np(pthread_self(), &attr));
CHECK(0 == pthread_attr_getstacksize(&attr, &stack_size));
expected = arg == nullptr ? 0 :
(reinterpret_cast<uv_thread_options_t*>(arg.get()))->stack_size;
if (expected == 0)
expected = (size_t)lim.rlim_cur;
CHECK(stack_size >= expected);
CHECK(0 == pthread_attr_destroy(&attr));
#endif
}


TEST_CASE("thread_stack_size", "[thread]") {
ns_thread thread;
uv_thread_options_t* arg = nullptr;
Expand All @@ -208,6 +258,14 @@ TEST_CASE("thread_stack_size", "[thread]") {
}


TEST_CASE("thread_stack_size_sp", "[thread]") {
ns_thread thread;
std::shared_ptr<uv_thread_options_t> arg = { nullptr };
ASSERT_EQ(0, thread.create(thread_check_stack_sp, arg));
ASSERT_EQ(0, thread.join());
}


TEST_CASE("thread_stack_size_explicit", "[thread]") {
ns_thread thread;
uv_thread_options_t options;
Expand Down

0 comments on commit 6e3a95e

Please sign in to comment.