Skip to content

Commit 5fe1a06

Browse files
committed
Bugfix: Signal Trace mode may send SIGURG to wrong thread (#3038)
* Bugfix: Use `pthread_sigqueue` to send the signal to correct worker thread' * Change the type of `TaskGroup::_tid` to `pthread_t`
1 parent e0d1270 commit 5fe1a06

6 files changed

Lines changed: 36 additions & 30 deletions

File tree

src/bthread/task_control.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
// Date: Tue Jul 10 17:40:58 CST 2012
2121

22+
#include <pthread.h>
2223
#include <sys/syscall.h> // SYS_gettid
2324
#include "butil/scoped_lock.h" // BAIDU_SCOPED_LOCK
2425
#include "butil/errno.h" // berror
@@ -90,7 +91,7 @@ void* TaskControl::worker_thread(void* arg) {
9091
return NULL;
9192
}
9293

93-
g->_tid = syscall(SYS_gettid);
94+
g->_tid = pthread_self();
9495

9596
std::string worker_thread_name = butil::string_printf(
9697
"brpc_wkr:%d-%d", g->tag(),

src/bthread/task_group.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1107,7 +1107,7 @@ void print_task(std::ostream& os, bthread_t tid) {
11071107
TaskStatistics stat = {0, 0, 0};
11081108
TaskStatus status = TASK_STATUS_UNKNOWN;
11091109
bool traced = false;
1110-
pid_t worker_tid = 0;
1110+
pthread_t worker_tid{};
11111111
{
11121112
BAIDU_SCOPED_LOCK(m->version_lock);
11131113
if (given_ver == *m->version_butex) {

src/bthread/task_group.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ class TaskGroup {
219219

220220
bthread_tag_t tag() const { return _tag; }
221221

222-
pid_t tid() const { return _tid; }
222+
pthread_t tid() const { return _tid; }
223223

224224
int64_t current_task_cpu_clock_ns() {
225225
if (_last_cpu_clock_ns == 0) {
@@ -378,7 +378,7 @@ friend class TaskControl;
378378
bthread_tag_t _tag{BTHREAD_TAG_DEFAULT};
379379

380380
// Worker thread id.
381-
pid_t _tid{-1};
381+
pthread_t _tid{};
382382
};
383383

384384
} // namespace bthread

src/bthread/task_meta.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ struct TaskMeta {
113113
// Whether bthread is traced?
114114
bool traced{false};
115115
// Worker thread id.
116-
pid_t worker_tid{-1};
116+
pthread_t worker_tid{};
117117

118118
public:
119119
// Only initialize [Not Reset] fields, other fields will be reset in

src/bthread/task_tracer.cpp

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,18 @@
1818
#ifdef BRPC_BTHREAD_TRACER
1919

2020
#include "bthread/task_tracer.h"
21-
#include <unistd.h>
22-
#include <poll.h>
23-
#include <gflags/gflags.h>
24-
#include <absl/debugging/stacktrace.h>
25-
#include <absl/debugging/symbolize.h>
26-
#include "butil/debug/stack_trace.h"
21+
#include "bthread/processor.h"
22+
#include "bthread/task_group.h"
23+
#include "butil/fd_utility.h"
2724
#include "butil/memory/scope_guard.h"
2825
#include "butil/reloadable_flags.h"
29-
#include "butil/fd_utility.h"
30-
#include "bthread/task_group.h"
31-
#include "bthread/processor.h"
26+
#include <absl/debugging/stacktrace.h>
27+
#include <absl/debugging/symbolize.h>
28+
#include <csignal>
29+
#include <gflags/gflags.h>
30+
#include <poll.h>
31+
#include <pthread.h>
32+
#include <unistd.h>
3233

3334
namespace bthread {
3435

@@ -151,7 +152,7 @@ void TaskTracer::set_status(TaskStatus s, TaskMeta* m) {
151152
m->status = s;
152153
}
153154
if (TASK_STATUS_CREATED == s) {
154-
m->worker_tid = -1;
155+
m->worker_tid = pthread_t{};
155156
}
156157
}
157158

@@ -161,7 +162,7 @@ void TaskTracer::set_status(TaskStatus s, TaskMeta* m) {
161162
}
162163
}
163164

164-
void TaskTracer::set_running_status(pid_t worker_tid, TaskMeta* m) {
165+
void TaskTracer::set_running_status(pthread_t worker_tid, TaskMeta* m) {
165166
BAIDU_SCOPED_LOCK(m->version_lock);
166167
m->worker_tid = worker_tid;
167168
m->status = TASK_STATUS_RUNNING;
@@ -230,7 +231,7 @@ TaskTracer::Result TaskTracer::TraceImpl(bthread_t tid) {
230231

231232
BAIDU_SCOPED_LOCK(_mutex);
232233
TaskStatus status;
233-
pid_t worker_tid;
234+
pthread_t worker_tid;
234235
const uint32_t given_version = get_version(tid);
235236
{
236237
BAIDU_SCOPED_LOCK(m->version_lock);
@@ -368,7 +369,7 @@ void TaskTracer::SignalHandler(int, siginfo_t* info, void* context) {
368369
butil::ignore_result(write(signal_sync->pipe_fds[1], "1", 1));
369370
}
370371

371-
TaskTracer::Result TaskTracer::SignalTrace(pid_t tid) {
372+
TaskTracer::Result TaskTracer::SignalTrace(pthread_t worker_tid) {
372373
// CAUTION:
373374
// https://github.com/gperftools/gperftools/wiki/gperftools'-stacktrace-capturing-methods-and-their-issues#libunwind
374375
// Generally, libunwind promises async-signal-safety for capturing backtraces.
@@ -403,6 +404,10 @@ TaskTracer::Result TaskTracer::SignalTrace(pid_t tid) {
403404
//
404405
// Therefore, use async-signal-safe absl::DefaultStackUnwinder instead of libunwind.
405406

407+
if (pthread_equal(worker_tid, pthread_self())) {
408+
return Result::MakeErrorResult("Forbid to trace self");
409+
}
410+
406411
// Remove unused SignalSyncs.
407412
auto iter = std::remove_if(
408413
_inuse_signal_syncs.begin(), _inuse_signal_syncs.end(),
@@ -424,11 +429,11 @@ TaskTracer::Result TaskTracer::SignalTrace(pid_t tid) {
424429
sigval value{};
425430
value.sival_ptr = signal_sync.get();
426431
size_t sigqueue_try = 0;
427-
while (sigqueue(tid, SIGURG, value) != 0) {
432+
while (pthread_sigqueue(worker_tid, SIGURG, value) != 0) {
428433
if (errno != EAGAIN || sigqueue_try++ >= 3) {
429434
// Remove reference for SignalHandler.
430435
signal_sync->RemoveRefManually();
431-
return Result::MakeErrorResult("Fail to sigqueue: %s, tid: %d", berror(), tid);
436+
return Result::MakeErrorResult("Fail to pthread_sigqueue: %s", berror());
432437
}
433438
}
434439
_inuse_signal_syncs.push_back(signal_sync);

src/bthread/task_tracer.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@
2020

2121
#ifdef BRPC_BTHREAD_TRACER
2222

23-
#include <signal.h>
24-
#include <vector>
25-
#include <libunwind.h>
26-
#include "butil/synchronization/condition_variable.h"
23+
#include "bthread/mutex.h"
24+
#include "bthread/task_meta.h"
2725
#include "butil/intrusive_ptr.hpp"
28-
#include "butil/strings/safe_sprintf.h"
2926
#include "butil/shared_object.h"
30-
#include "bthread/task_meta.h"
31-
#include "bthread/mutex.h"
27+
#include "butil/strings/safe_sprintf.h"
28+
#include "butil/synchronization/condition_variable.h"
29+
#include <libunwind.h>
30+
#include <signal.h>
31+
#include <vector>
3232

3333
namespace bthread {
3434

@@ -39,10 +39,10 @@ class TaskTracer {
3939
bool Init();
4040
// Set the status to `s'.
4141
void set_status(TaskStatus s, TaskMeta* meta);
42-
static void set_running_status(pid_t worker_tid, TaskMeta* meta);
42+
static void set_running_status(pthread_t worker_tid, TaskMeta* meta);
4343
static bool set_end_status_unsafe(TaskMeta* m);
4444

45-
// Trace the bthread of `tid'.
45+
// Trace the bthread of `tid`.
4646
std::string Trace(bthread_t tid);
4747
void Trace(std::ostream& os, bthread_t tid);
4848

@@ -103,7 +103,7 @@ class TaskTracer {
103103

104104
static bool RegisterSignalHandler();
105105
static void SignalHandler(int sig, siginfo_t* info, void* context);
106-
Result SignalTrace(pid_t worker_tid);
106+
Result SignalTrace(pthread_t worker_tid);
107107

108108
// Make sure only one bthread is traced at a time.
109109
Mutex _trace_request_mutex;

0 commit comments

Comments
 (0)