Coverage Report

Created: 2021-09-21 08:58

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