Coverage Report

Created: 2024-11-22 21:49

/root/doris/be/src/util/thread.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
// This file is copied from
18
// https://github.com/apache/impala/blob/branch-2.9.0/be/src/util/thread.h
19
// and modified by Doris
20
21
#pragma once
22
#include <butil/macros.h>
23
#include <pthread.h>
24
#include <stdint.h>
25
26
#include <functional>
27
#include <string>
28
#include <utility>
29
30
#include "common/status.h"
31
#include "gutil/ref_counted.h"
32
#include "util/countdown_latch.h"
33
34
namespace doris {
35
class WebPageHandler;
36
37
class Thread : public RefCountedThreadSafe<Thread> {
38
public:
39
    enum CreateFlags { NO_FLAGS = 0, NO_STACK_WATCHDOG = 1 };
40
41
    template <class F>
42
    static Status create_with_flags(const std::string& category, const std::string& name,
43
                                    const F& f, uint64_t flags, scoped_refptr<Thread>* holder) {
44
        return start_thread(category, name, f, flags, holder);
45
    }
46
47
    template <class F>
48
    static Status create(const std::string& category, const std::string& name, const F& f,
49
28
                         scoped_refptr<Thread>* holder) {
50
28
        return start_thread(category, name, f, NO_FLAGS, holder);
51
28
    }
_ZN5doris6Thread6createIFvvEEENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESB_RKT_P13scoped_refptrIS0_E
Line
Count
Source
49
1
                         scoped_refptr<Thread>* holder) {
50
1
        return start_thread(category, name, f, NO_FLAGS, holder);
51
1
    }
task_worker_pool.cpp:_ZN5doris6Thread6createIZNS_19PriorTaskWorkerPoolC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEiiSt8functionIFvRKNS_17TAgentTaskRequestEEEE3$_0EENS_6StatusESA_SA_RKT_P13scoped_refptrIS0_E
Line
Count
Source
49
1
                         scoped_refptr<Thread>* holder) {
50
1
        return start_thread(category, name, f, NO_FLAGS, holder);
51
1
    }
task_worker_pool.cpp:_ZN5doris6Thread6createIZNS_19PriorTaskWorkerPoolC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEiiSt8functionIFvRKNS_17TAgentTaskRequestEEEE3$_1EENS_6StatusESA_SA_RKT_P13scoped_refptrIS0_E
Line
Count
Source
49
1
                         scoped_refptr<Thread>* holder) {
50
1
        return start_thread(category, name, f, NO_FLAGS, holder);
51
1
    }
task_worker_pool.cpp:_ZN5doris6Thread6createIZNS_12ReportWorkerC1ENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPKNS_11ClusterInfoEiSt8functionIFvvEEE3$_0EENS_6StatusERKS8_SI_RKT_P13scoped_refptrIS0_E
Line
Count
Source
49
1
                         scoped_refptr<Thread>* holder) {
50
1
        return start_thread(category, name, f, NO_FLAGS, holder);
51
1
    }
Unexecuted instantiation: olap_server.cpp:_ZN5doris6Thread6createIZNS_13StorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE3$_0EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: olap_server.cpp:_ZN5doris6Thread6createIZNS_13StorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE3$_1EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: olap_server.cpp:_ZN5doris6Thread6createIZNS_13StorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE3$_2EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: olap_server.cpp:_ZN5doris6Thread6createIZNS_13StorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE3$_3EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: olap_server.cpp:_ZN5doris6Thread6createIZNS_13StorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE3$_4EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: olap_server.cpp:_ZN5doris6Thread6createIZNS_13StorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE3$_5EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: olap_server.cpp:_ZN5doris6Thread6createIZNS_13StorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE3$_6EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: olap_server.cpp:_ZN5doris6Thread6createIZNS_13StorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE3$_7EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: olap_server.cpp:_ZN5doris6Thread6createIZNS_13StorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE3$_8EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: olap_server.cpp:_ZN5doris6Thread6createIZNS_13StorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE3$_9EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: olap_server.cpp:_ZN5doris6Thread6createIZNS_13StorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE4$_10EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: olap_server.cpp:_ZN5doris6Thread6createIZNS_13StorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE4$_11EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: olap_server.cpp:_ZN5doris6Thread6createIZNS_13StorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE4$_12EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
wal_manager.cpp:_ZN5doris6Thread6createIZNS_10WalManager4initEvE3$_0EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESC_RKT_P13scoped_refptrIS0_E
Line
Count
Source
49
1
                         scoped_refptr<Thread>* holder) {
50
1
        return start_thread(category, name, f, NO_FLAGS, holder);
51
1
    }
wal_manager.cpp:_ZN5doris6Thread6createIZNS_10WalManager19_init_wal_dirs_infoEvE3$_0EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESC_RKT_P13scoped_refptrIS0_E
Line
Count
Source
49
14
                         scoped_refptr<Thread>* holder) {
50
14
        return start_thread(category, name, f, NO_FLAGS, holder);
51
14
    }
Unexecuted instantiation: broker_mgr.cpp:_ZN5doris6Thread6createIZNS_9BrokerMgrC1EPNS_7ExecEnvEE3$_0EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_RKT_P13scoped_refptrIS0_E
external_scan_context_mgr.cpp:_ZN5doris6Thread6createIZNS_22ExternalScanContextMgrC1EPNS_7ExecEnvEE3$_0EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_RKT_P13scoped_refptrIS0_E
Line
Count
Source
49
4
                         scoped_refptr<Thread>* holder) {
50
4
        return start_thread(category, name, f, NO_FLAGS, holder);
51
4
    }
fragment_mgr.cpp:_ZN5doris6Thread6createIZNS_11FragmentMgrC1EPNS_7ExecEnvEE3$_0EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_RKT_P13scoped_refptrIS0_E
Line
Count
Source
49
4
                         scoped_refptr<Thread>* holder) {
50
4
        return start_thread(category, name, f, NO_FLAGS, holder);
51
4
    }
Unexecuted instantiation: load_channel_mgr.cpp:_ZN5doris6Thread6createIZNS_14LoadChannelMgr16_start_bg_workerEvE3$_0EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESC_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: load_path_mgr.cpp:_ZN5doris6Thread6createIZNS_11LoadPathMgr4initEvE3$_0EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESC_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: result_buffer_mgr.cpp:_ZN5doris6Thread6createIZNS_15ResultBufferMgr4initEvE3$_0EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESC_RKT_P13scoped_refptrIS0_E
data_consumer_pool.cpp:_ZN5doris6Thread6createIZNS_16DataConsumerPool15start_bg_workerEvE3$_0EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESC_RKT_P13scoped_refptrIS0_E
Line
Count
Source
49
1
                         scoped_refptr<Thread>* holder) {
50
1
        return start_thread(category, name, f, NO_FLAGS, holder);
51
1
    }
Unexecuted instantiation: workload_sched_policy_mgr.cpp:_ZN5doris6Thread6createIZNS_22WorkloadSchedPolicyMgr5startEPNS_7ExecEnvEE3$_0EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: spill_stream_manager.cpp:_ZN5doris6Thread6createIZNS_10vectorized18SpillStreamManager4initEvE3$_0EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESD_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: cloud_storage_engine.cpp:_ZN5doris6Thread6createIZNS_18CloudStorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE3$_0EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: cloud_storage_engine.cpp:_ZN5doris6Thread6createIZNS_18CloudStorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE3$_1EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: cloud_storage_engine.cpp:_ZN5doris6Thread6createIZNS_18CloudStorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE3$_2EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: cloud_storage_engine.cpp:_ZN5doris6Thread6createIZNS_18CloudStorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE3$_3EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: cloud_storage_engine.cpp:_ZN5doris6Thread6createIZNS_18CloudStorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE3$_4EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: cloud_storage_engine.cpp:_ZN5doris6Thread6createIZNS_18CloudStorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE3$_5EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: cloud_storage_engine.cpp:_ZN5doris6Thread6createIZNS_18CloudStorageEngine16start_bg_threadsESt10shared_ptrINS_13WorkloadGroupEEE3$_6EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_P13scoped_refptrIS0_E
Unexecuted instantiation: cloud_txn_delete_bitmap_cache.cpp:_ZN5doris6Thread6createIZNS_25CloudTxnDeleteBitmapCache4initEvE3$_0EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESC_RKT_P13scoped_refptrIS0_E
52
53
    template <class F, class A1>
54
    static Status create(const std::string& category, const std::string& name, const F& f,
55
2.41k
                         const A1& a1, scoped_refptr<Thread>* holder) {
56
2.41k
        return start_thread(category, name, std::bind(f, a1), NO_FLAGS, holder);
57
2.41k
    }
_ZN5doris6Thread6createIMNS_14CountDownLatchEFvvEPS2_EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_RKT_RKT0_P13scoped_refptrIS0_E
Line
Count
Source
55
1
                         const A1& a1, scoped_refptr<Thread>* holder) {
56
1
        return start_thread(category, name, std::bind(f, a1), NO_FLAGS, holder);
57
1
    }
_ZN5doris6Thread6createIFvlEiEENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESB_RKT_RKT0_P13scoped_refptrIS0_E
Line
Count
Source
55
1.00k
                         const A1& a1, scoped_refptr<Thread>* holder) {
56
1.00k
        return start_thread(category, name, std::bind(f, a1), NO_FLAGS, holder);
57
1.00k
    }
Unexecuted instantiation: _ZN5doris6Thread6createIMNS_2io15FileHandleCacheEFvvEPS3_EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_RKT_RKT0_P13scoped_refptrIS0_E
_ZN5doris6Thread6createIMNS_10ThreadPoolEFvvEPS2_EENS_6StatusERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_RKT_RKT0_P13scoped_refptrIS0_E
Line
Count
Source
55
1.40k
                         const A1& a1, scoped_refptr<Thread>* holder) {
56
1.40k
        return start_thread(category, name, std::bind(f, a1), NO_FLAGS, holder);
57
1.40k
    }
58
59
    template <class F, class A1, class A2>
60
    static Status create(const std::string& category, const std::string& name, const F& f,
61
                         const A1& a1, const A2& a2, scoped_refptr<Thread>* holder) {
62
        return start_thread(category, name, std::bind(f, a1, a2), NO_FLAGS, holder);
63
    }
64
65
    template <class F, class A1, class A2, class A3>
66
    static Status create(const std::string& category, const std::string& name, const F& f,
67
                         const A1& a1, const A2& a2, const A3& a3, scoped_refptr<Thread>* holder) {
68
        return start_thread(category, name, std::bind(f, a1, a2, a3), NO_FLAGS, holder);
69
    }
70
71
    template <class F, class A1, class A2, class A3, class A4>
72
    static Status create(const std::string& category, const std::string& name, const F& f,
73
                         const A1& a1, const A2& a2, const A3& a3, const A4& a4,
74
                         scoped_refptr<Thread>* holder) {
75
        return start_thread(category, name, std::bind(f, a1, a2, a3, a4), NO_FLAGS, holder);
76
    }
77
78
    template <class F, class A1, class A2, class A3, class A4, class A5>
79
    static Status create(const std::string& category, const std::string& name, const F& f,
80
                         const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5,
81
                         scoped_refptr<Thread>* holder) {
82
        return start_thread(category, name, std::bind(f, a1, a2, a3, a4, a5), NO_FLAGS, holder);
83
    }
84
85
    template <class F, class A1, class A2, class A3, class A4, class A5, class A6>
86
    static Status create(const std::string& category, const std::string& name, const F& f,
87
                         const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5,
88
                         const A6& a6, scoped_refptr<Thread>* holder) {
89
        return start_thread(category, name, std::bind(f, a1, a2, a3, a4, a5, a6), NO_FLAGS, holder);
90
    }
91
92
    static void set_self_name(const std::string& name);
93
94
#ifndef __APPLE__
95
    static void set_idle_sched();
96
97
    static void set_thread_nice_value();
98
#endif
99
100
    ~Thread();
101
102
    // Blocks until this thread finishes execution. Once this method returns, the thread
103
    // will be unregistered with the ThreadMgr and will not appear in the debug UI.
104
    void join();
105
106
    // The thread ID assigned to this thread by the operating system. If the thread
107
    // has not yet started running, returns INVALID_TID.
108
    //
109
    // NOTE: this may block for a short amount of time if the thread has just been
110
    // started.
111
    int64_t tid() const;
112
113
    // Returns the thread's pthread ID.
114
    pthread_t pthread_id() const;
115
116
    const std::string& name() const;
117
    const std::string& category() const;
118
    std::string to_string() const;
119
120
    // The current thread of execution, or nullptr if the current thread isn't a doris::Thread.
121
    // This call is signal-safe.
122
    static Thread* current_thread();
123
124
    // Returns a unique, stable identifier for this thread. Note that this is a static
125
    // method and thus can be used on any thread, including the main thread of the
126
    // process.
127
    //
128
    // In general, this should be used when a value is required that is unique to
129
    // a thread and must work on any thread including the main process thread.
130
    //
131
    // NOTE: this is _not_ the TID, but rather a unique value assigned by the
132
    // thread implementation. So, this value should not be presented to the user
133
    // in log messages, etc.
134
    static int64_t unique_thread_id();
135
136
    // Returns the system thread ID (tid on Linux) for the current thread. Note
137
    // that this is a static method and thus can be used from any thread,
138
    // including the main thread of the process. This is in contrast to
139
    // Thread::tid(), which only works on doris::Threads.
140
    //
141
    // Thread::tid() will return the same value, but the value is cached in the
142
    // Thread object, so will be faster to call.
143
    //
144
    // Thread::unique_thread_id() (or Thread::tid()) should be preferred for
145
    // performance sensitive code, however it is only guaranteed to return a
146
    // unique and stable thread ID, not necessarily the system thread ID.
147
    static int64_t current_thread_id();
148
149
private:
150
    friend class ThreadJoiner;
151
152
    enum {
153
        INVALID_TID = -1,
154
        PARENT_WAITING_TID = -2,
155
    };
156
157
    // User function to be executed by this thread.
158
    typedef std::function<void()> ThreadFunctor;
159
    Thread(const std::string& category, const std::string& name, ThreadFunctor functor)
160
            : _thread(0),
161
              _tid(INVALID_TID),
162
              _functor(std::move(functor)),
163
              _category(std::move(category)),
164
              _name(std::move(name)),
165
              _done(1),
166
2.43k
              _joinable(false) {}
167
168
    // Library-specific thread ID.
169
    pthread_t _thread;
170
171
    // OS-specific thread ID. Once the constructor finishes start_thread(),
172
    // guaranteed to be set either to a non-negative integer, or to INVALID_TID.
173
    //
174
    // The tid_ member goes through the following states:
175
    // 1. INVALID_TID: the thread has not been started, or has already exited.
176
    // 2. PARENT_WAITING_TID: the parent has started the thread, but the
177
    //    thread has not yet begun running. Therefore the TID is not yet known
178
    //    but it will be set once the thread starts.
179
    // 3. <positive value>: the thread is running.
180
    int64_t _tid;
181
182
    const ThreadFunctor _functor;
183
184
    const std::string _category;
185
    const std::string _name;
186
187
    // Joiners wait on this latch to be notified if the thread is done.
188
    //
189
    // Note that Joiners must additionally pthread_join(), otherwise certain
190
    // resources that callers expect to be destroyed (like TLS) may still be
191
    // alive when a Joiner finishes.
192
    CountDownLatch _done;
193
194
    bool _joinable;
195
196
    // Thread local pointer to the current thread of execution. Will be nullptr if the current
197
    // thread is not a Thread.
198
    static __thread Thread* _tls;
199
200
    // Wait for the running thread to publish its tid.
201
    int64_t wait_for_tid() const;
202
203
    // Starts the thread running supervise_thread(), and returns once that thread has
204
    // initialised and its TID has been read. Waits for notification from the started
205
    // thread that initialisation is complete before returning. On success, stores a
206
    // reference to the thread in holder.
207
    static Status start_thread(const std::string& category, const std::string& name,
208
                               const ThreadFunctor& functor, uint64_t flags,
209
                               scoped_refptr<Thread>* holder);
210
211
    // Wrapper for the user-supplied function. Invoked from the new thread,
212
    // with the Thread as its only argument. Executes _functor, but before
213
    // doing so registers with the global ThreadMgr and reads the thread's
214
    // system ID. After _functor terminates, unregisters with the ThreadMgr.
215
    // Always returns nullptr.
216
    //
217
    // supervise_thread() notifies start_thread() when thread initialisation is
218
    // completed via the _tid, which is set to the new thread's system ID.
219
    // By that point in time supervise_thread() has also taken a reference to
220
    // the Thread object, allowing it to safely refer to it even after the
221
    // caller drops its reference.
222
    //
223
    // Additionally, start_thread() notifies supervise_thread() when the actual
224
    // Thread object has been assigned (supervise_thread() is spinning during
225
    // this time). Without this, the new thread may reference the actual
226
    // Thread object before it has been assigned by start_thread(). See
227
    // KUDU-11 for more details.
228
    static void* supervise_thread(void* arg);
229
230
    // Invoked when the user-supplied function finishes or in the case of an
231
    // abrupt exit (i.e. pthread_exit()). Cleans up after supervise_thread().
232
    static void finish_thread(void* arg);
233
234
    static void init_threadmgr();
235
};
236
237
// Utility to join on a thread, printing warning messages if it
238
// takes too long. For example:
239
//
240
//   ThreadJoiner(&my_thread, "processing thread")
241
//     .warn_after_ms(1000)
242
//     .warn_every_ms(5000)
243
//     .Join();
244
//
245
// TODO: would be nice to offer a way to use ptrace() or signals to
246
// dump the stack trace of the thread we're trying to join on if it
247
// gets stuck. But, after looking for 20 minutes or so, it seems
248
// pretty complicated to get right.
249
class ThreadJoiner {
250
public:
251
    explicit ThreadJoiner(Thread* thread);
252
253
    // Start emitting warnings after this many milliseconds.
254
    //
255
    // Default: 1000 ms.
256
    ThreadJoiner& warn_after_ms(int ms);
257
258
    // After the warnings after started, emit another warning at the
259
    // given interval.
260
    //
261
    // Default: 1000 ms.
262
    ThreadJoiner& warn_every_ms(int ms);
263
264
    // If the thread has not stopped after this number of milliseconds, give up
265
    // joining on it and return Status::Aborted.
266
    //
267
    // -1 (the default) means to wait forever trying to join.
268
    ThreadJoiner& give_up_after_ms(int ms);
269
270
    // Join the thread, subject to the above parameters. If the thread joining
271
    // fails for any reason, returns RuntimeError. If it times out, returns
272
    // Aborted.
273
    Status join();
274
275
private:
276
    enum {
277
        kDefaultWarnAfterMs = 1000,
278
        kDefaultWarnEveryMs = 1000,
279
        kDefaultGiveUpAfterMs = -1 // forever
280
    };
281
282
    Thread* _thread = nullptr;
283
284
    int _warn_after_ms;
285
    int _warn_every_ms;
286
    int _give_up_after_ms;
287
288
    DISALLOW_COPY_AND_ASSIGN(ThreadJoiner);
289
};
290
291
// Registers /threadz with the debug webserver.
292
void register_thread_display_page(WebPageHandler* web_page_handler);
293
294
} //namespace doris