Commit c7cd1587 authored by jamesge's avatar jamesge

Support fork without exec

parent 6efb0cff
...@@ -57,13 +57,11 @@ struct CombineSampler { ...@@ -57,13 +57,11 @@ struct CombineSampler {
// deletion is taken place in the thread as well. // deletion is taken place in the thread as well.
class SamplerCollector : public bvar::Reducer<Sampler*, CombineSampler> { class SamplerCollector : public bvar::Reducer<Sampler*, CombineSampler> {
public: public:
SamplerCollector() : _created(false), _stop(false), _cumulated_time_us(0) { SamplerCollector()
int rc = pthread_create(&_tid, NULL, sampling_thread, this); : _created(false)
if (rc != 0) { , _stop(false)
LOG(FATAL) << "Fail to create sampling_thread, " << berror(rc); , _cumulated_time_us(0) {
} else { create_sampling_thread();
_created = true;
}
} }
~SamplerCollector() { ~SamplerCollector() {
if (_created) { if (_created) {
...@@ -73,33 +71,75 @@ public: ...@@ -73,33 +71,75 @@ public:
} }
} }
static double get_cumulated_time(void* arg) {
return ((SamplerCollector*)arg)->_cumulated_time_us / 1000.0 / 1000.0;
}
private: private:
// Support for fork:
// * The singleton can be null before forking, the child callback will not
// be registered.
// * If the singleton is not null before forking, the child callback will
// be registered and the sampling thread will be re-created.
// * A forked program can be forked again.
static void child_callback_atfork() {
butil::get_leaky_singleton<SamplerCollector>()->after_forked_as_child();
}
void create_sampling_thread() {
const int rc = pthread_create(&_tid, NULL, sampling_thread, this);
if (rc != 0) {
LOG(FATAL) << "Fail to create sampling_thread, " << berror(rc);
} else {
_created = true;
pthread_atfork(NULL, NULL, child_callback_atfork);
}
}
void after_forked_as_child() {
_created = false;
create_sampling_thread();
}
void run(); void run();
static void* sampling_thread(void* arg) { static void* sampling_thread(void* arg) {
((SamplerCollector*)arg)->run(); static_cast<SamplerCollector*>(arg)->run();
return NULL; return NULL;
} }
static double get_cumulated_time(void* arg) {
return static_cast<SamplerCollector*>(arg)->_cumulated_time_us / 1000.0 / 1000.0;
}
private: private:
bool _created; bool _created;
bool _stop; bool _stop;
pid_t _created_pid;
int64_t _cumulated_time_us; int64_t _cumulated_time_us;
pthread_t _tid; pthread_t _tid;
}; };
PassiveStatus<double>* g_cumulated_time_bvar = NULL;
bvar::PerSecond<bvar::PassiveStatus<double> >* g_sampling_thread_usage_bvar = NULL;
void SamplerCollector::run() { void SamplerCollector::run() {
butil::LinkNode<Sampler> root;
int consecutive_nosleep = 0;
#ifndef UNIT_TEST #ifndef UNIT_TEST
PassiveStatus<double> cumulated_time(get_cumulated_time, this); // NOTE:
bvar::PerSecond<bvar::PassiveStatus<double> > usage( // * Following vars can't be created on thread's stack since this thread
"bvar_sampler_collector_usage", &cumulated_time, 10); // may be adandoned at any time after forking.
// * They can't created inside the constructor of SamplerCollector as well,
// which results in deadlock.
if (g_cumulated_time_bvar == NULL) {
g_cumulated_time_bvar =
new PassiveStatus<double>(get_cumulated_time, this);
}
if (g_sampling_thread_usage_bvar == NULL) {
g_sampling_thread_usage_bvar =
new bvar::PerSecond<bvar::PassiveStatus<double> >(
"bvar_sampler_collector_usage", g_cumulated_time_bvar, 10);
}
#endif #endif
butil::LinkNode<Sampler> root;
int consecutive_nosleep = 0;
while (!_stop) { while (!_stop) {
int64_t abstime = butil::gettimeofday_us(); int64_t abstime = butil::gettimeofday_us();
Sampler* s = this->reset(); Sampler* s = this->reset();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment