Index: llvm/include/llvm/Support/thread.h =================================================================== --- llvm/include/llvm/Support/thread.h +++ llvm/include/llvm/Support/thread.h @@ -23,7 +23,102 @@ #include namespace llvm { +#if !defined(__APPLE__) typedef std::thread thread; +#else +/// Darwin's default stack size for threads except the main one is only 512KB, +/// which is not enough for some/many normal LLVM compilations. This implements +/// the same interface as std::thread but requests the same stack size as the +/// main thread (2MB) before creation. +class thread { + pthread_t Thread; + + template + static void Apply(std::tuple &Callee, std::index_sequence) { + std::move(std::get<0>(Callee))(std::move(std::get(Callee))...); + } + + template + static void *ThreadProxy(void *Ptr) { + std::unique_ptr Callee(static_cast(Ptr)); + + // FIXME: use std::apply when C++17 is allowed. + std::make_index_sequence() - 1> Indices{}; + Apply(*Callee.get(), Indices); + return nullptr; + } +public: + typedef pthread_t native_handle_type; + typedef pthread_t id; + + thread() : Thread(pthread_t()) {} + thread(thread &&Other) noexcept + : Thread(std::exchange(Other.Thread, pthread_t())) {} + + template + explicit thread(Function &&f, Args &&... args) { + pthread_attr_t Attr; + pthread_attr_init(&Attr); + pthread_attr_setstacksize(&Attr, 2 * 1024 * 1024); + + typedef std::tuple::type, + typename std::decay::type...> + CalleeTuple; + std::unique_ptr Callee( + new CalleeTuple(std::forward(f), std::forward(args)...)); + + int Err = pthread_create(&Thread, &Attr, ThreadProxy, Callee.get()); + if (Err == 0) + Callee.release(); + else + report_fatal_error("pthread_create failed"); + + pthread_attr_destroy(&Attr); + } + thread(const thread &) = delete; + + ~thread() { + if (joinable()) + std::terminate(); + } + + thread &operator=(thread &&Other) noexcept { + if (joinable()) + std::terminate(); + Thread = std::exchange(Other.Thread, pthread_t()); + return *this; + } + + bool joinable() const noexcept { + return Thread != pthread_t(); + } + + id get_id() const noexcept { + return Thread; + } + + native_handle_type native_handle() const noexcept { + return Thread; + } + + static unsigned hardware_concurrency() { return std::thread::hardware_concurrency(); }; + + void join() { + pthread_join(Thread, nullptr); + Thread = pthread_t(); + } + + void detach() { + pthread_detach(Thread); + Thread = pthread_t(); + } + + void swap(llvm::thread &Other) noexcept { + std::swap(Thread, Other.Thread); + } +}; + +#endif } #else // !LLVM_ENABLE_THREADS Index: llvm/unittests/Support/Threading.cpp =================================================================== --- llvm/unittests/Support/Threading.cpp +++ llvm/unittests/Support/Threading.cpp @@ -76,6 +76,17 @@ &Executed); ASSERT_EQ(Executed, true); } + +#if defined(__APPLE__) +TEST(Threading, AppleStackSize) { + llvm::thread Thread([] { + volatile unsigned char Var[2 * 1024 * 1024 - 1024]; + Var[0] = 0xff; + ASSERT_EQ(Var[0], 0xff); + }); + Thread.join(); +} +#endif #endif } // end anon namespace