Skip to content

Commit 456f748

Browse files
committed
Revert "Merge pull request grpc#18146 from grpc/revert-17308-shutdown"
This reverts commit 9079e98, reversing changes made to 76a38bf.
1 parent c9aebe3 commit 456f748

39 files changed

+344
-183
lines changed

grpc.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ EXPORTS
1616
grpc_init
1717
grpc_shutdown
1818
grpc_is_initialized
19+
grpc_shutdown_blocking
1920
grpc_version_string
2021
grpc_g_stands_for
2122
grpc_completion_queue_factory_lookup

include/grpc/grpc.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,11 @@ GRPCAPI void grpc_init(void);
7373
Before it's called, there should haven been a matching invocation to
7474
grpc_init().
7575
76-
No memory is used by grpc after this call returns, nor are any instructions
77-
executing within the grpc library.
78-
Prior to calling, all application owned grpc objects must have been
79-
destroyed. */
76+
The last call to grpc_shutdown will initiate cleaning up of grpc library
77+
internals, which can happen in another thread. Once the clean-up is done,
78+
no memory is used by grpc, nor are any instructions executing within the
79+
grpc library. Prior to calling, all application owned grpc objects must
80+
have been destroyed. */
8081
GRPCAPI void grpc_shutdown(void);
8182

8283
/** EXPERIMENTAL. Returns 1 if the grpc library has been initialized.
@@ -85,6 +86,10 @@ GRPCAPI void grpc_shutdown(void);
8586
https://github.com/grpc/grpc/issues/15334 */
8687
GRPCAPI int grpc_is_initialized(void);
8788

89+
/** EXPERIMENTAL. Blocking shut down grpc library.
90+
This is only for wrapped language to use now. */
91+
GRPCAPI void grpc_shutdown_blocking(void);
92+
8893
/** Return a string representing the current version of grpc */
8994
GRPCAPI const char* grpc_version_string(void);
9095

src/core/lib/debug/trace.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ void grpc_tracer_enable_flag(grpc_core::TraceFlag* flag);
5353
class TraceFlag {
5454
public:
5555
TraceFlag(bool default_enabled, const char* name);
56-
// This needs to be trivially destructible as it is used as global variable.
56+
// TraceFlag needs to be trivially destructible since it is used as global
57+
// variable.
5758
~TraceFlag() = default;
5859

5960
const char* name() const { return name_; }

src/core/lib/gprpp/thd.h

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,27 @@ class ThreadInternalsInterface {
4747

4848
class Thread {
4949
public:
50+
class Options {
51+
public:
52+
Options() : joinable_(true), tracked_(true) {}
53+
/// Set whether the thread is joinable or detached.
54+
Options& set_joinable(bool joinable) {
55+
joinable_ = joinable;
56+
return *this;
57+
}
58+
bool joinable() const { return joinable_; }
59+
60+
/// Set whether the thread is tracked for fork support.
61+
Options& set_tracked(bool tracked) {
62+
tracked_ = tracked;
63+
return *this;
64+
}
65+
bool tracked() const { return tracked_; }
66+
67+
private:
68+
bool joinable_;
69+
bool tracked_;
70+
};
5071
/// Default constructor only to allow use in structs that lack constructors
5172
/// Does not produce a validly-constructed thread; must later
5273
/// use placement new to construct a real thread. Does not init mu_ and cv_
@@ -57,14 +78,17 @@ class Thread {
5778
/// with argument \a arg once it is started.
5879
/// The optional \a success argument indicates whether the thread
5980
/// is successfully created.
81+
/// The optional \a options can be used to set the thread detachable.
6082
Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg,
61-
bool* success = nullptr);
83+
bool* success = nullptr, const Options& options = Options());
6284

6385
/// Move constructor for thread. After this is called, the other thread
6486
/// no longer represents a living thread object
65-
Thread(Thread&& other) : state_(other.state_), impl_(other.impl_) {
87+
Thread(Thread&& other)
88+
: state_(other.state_), impl_(other.impl_), options_(other.options_) {
6689
other.state_ = MOVED;
6790
other.impl_ = nullptr;
91+
other.options_ = Options();
6892
}
6993

7094
/// Move assignment operator for thread. After this is called, the other
@@ -79,8 +103,10 @@ class Thread {
79103
// assert it for the time being.
80104
state_ = other.state_;
81105
impl_ = other.impl_;
106+
options_ = other.options_;
82107
other.state_ = MOVED;
83108
other.impl_ = nullptr;
109+
other.options_ = Options();
84110
}
85111
return *this;
86112
}
@@ -95,11 +121,16 @@ class Thread {
95121
GPR_ASSERT(state_ == ALIVE);
96122
state_ = STARTED;
97123
impl_->Start();
124+
if (!options_.joinable()) {
125+
state_ = DONE;
126+
impl_ = nullptr;
127+
}
98128
} else {
99129
GPR_ASSERT(state_ == FAILED);
100130
}
101-
};
131+
}
102132

133+
// It is only legal to call Join if the Thread is created as joinable.
103134
void Join() {
104135
if (impl_ != nullptr) {
105136
impl_->Join();
@@ -119,12 +150,13 @@ class Thread {
119150
/// FAKE -- just a dummy placeholder Thread created by the default constructor
120151
/// ALIVE -- an actual thread of control exists associated with this thread
121152
/// STARTED -- the thread of control has been started
122-
/// DONE -- the thread of control has completed and been joined
153+
/// DONE -- the thread of control has completed and been joined/detached
123154
/// FAILED -- the thread of control never came alive
124155
/// MOVED -- contents were moved out and we're no longer tracking them
125156
enum ThreadState { FAKE, ALIVE, STARTED, DONE, FAILED, MOVED };
126157
ThreadState state_;
127158
internal::ThreadInternalsInterface* impl_;
159+
Options options_;
128160
};
129161

130162
} // namespace grpc_core

src/core/lib/gprpp/thd_posix.cc

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,14 @@ struct thd_arg {
4444
void (*body)(void* arg); /* body of a thread */
4545
void* arg; /* argument to a thread */
4646
const char* name; /* name of thread. Can be nullptr. */
47+
bool joinable;
48+
bool tracked;
4749
};
4850

49-
class ThreadInternalsPosix
50-
: public grpc_core::internal::ThreadInternalsInterface {
51+
class ThreadInternalsPosix : public internal::ThreadInternalsInterface {
5152
public:
5253
ThreadInternalsPosix(const char* thd_name, void (*thd_body)(void* arg),
53-
void* arg, bool* success)
54+
void* arg, bool* success, const Thread::Options& options)
5455
: started_(false) {
5556
gpr_mu_init(&mu_);
5657
gpr_cv_init(&ready_);
@@ -63,11 +64,20 @@ class ThreadInternalsPosix
6364
info->body = thd_body;
6465
info->arg = arg;
6566
info->name = thd_name;
66-
grpc_core::Fork::IncThreadCount();
67+
info->joinable = options.joinable();
68+
info->tracked = options.tracked();
69+
if (options.tracked()) {
70+
Fork::IncThreadCount();
71+
}
6772

6873
GPR_ASSERT(pthread_attr_init(&attr) == 0);
69-
GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) ==
70-
0);
74+
if (options.joinable()) {
75+
GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) ==
76+
0);
77+
} else {
78+
GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) ==
79+
0);
80+
}
7181

7282
*success =
7383
(pthread_create(&pthread_id_, &attr,
@@ -97,8 +107,14 @@ class ThreadInternalsPosix
97107
}
98108
gpr_mu_unlock(&arg.thread->mu_);
99109

110+
if (!arg.joinable) {
111+
Delete(arg.thread);
112+
}
113+
100114
(*arg.body)(arg.arg);
101-
grpc_core::Fork::DecThreadCount();
115+
if (arg.tracked) {
116+
Fork::DecThreadCount();
117+
}
102118
return nullptr;
103119
},
104120
info) == 0);
@@ -108,9 +124,11 @@ class ThreadInternalsPosix
108124
if (!(*success)) {
109125
/* don't use gpr_free, as this was allocated using malloc (see above) */
110126
free(info);
111-
grpc_core::Fork::DecThreadCount();
127+
if (options.tracked()) {
128+
Fork::DecThreadCount();
129+
}
112130
}
113-
};
131+
}
114132

115133
~ThreadInternalsPosix() override {
116134
gpr_mu_destroy(&mu_);
@@ -136,15 +154,15 @@ class ThreadInternalsPosix
136154
} // namespace
137155

138156
Thread::Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg,
139-
bool* success) {
157+
bool* success, const Options& options)
158+
: options_(options) {
140159
bool outcome = false;
141-
impl_ =
142-
grpc_core::New<ThreadInternalsPosix>(thd_name, thd_body, arg, &outcome);
160+
impl_ = New<ThreadInternalsPosix>(thd_name, thd_body, arg, &outcome, options);
143161
if (outcome) {
144162
state_ = ALIVE;
145163
} else {
146164
state_ = FAILED;
147-
grpc_core::Delete(impl_);
165+
Delete(impl_);
148166
impl_ = nullptr;
149167
}
150168

src/core/lib/gprpp/thd_windows.cc

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,16 @@ struct thd_info {
4646
void (*body)(void* arg); /* body of a thread */
4747
void* arg; /* argument to a thread */
4848
HANDLE join_event; /* the join event */
49+
bool joinable; /* whether it is joinable */
4950
};
5051

5152
thread_local struct thd_info* g_thd_info;
5253

5354
class ThreadInternalsWindows
5455
: public grpc_core::internal::ThreadInternalsInterface {
5556
public:
56-
ThreadInternalsWindows(void (*thd_body)(void* arg), void* arg, bool* success)
57+
ThreadInternalsWindows(void (*thd_body)(void* arg), void* arg, bool* success,
58+
const grpc_core::Thread::Options& options)
5759
: started_(false) {
5860
gpr_mu_init(&mu_);
5961
gpr_cv_init(&ready_);
@@ -63,21 +65,24 @@ class ThreadInternalsWindows
6365
info_->thread = this;
6466
info_->body = thd_body;
6567
info_->arg = arg;
66-
67-
info_->join_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
68-
if (info_->join_event == nullptr) {
69-
gpr_free(info_);
70-
*success = false;
71-
} else {
72-
handle = CreateThread(nullptr, 64 * 1024, thread_body, info_, 0, nullptr);
73-
if (handle == nullptr) {
74-
destroy_thread();
68+
info_->join_event = nullptr;
69+
info_->joinable = options.joinable();
70+
if (info_->joinable) {
71+
info_->join_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
72+
if (info_->join_event == nullptr) {
73+
gpr_free(info_);
7574
*success = false;
76-
} else {
77-
CloseHandle(handle);
78-
*success = true;
75+
return;
7976
}
8077
}
78+
handle = CreateThread(nullptr, 64 * 1024, thread_body, info_, 0, nullptr);
79+
if (handle == nullptr) {
80+
destroy_thread();
81+
*success = false;
82+
} else {
83+
CloseHandle(handle);
84+
*success = true;
85+
}
8186
}
8287

8388
~ThreadInternalsWindows() override {
@@ -107,14 +112,24 @@ class ThreadInternalsWindows
107112
gpr_inf_future(GPR_CLOCK_MONOTONIC));
108113
}
109114
gpr_mu_unlock(&g_thd_info->thread->mu_);
115+
if (!g_thd_info->joinable) {
116+
grpc_core::Delete(g_thd_info->thread);
117+
g_thd_info->thread = nullptr;
118+
}
110119
g_thd_info->body(g_thd_info->arg);
111-
BOOL ret = SetEvent(g_thd_info->join_event);
112-
GPR_ASSERT(ret);
120+
if (g_thd_info->joinable) {
121+
BOOL ret = SetEvent(g_thd_info->join_event);
122+
GPR_ASSERT(ret);
123+
} else {
124+
gpr_free(g_thd_info);
125+
}
113126
return 0;
114127
}
115128

116129
void destroy_thread() {
117-
CloseHandle(info_->join_event);
130+
if (info_ != nullptr && info_->joinable) {
131+
CloseHandle(info_->join_event);
132+
}
118133
gpr_free(info_);
119134
}
120135

@@ -129,14 +144,15 @@ class ThreadInternalsWindows
129144
namespace grpc_core {
130145

131146
Thread::Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg,
132-
bool* success) {
147+
bool* success, const Options& options)
148+
: options_(options) {
133149
bool outcome = false;
134-
impl_ = grpc_core::New<ThreadInternalsWindows>(thd_body, arg, &outcome);
150+
impl_ = New<ThreadInternalsWindows>(thd_body, arg, &outcome, options);
135151
if (outcome) {
136152
state_ = ALIVE;
137153
} else {
138154
state_ = FAILED;
139-
grpc_core::Delete(impl_);
155+
Delete(impl_);
140156
impl_ = nullptr;
141157
}
142158

0 commit comments

Comments
 (0)