Coverage Report

Created: 2022-07-16 07:03

/Users/buildslave/jenkins/workspace/coverage/llvm-project/libcxx/src/thread.cpp
Line
Count
Source (jump to first uncovered line)
1
//===------------------------- thread.cpp----------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include <__config>
10
11
#ifndef _LIBCPP_HAS_NO_THREADS
12
13
#include <exception>
14
#include <future>
15
#include <limits>
16
#include <thread>
17
#include <vector>
18
19
#if __has_include(<unistd.h>)
20
# include <unistd.h> // for sysconf
21
#endif
22
23
#if defined(__NetBSD__)
24
#pragma weak pthread_create // Do not create libpthread dependency
25
#endif
26
27
#if defined(_LIBCPP_WIN32API)
28
#include <windows.h>
29
#endif
30
31
#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
32
#pragma comment(lib, "pthread")
33
#endif
34
35
_LIBCPP_BEGIN_NAMESPACE_STD
36
37
thread::~thread()
38
24
{
39
24
    if (!__libcpp_thread_isnull(&__t_))
40
0
        terminate();
41
24
}
42
43
void
44
thread::join()
45
3
{
46
3
    int ec = EINVAL;
47
3
    if (!__libcpp_thread_isnull(&__t_))
48
3
    {
49
3
        ec = __libcpp_thread_join(&__t_);
50
3
        if (ec == 0)
51
3
            __t_ = _LIBCPP_NULL_THREAD;
52
3
    }
53
54
3
    if (ec)
55
0
        __throw_system_error(ec, "thread::join failed");
56
3
}
57
58
void
59
thread::detach()
60
8
{
61
8
    int ec = EINVAL;
62
8
    if (!__libcpp_thread_isnull(&__t_))
63
8
    {
64
8
        ec = __libcpp_thread_detach(&__t_);
65
8
        if (ec == 0)
66
8
            __t_ = _LIBCPP_NULL_THREAD;
67
8
    }
68
69
8
    if (ec)
70
0
        __throw_system_error(ec, "thread::detach failed");
71
8
}
72
73
unsigned
74
thread::hardware_concurrency() noexcept
75
2
{
76
2
#if defined(_SC_NPROCESSORS_ONLN)
77
2
    long result = sysconf(_SC_NPROCESSORS_ONLN);
78
    // sysconf returns -1 if the name is invalid, the option does not exist or
79
    // does not have a definite limit.
80
    // if sysconf returns some other negative number, we have no idea
81
    // what is going on. Default to something safe.
82
2
    if (result < 0)
83
0
        return 0;
84
2
    return static_cast<unsigned>(result);
85
#elif defined(_LIBCPP_WIN32API)
86
    SYSTEM_INFO info;
87
    GetSystemInfo(&info);
88
    return info.dwNumberOfProcessors;
89
#else  // defined(CTL_HW) && defined(HW_NCPU)
90
    // TODO: grovel through /proc or check cpuid on x86 and similar
91
    // instructions on other architectures.
92
#   if defined(_LIBCPP_WARNING)
93
        _LIBCPP_WARNING("hardware_concurrency not yet implemented")
94
#   else
95
#       warning hardware_concurrency not yet implemented
96
#   endif
97
    return 0;  // Means not computable [thread.thread.static]
98
#endif // defined(CTL_HW) && defined(HW_NCPU)
99
2
}
100
101
namespace this_thread
102
{
103
104
void
105
sleep_for(const chrono::nanoseconds& ns)
106
3
{
107
3
    if (ns > chrono::nanoseconds::zero())
108
3
    {
109
3
        __libcpp_thread_sleep_for(ns);
110
3
    }
111
3
}
112
113
}  // this_thread
114
115
__thread_specific_ptr<__thread_struct>&
116
__thread_local_data()
117
21
{
118
  // Even though __thread_specific_ptr's destructor doesn't actually destroy
119
  // anything (see comments there), we can't call it at all because threads may
120
  // outlive the static variable and calling its destructor means accessing an
121
  // object outside of its lifetime, which is UB.
122
21
  alignas(__thread_specific_ptr<__thread_struct>) static char __b[sizeof(__thread_specific_ptr<__thread_struct>)];
123
21
  static __thread_specific_ptr<__thread_struct>* __p = new (__b) __thread_specific_ptr<__thread_struct>();
124
21
  return *__p;
125
21
}
126
127
// __thread_struct_imp
128
129
template <class T>
130
class _LIBCPP_HIDDEN __hidden_allocator
131
{
132
public:
133
    typedef T  value_type;
134
135
    T* allocate(size_t __n)
136
0
        {return static_cast<T*>(::operator new(__n * sizeof(T)));}
Unexecuted instantiation: std::__1::__hidden_allocator<std::__1::pair<std::__1::condition_variable*, std::__1::mutex*> >::allocate(unsigned long)
Unexecuted instantiation: std::__1::__hidden_allocator<std::__1::__assoc_sub_state*>::allocate(unsigned long)
137
0
    void deallocate(T* __p, size_t) {::operator delete(static_cast<void*>(__p));}
Unexecuted instantiation: std::__1::__hidden_allocator<std::__1::__assoc_sub_state*>::deallocate(std::__1::__assoc_sub_state**, unsigned long)
Unexecuted instantiation: std::__1::__hidden_allocator<std::__1::pair<std::__1::condition_variable*, std::__1::mutex*> >::deallocate(std::__1::pair<std::__1::condition_variable*, std::__1::mutex*>*, unsigned long)
138
139
0
    size_t max_size() const {return size_t(~0) / sizeof(T);}
Unexecuted instantiation: std::__1::__hidden_allocator<std::__1::pair<std::__1::condition_variable*, std::__1::mutex*> >::max_size() const
Unexecuted instantiation: std::__1::__hidden_allocator<std::__1::__assoc_sub_state*>::max_size() const
140
};
141
142
class _LIBCPP_HIDDEN __thread_struct_imp
143
{
144
    typedef vector<__assoc_sub_state*,
145
                          __hidden_allocator<__assoc_sub_state*> > _AsyncStates;
146
    typedef vector<pair<condition_variable*, mutex*>,
147
               __hidden_allocator<pair<condition_variable*, mutex*> > > _Notify;
148
149
    _AsyncStates async_states_;
150
    _Notify notify_;
151
152
    __thread_struct_imp(const __thread_struct_imp&);
153
    __thread_struct_imp& operator=(const __thread_struct_imp&);
154
public:
155
21
    __thread_struct_imp() {}
156
    ~__thread_struct_imp();
157
158
    void notify_all_at_thread_exit(condition_variable* cv, mutex* m);
159
    void __make_ready_at_thread_exit(__assoc_sub_state* __s);
160
};
161
162
__thread_struct_imp::~__thread_struct_imp()
163
21
{
164
21
    for (_Notify::iterator i = notify_.begin(), e = notify_.end();
165
21
            i != e; 
++i0
)
166
0
    {
167
0
        i->second->unlock();
168
0
        i->first->notify_all();
169
0
    }
170
21
    for (_AsyncStates::iterator i = async_states_.begin(), e = async_states_.end();
171
21
            i != e; 
++i0
)
172
0
    {
173
0
        (*i)->__make_ready();
174
0
        (*i)->__release_shared();
175
0
    }
176
21
}
177
178
void
179
__thread_struct_imp::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
180
0
{
181
0
    notify_.push_back(pair<condition_variable*, mutex*>(cv, m));
182
0
}
183
184
void
185
__thread_struct_imp::__make_ready_at_thread_exit(__assoc_sub_state* __s)
186
0
{
187
0
    async_states_.push_back(__s);
188
0
    __s->__add_shared();
189
0
}
190
191
// __thread_struct
192
193
__thread_struct::__thread_struct()
194
    : __p_(new __thread_struct_imp)
195
21
{
196
21
}
197
198
__thread_struct::~__thread_struct()
199
21
{
200
21
    delete __p_;
201
21
}
202
203
void
204
__thread_struct::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
205
0
{
206
0
    __p_->notify_all_at_thread_exit(cv, m);
207
0
}
208
209
void
210
__thread_struct::__make_ready_at_thread_exit(__assoc_sub_state* __s)
211
0
{
212
0
    __p_->__make_ready_at_thread_exit(__s);
213
0
}
214
215
_LIBCPP_END_NAMESPACE_STD
216
217
#endif // !_LIBCPP_HAS_NO_THREADS