File: thread_test.c

package info (click to toggle)
aws-crt-python 0.20.4%2Bdfsg-1~bpo12%2B1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-backports
  • size: 72,656 kB
  • sloc: ansic: 381,805; python: 23,008; makefile: 6,251; sh: 4,536; cpp: 699; ruby: 208; java: 77; perl: 73; javascript: 46; xml: 11
file content (221 lines) | stat: -rw-r--r-- 7,582 bytes parent folder | download
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/**
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */

#include <aws/common/clock.h>
#include <aws/common/private/thread_shared.h>
#include <aws/common/thread.h>

#include <aws/testing/aws_test_harness.h>

struct thread_test_data {
    struct aws_allocator *allocator;
    aws_thread_id_t thread_id;
    struct aws_string *thread_name;
    int get_thread_name_error;
};

static void s_thread_fn(void *arg) {
    struct thread_test_data *test_data = (struct thread_test_data *)arg;
    test_data->thread_id = aws_thread_current_thread_id();
    test_data->get_thread_name_error = AWS_OP_SUCCESS;
    if (aws_thread_name(test_data->allocator, test_data->thread_id, &test_data->thread_name)) {
        test_data->get_thread_name_error = aws_last_error();
    }
}

static int s_test_thread_creation_join_fn(struct aws_allocator *allocator, void *ctx) {
    (void)ctx;
    aws_common_library_init(allocator);
    struct thread_test_data test_data = {.allocator = allocator};

    struct aws_thread thread;
    aws_thread_init(&thread, allocator);

    struct aws_thread_options thread_options = *aws_default_thread_options();
    /* there should be at least 1 cpu on any machine running this test. Just bind that to make sure that code
     * path is exercised. */
    thread_options.cpu_id = 0;

    /* Exercise the thread naming code path */
    thread_options.name = aws_byte_cursor_from_c_str("MyThreadName");

    ASSERT_SUCCESS(
        aws_thread_launch(&thread, s_thread_fn, (void *)&test_data, &thread_options), "thread creation failed");
    ASSERT_INT_EQUALS(
        AWS_THREAD_JOINABLE, aws_thread_get_detach_state(&thread), "thread state should have returned JOINABLE");
    ASSERT_SUCCESS(aws_thread_join(&thread), "thread join failed");
    ASSERT_TRUE(
        aws_thread_thread_id_equal(test_data.thread_id, aws_thread_get_id(&thread)),
        "get_thread_id should have returned the same id as the thread calling current_thread_id");
    ASSERT_INT_EQUALS(
        AWS_THREAD_JOIN_COMPLETED,
        aws_thread_get_detach_state(&thread),
        "thread state should have returned JOIN_COMPLETED");

    if (AWS_OP_SUCCESS == test_data.get_thread_name_error) {
        ASSERT_CURSOR_VALUE_STRING_EQUALS(
            aws_byte_cursor_from_c_str("MyThreadName"), test_data.thread_name, "thread name equals");
    } else {
        ASSERT_INT_EQUALS(test_data.get_thread_name_error, AWS_ERROR_PLATFORM_NOT_SUPPORTED);
    }

    aws_string_destroy(test_data.thread_name);
    aws_thread_clean_up(&thread);
    aws_common_library_clean_up();

    return 0;
}

AWS_TEST_CASE(thread_creation_join_test, s_test_thread_creation_join_fn)

static uint32_t s_atexit_call_count = 0;
static void s_thread_atexit_fn(void *user_data) {
    (void)user_data;
    AWS_FATAL_ASSERT(s_atexit_call_count == 0);
    s_atexit_call_count = 1;
}

static void s_thread_atexit_fn2(void *user_data) {
    (void)user_data;
    AWS_FATAL_ASSERT(s_atexit_call_count == 1);
    s_atexit_call_count = 2;
}

static void s_thread_worker_with_atexit(void *arg) {
    (void)arg;
    AWS_FATAL_ASSERT(AWS_OP_SUCCESS == aws_thread_current_at_exit(s_thread_atexit_fn2, NULL));
    AWS_FATAL_ASSERT(AWS_OP_SUCCESS == aws_thread_current_at_exit(s_thread_atexit_fn, NULL));
}

static int s_test_thread_atexit(struct aws_allocator *allocator, void *ctx) {
    (void)ctx;
    struct aws_thread thread;
    ASSERT_SUCCESS(aws_thread_init(&thread, allocator));

    ASSERT_SUCCESS(aws_thread_launch(&thread, s_thread_worker_with_atexit, NULL, 0), "thread creation failed");
    ASSERT_SUCCESS(aws_thread_join(&thread), "thread join failed");

    ASSERT_INT_EQUALS(2, s_atexit_call_count);

    aws_thread_clean_up(&thread);

    return 0;
}

AWS_TEST_CASE(thread_atexit_test, s_test_thread_atexit)

struct managed_thread_test_data {
    uint64_t sleep_time_in_ns;
};

static void s_managed_thread_fn(void *arg) {
    struct managed_thread_test_data *test_data = (struct managed_thread_test_data *)arg;

    aws_thread_current_sleep(test_data->sleep_time_in_ns);
}

#define MAX_MANAGED_THREAD_TEST_QUANTITY 16

static int s_do_managed_thread_join_test(struct aws_allocator *allocator, size_t thread_count) {

    struct aws_thread threads[MAX_MANAGED_THREAD_TEST_QUANTITY];
    struct managed_thread_test_data thread_data[MAX_MANAGED_THREAD_TEST_QUANTITY];

    AWS_FATAL_ASSERT(thread_count <= MAX_MANAGED_THREAD_TEST_QUANTITY);

    for (size_t i = 0; i < thread_count; ++i) {
        thread_data[i].sleep_time_in_ns =
            aws_timestamp_convert(100 * (i / 2), AWS_TIMESTAMP_MILLIS, AWS_TIMESTAMP_NANOS, NULL);
        aws_thread_init(&threads[i], allocator);
    }

    struct aws_thread_options thread_options = *aws_default_thread_options();
    thread_options.join_strategy = AWS_TJS_MANAGED;

    for (size_t i = 0; i < thread_count; ++i) {
        ASSERT_SUCCESS(
            aws_thread_launch(&threads[i], s_managed_thread_fn, (void *)&thread_data[i], &thread_options),
            "thread creation failed");

        ASSERT_INT_EQUALS(
            AWS_THREAD_MANAGED, aws_thread_get_detach_state(&threads[i]), "thread state should have returned JOINABLE");
    }

    aws_thread_join_all_managed();

    return AWS_OP_SUCCESS;
}

static int s_test_managed_thread_join(struct aws_allocator *allocator, void *ctx) {
    (void)ctx;
    aws_common_library_init(allocator);

    for (size_t i = 1; i <= MAX_MANAGED_THREAD_TEST_QUANTITY; ++i) {
        ASSERT_SUCCESS(s_do_managed_thread_join_test(allocator, i));
    }

    aws_common_library_clean_up();

    return 0;
}

AWS_TEST_CASE(test_managed_thread_join, s_test_managed_thread_join)

/*
 * Because this is unmocked time, this is technically not a purely deterministic test, but we set the time values
 * to extreme enough values that it should absurdly unlikely that an internal OS/CPU hiccup causes this test to fail.
 */
static int s_test_managed_thread_join_timeout(struct aws_allocator *allocator, void *ctx) {
    (void)ctx;
    aws_common_library_init(allocator);

    /*
     * Add a short timeout to managed thread join
     */
    aws_thread_set_managed_join_timeout_ns(aws_timestamp_convert(1, AWS_TIMESTAMP_SECS, AWS_TIMESTAMP_NANOS, NULL));

    /*
     * Spawn a managed thread that sleeps for significantly longer.
     */
    struct managed_thread_test_data thread_data;
    AWS_ZERO_STRUCT(thread_data);
    thread_data.sleep_time_in_ns = aws_timestamp_convert(3, AWS_TIMESTAMP_SECS, AWS_TIMESTAMP_NANOS, NULL);

    struct aws_thread thread;
    AWS_ZERO_STRUCT(thread);
    aws_thread_init(&thread, allocator);

    struct aws_thread_options thread_options = *aws_default_thread_options();
    thread_options.join_strategy = AWS_TJS_MANAGED;

    ASSERT_SUCCESS(
        aws_thread_launch(&thread, s_managed_thread_fn, (void *)&thread_data, &thread_options),
        "thread creation failed");

    ASSERT_TRUE(aws_thread_get_managed_thread_count() == 1);

    /*
     * Do a managed thread join, it should timeout
     */
    aws_thread_join_all_managed();

    /*
     * Check that the managed thread is still running
     */
    ASSERT_TRUE(aws_thread_get_managed_thread_count() == 1);

    /*
     * Increase the timeout and shut down
     */
    aws_thread_set_managed_join_timeout_ns(aws_timestamp_convert(5, AWS_TIMESTAMP_SECS, AWS_TIMESTAMP_NANOS, NULL));

    aws_common_library_clean_up();

    ASSERT_TRUE(aws_thread_get_managed_thread_count() == 0);

    return 0;
}

AWS_TEST_CASE(test_managed_thread_join_timeout, s_test_managed_thread_join_timeout)