ext/oxt/thread.hpp in passenger-3.0.21 vs ext/oxt/thread.hpp in passenger-3.9.1.beta
- old
+ new
@@ -24,94 +24,35 @@
*/
#ifndef _OXT_THREAD_HPP_
#define _OXT_THREAD_HPP_
#include <boost/thread.hpp>
-#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
+#include <boost/make_shared.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include "system_calls.hpp"
-#include "backtrace.hpp"
-#ifdef OXT_BACKTRACE_IS_ENABLED
- #include <sstream>
-#endif
+#include "detail/context.hpp"
#include <string>
#include <list>
#include <unistd.h>
#include <limits.h> // for PTHREAD_STACK_MIN
namespace oxt {
-extern boost::mutex _next_thread_number_mutex;
-extern unsigned int _next_thread_number;
-
/**
* Enhanced thread class with support for:
* - user-defined stack size.
* - system call interruption.
* - backtraces.
*/
class thread: public boost::thread {
private:
- struct thread_data {
- std::string name;
- #ifdef OXT_BACKTRACE_IS_ENABLED
- thread_registration *registration;
- boost::mutex registration_lock;
- bool done;
- #endif
- };
-
- typedef boost::shared_ptr<thread_data> thread_data_ptr;
-
- thread_data_ptr data;
+ thread_local_context_ptr context;
- void initialize_data(const std::string &thread_name) {
- data = thread_data_ptr(new thread_data());
- if (thread_name.empty()) {
- boost::mutex::scoped_lock l(_next_thread_number_mutex);
- std::stringstream str;
-
- str << "Thread #" << _next_thread_number;
- _next_thread_number++;
- data->name = str.str();
- } else {
- data->name = thread_name;
- }
- #ifdef OXT_BACKTRACE_IS_ENABLED
- data->registration = NULL;
- data->done = false;
- #endif
- }
+ static std::string make_thread_name(const std::string &given_name);
+ static void thread_main(const boost::function<void ()> func, thread_local_context_ptr ctx);
- static void thread_main(const boost::function<void ()> func, thread_data_ptr data) {
- #ifdef OXT_BACKTRACE_IS_ENABLED
- initialize_backtrace_support_for_this_thread i(data->name);
- data->registration = i.registration;
- #endif
-
- #ifdef OXT_BACKTRACE_IS_ENABLED
- // Put finalization code in a struct destructor,
- // for exception safety.
- struct finalization_routines {
- thread_data_ptr &data;
-
- finalization_routines(thread_data_ptr &data_)
- : data(data_) {}
-
- ~finalization_routines() {
- boost::mutex::scoped_lock l(data->registration_lock);
- data->registration = NULL;
- data->done = true;
- }
- };
- finalization_routines f(data);
- #endif
-
- func();
- }
-
public:
/**
* Create a new thread.
*
* @param func A function object which will be called as the thread's
@@ -127,15 +68,15 @@
* system's minimum stack size will be used.
* @pre func must be copyable.
* @throws boost::thread_resource_error Something went wrong during
* creation of the thread.
*/
- explicit thread(const boost::function<void ()> func, const std::string &name = "", unsigned int stack_size = 0) {
- initialize_data(name);
+ explicit thread(const boost::function<void ()> func, const std::string &name = std::string(), unsigned int stack_size = 0) {
+ context = thread_local_context::make_shared_ptr();
+ context->thread_name = make_thread_name(name);
+ set_thread_main_function(boost::bind(thread_main, func, context));
- set_thread_main_function(boost::bind(thread_main, func, data));
-
unsigned long min_stack_size;
bool stack_min_size_defined;
bool round_stack_size;
#ifdef PTHREAD_STACK_MIN
@@ -178,57 +119,22 @@
}
/**
* Return this thread's name. The name was set during construction.
*/
- std::string name() const throw() {
- return data->name;
- }
+ std::string name() const throw();
/**
* Return the current backtrace of the thread of execution, as a string.
*/
- std::string backtrace() const throw() {
- #ifdef OXT_BACKTRACE_IS_ENABLED
- boost::mutex::scoped_lock l(data->registration_lock);
- if (data->registration == NULL) {
- if (data->done) {
- return " (no backtrace: thread has quit)";
- } else {
- return " (no backtrace: thread hasn't been started yet)";
- }
- } else {
- spin_lock::scoped_lock l2(*data->registration->backtrace_lock);
- return _format_backtrace(data->registration->backtrace);
- }
- #else
- return " (backtrace support disabled during compile time)";
- #endif
- }
+ std::string backtrace() const throw();
/**
* Return the backtraces of all oxt::thread threads, as well as that of the
* main thread, in a nicely formatted string.
*/
- static std::string all_backtraces() throw() {
- #ifdef OXT_BACKTRACE_IS_ENABLED
- boost::mutex::scoped_lock l(_thread_registration_mutex);
- list<thread_registration *>::const_iterator it;
- std::stringstream result;
-
- for (it = _registered_threads.begin(); it != _registered_threads.end(); it++) {
- thread_registration *r = *it;
- result << "Thread '" << r->name << "':" << endl;
-
- spin_lock::scoped_lock l(*r->backtrace_lock);
- result << _format_backtrace(r->backtrace) << endl;
- }
- return result.str();
- #else
- return "(backtrace support disabled during compile time)";
- #endif
- }
+ static std::string all_backtraces() throw();
/**
* Interrupt the thread. This method behaves just like
* boost::thread::interrupt(), but if <em>interruptSyscalls</em> is true
* then it will also respect the interruption points defined in
@@ -238,20 +144,10 @@
* current execution point of the thread. Thus, one should call this
* method in a loop, until a certain goal condition has been fulfilled.
* interrupt_and_join() is a convenience method that implements this
* pattern.
*/
- void interrupt(bool interruptSyscalls = true) {
- int ret;
-
- boost::thread::interrupt();
- if (interruptSyscalls) {
- do {
- ret = pthread_kill(native_handle(),
- INTERRUPTION_SIGNAL);
- } while (ret == EINTR);
- }
- }
+ void interrupt(bool interruptSyscalls = true);
/**
* Keep interrupting the thread until it's done, then join it.
*
* @param interruptSyscalls Whether oxt::syscalls calls should also