1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/testapp.h>
#include <atomic>
#include <unistd.h>
using namespace vespalib;
class Test : public TestApp
{
public:
~Test();
int Main() override;
};
Test::~Test()
{
}
void * just_return(void * arg)
{
return arg;
}
void * just_exit(void * arg)
{
pthread_exit(arg);
}
void * just_cancel(void * arg)
{
sleep(60);
return arg;
}
struct wait_info {
wait_info() :
_count(0)
{
if (pthread_mutex_init(&_mutex, NULL) != 0) { abort(); }
if (pthread_cond_init(&_cond, NULL) != 0) { abort(); }
}
~wait_info() {
if (pthread_mutex_destroy(&_mutex) != 0) { abort(); }
if (pthread_cond_destroy(&_cond) != 0) { abort(); }
}
pthread_cond_t _cond;
pthread_mutex_t _mutex;
std::atomic<uint64_t> _count;
};
void * just_wait(void * arg)
{
wait_info * info = (wait_info *) arg;
pthread_mutex_lock(&info->_mutex);
info->_count.fetch_add(1);
pthread_cond_wait(&info->_cond, &info->_mutex);
pthread_mutex_unlock(&info->_mutex);
pthread_cond_signal(&info->_cond);
info->_count.fetch_sub(1);
return arg;
}
int Test::Main()
{
TEST_INIT("thread_test");
size_t threadCount(102400);
if (_argc >= 3) {
threadCount = strtoul(_argv[2], NULL, 0);
}
const char * testType = _argv[1];
for (size_t i(0); i < threadCount; i++) {
pthread_t th;
void *retval;
if (strcmp(testType, "exit") == 0) {
EXPECT_EQUAL( pthread_create(&th, NULL, just_exit, NULL), 0);
} else if (strcmp(testType, "cancel") == 0) {
EXPECT_EQUAL( pthread_create(&th, NULL, just_cancel, NULL), 0);
EXPECT_EQUAL( pthread_cancel(th), 0);
} else {
EXPECT_EQUAL( pthread_create(&th, NULL, just_return, NULL), 0);
}
EXPECT_EQUAL(pthread_join(th, &retval), 0);
}
wait_info info;
pthread_attr_t attr;
EXPECT_EQUAL(pthread_attr_init(&attr), 0);
EXPECT_EQUAL(pthread_attr_setstacksize(&attr, 64*1024), 0);
EXPECT_EQUAL(info._count, 0ul);
const size_t NUM_THREADS(16382); // +1 for main thread, +1 for testsystem = 16384
pthread_t tl[NUM_THREADS];
for (size_t j=0;j < NUM_THREADS;j++) {
int e = pthread_create(&tl[j], &attr, just_wait, &info);
if (e != 0) {
fprintf(stderr, "pthread_create failed at index '%ld'. with errno='%d'", j, e);
perror("pthread_create failed");
abort();
}
}
pthread_t th;
EXPECT_EQUAL( pthread_create(&th, &attr, just_wait, &info), EAGAIN); // Verify that you have reached upper limit of threads with vespamalloc.
while (info._count != NUM_THREADS) {
usleep(1);
}
pthread_mutex_lock(&info._mutex);
pthread_cond_signal(&info._cond);
pthread_mutex_unlock(&info._mutex);
for (size_t j=0;j < NUM_THREADS;j++) {
void *retval;
EXPECT_EQUAL(pthread_join(tl[j], &retval), 0);
}
EXPECT_EQUAL(pthread_attr_destroy(&attr), 0);
EXPECT_EQUAL(info._count, 0ul);
TEST_DONE();
}
TEST_APPHOOK(Test);
|