mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-26 23:21:11 +00:00
615e6dd1c5
We recently noticed that the unwrap_iter.h file was pushing macros, but it was pushing them again instead of popping them at the end of the file. This led to libc++ basically swallowing any custom definition of these macros in user code: #define min HELLO #include <algorithm> // min is not HELLO anymore, it's not defined While investigating this issue, I noticed that our push/pop pragmas were actually entirely wrong too. Indeed, instead of pushing macros like `move`, we'd push `move(int, int)` in the pragma, which is not a valid macro name. As a result, we would not actually push macros like `move` -- instead we'd simply undefine them. This led to the following code not working: #define move HELLO #include <algorithm> // move is not HELLO anymore Fixing the pragma push/pop incantations led to a cascade of issues because we use identifiers like `move` in a large number of places, and all of these headers would now need to do the push/pop dance. This patch fixes all these issues. First, it adds a check that we don't swallow important names like min, max, move or refresh as explained above. This is done by augmenting the existing system_reserved_names.gen.py test to also check that the macros are what we expect after including each header. Second, it fixes the push/pop pragmas to work properly and adds missing pragmas to all the files I could detect a failure in via the newly added test. rdar://121365472 (cherry picked from commit 7b4622514d232ce5f7110dd8b20d90e81127c467)
260 lines
8.7 KiB
C++
260 lines
8.7 KiB
C++
// -*- C++ -*-
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef _LIBCPP___THREAD_THREAD_H
|
|
#define _LIBCPP___THREAD_THREAD_H
|
|
|
|
#include <__condition_variable/condition_variable.h>
|
|
#include <__config>
|
|
#include <__exception/terminate.h>
|
|
#include <__functional/hash.h>
|
|
#include <__functional/unary_function.h>
|
|
#include <__memory/unique_ptr.h>
|
|
#include <__mutex/mutex.h>
|
|
#include <__system_error/system_error.h>
|
|
#include <__thread/id.h>
|
|
#include <__threading_support>
|
|
#include <__utility/forward.h>
|
|
#include <tuple>
|
|
|
|
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
|
# include <locale>
|
|
# include <sstream>
|
|
#endif
|
|
|
|
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
|
# pragma GCC system_header
|
|
#endif
|
|
|
|
_LIBCPP_PUSH_MACROS
|
|
#include <__undef_macros>
|
|
|
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
|
|
|
template <class _Tp>
|
|
class __thread_specific_ptr;
|
|
class _LIBCPP_EXPORTED_FROM_ABI __thread_struct;
|
|
class _LIBCPP_HIDDEN __thread_struct_imp;
|
|
class __assoc_sub_state;
|
|
|
|
_LIBCPP_EXPORTED_FROM_ABI __thread_specific_ptr<__thread_struct>& __thread_local_data();
|
|
|
|
class _LIBCPP_EXPORTED_FROM_ABI __thread_struct {
|
|
__thread_struct_imp* __p_;
|
|
|
|
__thread_struct(const __thread_struct&);
|
|
__thread_struct& operator=(const __thread_struct&);
|
|
|
|
public:
|
|
__thread_struct();
|
|
~__thread_struct();
|
|
|
|
void notify_all_at_thread_exit(condition_variable*, mutex*);
|
|
void __make_ready_at_thread_exit(__assoc_sub_state*);
|
|
};
|
|
|
|
template <class _Tp>
|
|
class __thread_specific_ptr {
|
|
__libcpp_tls_key __key_;
|
|
|
|
// Only __thread_local_data() may construct a __thread_specific_ptr
|
|
// and only with _Tp == __thread_struct.
|
|
static_assert((is_same<_Tp, __thread_struct>::value), "");
|
|
__thread_specific_ptr();
|
|
friend _LIBCPP_EXPORTED_FROM_ABI __thread_specific_ptr<__thread_struct>& __thread_local_data();
|
|
|
|
__thread_specific_ptr(const __thread_specific_ptr&);
|
|
__thread_specific_ptr& operator=(const __thread_specific_ptr&);
|
|
|
|
_LIBCPP_HIDDEN static void _LIBCPP_TLS_DESTRUCTOR_CC __at_thread_exit(void*);
|
|
|
|
public:
|
|
typedef _Tp* pointer;
|
|
|
|
~__thread_specific_ptr();
|
|
|
|
_LIBCPP_HIDE_FROM_ABI pointer get() const { return static_cast<_Tp*>(__libcpp_tls_get(__key_)); }
|
|
_LIBCPP_HIDE_FROM_ABI pointer operator*() const { return *get(); }
|
|
_LIBCPP_HIDE_FROM_ABI pointer operator->() const { return get(); }
|
|
void set_pointer(pointer __p);
|
|
};
|
|
|
|
template <class _Tp>
|
|
void _LIBCPP_TLS_DESTRUCTOR_CC __thread_specific_ptr<_Tp>::__at_thread_exit(void* __p) {
|
|
delete static_cast<pointer>(__p);
|
|
}
|
|
|
|
template <class _Tp>
|
|
__thread_specific_ptr<_Tp>::__thread_specific_ptr() {
|
|
int __ec = __libcpp_tls_create(&__key_, &__thread_specific_ptr::__at_thread_exit);
|
|
if (__ec)
|
|
__throw_system_error(__ec, "__thread_specific_ptr construction failed");
|
|
}
|
|
|
|
template <class _Tp>
|
|
__thread_specific_ptr<_Tp>::~__thread_specific_ptr() {
|
|
// __thread_specific_ptr is only created with a static storage duration
|
|
// so this destructor is only invoked during program termination. Invoking
|
|
// pthread_key_delete(__key_) may prevent other threads from deleting their
|
|
// thread local data. For this reason we leak the key.
|
|
}
|
|
|
|
template <class _Tp>
|
|
void __thread_specific_ptr<_Tp>::set_pointer(pointer __p) {
|
|
_LIBCPP_ASSERT_INTERNAL(get() == nullptr, "Attempting to overwrite thread local data");
|
|
std::__libcpp_tls_set(__key_, __p);
|
|
}
|
|
|
|
template <>
|
|
struct _LIBCPP_TEMPLATE_VIS hash<__thread_id> : public __unary_function<__thread_id, size_t> {
|
|
_LIBCPP_HIDE_FROM_ABI size_t operator()(__thread_id __v) const _NOEXCEPT {
|
|
return hash<__libcpp_thread_id>()(__v.__id_);
|
|
}
|
|
};
|
|
|
|
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
|
template <class _CharT, class _Traits>
|
|
_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>&
|
|
operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id) {
|
|
// [thread.thread.id]/9
|
|
// Effects: Inserts the text representation for charT of id into out.
|
|
//
|
|
// [thread.thread.id]/2
|
|
// The text representation for the character type charT of an
|
|
// object of type thread::id is an unspecified sequence of charT
|
|
// such that, for two objects of type thread::id x and y, if
|
|
// x == y is true, the thread::id objects have the same text
|
|
// representation, and if x != y is true, the thread::id objects
|
|
// have distinct text representations.
|
|
//
|
|
// Since various flags in the output stream can affect how the
|
|
// thread id is represented (e.g. numpunct or showbase), we
|
|
// use a temporary stream instead and just output the thread
|
|
// id representation as a string.
|
|
|
|
basic_ostringstream<_CharT, _Traits> __sstr;
|
|
__sstr.imbue(locale::classic());
|
|
__sstr << __id.__id_;
|
|
return __os << __sstr.str();
|
|
}
|
|
#endif // _LIBCPP_HAS_NO_LOCALIZATION
|
|
|
|
class _LIBCPP_EXPORTED_FROM_ABI thread {
|
|
__libcpp_thread_t __t_;
|
|
|
|
thread(const thread&);
|
|
thread& operator=(const thread&);
|
|
|
|
public:
|
|
typedef __thread_id id;
|
|
typedef __libcpp_thread_t native_handle_type;
|
|
|
|
_LIBCPP_HIDE_FROM_ABI thread() _NOEXCEPT : __t_(_LIBCPP_NULL_THREAD) {}
|
|
#ifndef _LIBCPP_CXX03_LANG
|
|
template <class _Fp, class... _Args, class = __enable_if_t<!is_same<__remove_cvref_t<_Fp>, thread>::value> >
|
|
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS explicit thread(_Fp&& __f, _Args&&... __args);
|
|
#else // _LIBCPP_CXX03_LANG
|
|
template <class _Fp>
|
|
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS explicit thread(_Fp __f);
|
|
#endif
|
|
~thread();
|
|
|
|
_LIBCPP_HIDE_FROM_ABI thread(thread&& __t) _NOEXCEPT : __t_(__t.__t_) { __t.__t_ = _LIBCPP_NULL_THREAD; }
|
|
|
|
_LIBCPP_HIDE_FROM_ABI thread& operator=(thread&& __t) _NOEXCEPT {
|
|
if (!__libcpp_thread_isnull(&__t_))
|
|
terminate();
|
|
__t_ = __t.__t_;
|
|
__t.__t_ = _LIBCPP_NULL_THREAD;
|
|
return *this;
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI void swap(thread& __t) _NOEXCEPT { std::swap(__t_, __t.__t_); }
|
|
|
|
_LIBCPP_HIDE_FROM_ABI bool joinable() const _NOEXCEPT { return !__libcpp_thread_isnull(&__t_); }
|
|
void join();
|
|
void detach();
|
|
_LIBCPP_HIDE_FROM_ABI id get_id() const _NOEXCEPT { return __libcpp_thread_get_id(&__t_); }
|
|
_LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() _NOEXCEPT { return __t_; }
|
|
|
|
static unsigned hardware_concurrency() _NOEXCEPT;
|
|
};
|
|
|
|
#ifndef _LIBCPP_CXX03_LANG
|
|
|
|
template <class _TSp, class _Fp, class... _Args, size_t... _Indices>
|
|
inline _LIBCPP_HIDE_FROM_ABI void __thread_execute(tuple<_TSp, _Fp, _Args...>& __t, __tuple_indices<_Indices...>) {
|
|
std::__invoke(std::move(std::get<1>(__t)), std::move(std::get<_Indices>(__t))...);
|
|
}
|
|
|
|
template <class _Fp>
|
|
_LIBCPP_HIDE_FROM_ABI void* __thread_proxy(void* __vp) {
|
|
// _Fp = tuple< unique_ptr<__thread_struct>, Functor, Args...>
|
|
unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp));
|
|
__thread_local_data().set_pointer(std::get<0>(*__p.get()).release());
|
|
typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 2>::type _Index;
|
|
std::__thread_execute(*__p.get(), _Index());
|
|
return nullptr;
|
|
}
|
|
|
|
template <class _Fp, class... _Args, class >
|
|
thread::thread(_Fp&& __f, _Args&&... __args) {
|
|
typedef unique_ptr<__thread_struct> _TSPtr;
|
|
_TSPtr __tsp(new __thread_struct);
|
|
typedef tuple<_TSPtr, __decay_t<_Fp>, __decay_t<_Args>...> _Gp;
|
|
unique_ptr<_Gp> __p(new _Gp(std::move(__tsp), std::forward<_Fp>(__f), std::forward<_Args>(__args)...));
|
|
int __ec = std::__libcpp_thread_create(&__t_, &__thread_proxy<_Gp>, __p.get());
|
|
if (__ec == 0)
|
|
__p.release();
|
|
else
|
|
__throw_system_error(__ec, "thread constructor failed");
|
|
}
|
|
|
|
#else // _LIBCPP_CXX03_LANG
|
|
|
|
template <class _Fp>
|
|
struct __thread_invoke_pair {
|
|
// This type is used to pass memory for thread local storage and a functor
|
|
// to a newly created thread because std::pair doesn't work with
|
|
// std::unique_ptr in C++03.
|
|
_LIBCPP_HIDE_FROM_ABI __thread_invoke_pair(_Fp& __f) : __tsp_(new __thread_struct), __fn_(__f) {}
|
|
unique_ptr<__thread_struct> __tsp_;
|
|
_Fp __fn_;
|
|
};
|
|
|
|
template <class _Fp>
|
|
_LIBCPP_HIDE_FROM_ABI void* __thread_proxy_cxx03(void* __vp) {
|
|
unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp));
|
|
__thread_local_data().set_pointer(__p->__tsp_.release());
|
|
(__p->__fn_)();
|
|
return nullptr;
|
|
}
|
|
|
|
template <class _Fp>
|
|
thread::thread(_Fp __f) {
|
|
typedef __thread_invoke_pair<_Fp> _InvokePair;
|
|
typedef unique_ptr<_InvokePair> _PairPtr;
|
|
_PairPtr __pp(new _InvokePair(__f));
|
|
int __ec = std::__libcpp_thread_create(&__t_, &__thread_proxy_cxx03<_InvokePair>, __pp.get());
|
|
if (__ec == 0)
|
|
__pp.release();
|
|
else
|
|
__throw_system_error(__ec, "thread constructor failed");
|
|
}
|
|
|
|
#endif // _LIBCPP_CXX03_LANG
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI void swap(thread& __x, thread& __y) _NOEXCEPT { __x.swap(__y); }
|
|
|
|
_LIBCPP_END_NAMESPACE_STD
|
|
|
|
_LIBCPP_POP_MACROS
|
|
|
|
#endif // _LIBCPP___THREAD_THREAD_H
|