1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include <stdio.h>
16#include <string.h>
17#include <limits.h>
18#include <pthread.h>
19#include <gtest/gtest.h>
20#include "utils.h"
21#include "log.h"
22#include "KernelConstants.h"
23#include "FutexTest.h"
24#include "mt_utils.h"
25
26using namespace testing::ext;
27
28/**
29 * @tc.number   SUB_KERNEL_PTHREAD_COND_INIT_0100
30 * @tc.name     pthread_cond_init initializes condition variables
31 * @tc.desc     [C- SOFTWARE -0200]
32 */
33HWTEST_F(FutexTest, testPthreadCondInit, Function | MediumTest | Level2)
34{
35    pthread_condattr_t condattr;
36    EXPECT_EQ(pthread_condattr_init(&condattr), 0);
37    pthread_cond_t cond1;
38    EXPECT_EQ(pthread_cond_init(&cond1, &condattr), 0);
39
40    pthread_cond_t cond2;
41    EXPECT_EQ(pthread_cond_init(&cond2, nullptr), 0);
42}
43
44/**
45 * @tc.number   SUB_KERNEL_PTHREAD_COND_DESTROY_0100
46 * @tc.name     pthread_cond_destroy destroy condition variables
47 * @tc.desc     [C- SOFTWARE -0200]
48 */
49HWTEST_F(FutexTest, testPthreadCondDestroy, Function | MediumTest | Level3)
50{
51    pthread_condattr_t condattr;
52    EXPECT_EQ(pthread_condattr_init(&condattr), 0);
53    pthread_cond_t cond1;
54    EXPECT_EQ(pthread_cond_init(&cond1, &condattr), 0);
55    EXPECT_EQ(pthread_cond_destroy(&cond1), 0);
56
57    pthread_cond_t cond2;
58    EXPECT_EQ(pthread_cond_init(&cond2, nullptr), 0);
59    EXPECT_EQ(pthread_cond_destroy(&cond2), 0);
60
61    pthread_cond_t cond3 = PTHREAD_COND_INITIALIZER;
62    EXPECT_EQ(pthread_cond_destroy(&cond3), 0);
63}
64
65/**
66 * @tc.number   SUB_KERNEL_PTHREAD_CONDATTR_INIT_0100
67 * @tc.name     Init and destroy operations
68 * @tc.desc     [C- SOFTWARE -0200]
69 */
70HWTEST_F(FutexTest, testPthreadCondattrInit, Function | MediumTest | Level2)
71{
72    pthread_condattr_t condattr;
73
74    EXPECT_EQ(pthread_condattr_init(&condattr), 0) << "> return errno";
75    EXPECT_EQ(pthread_condattr_destroy(&condattr), 0) << "> return errno";
76    EXPECT_EQ(pthread_condattr_init(&condattr), 0) << "> return errno";
77}
78
79/**
80 * @tc.number   SUB_KERNEL_PTHREAD_CONDATTR_SETCLOCK_0100
81 * @tc.name     Set and get the clock selection variable properties of the condition variable properties
82 * @tc.desc     [C- SOFTWARE -0200]
83 */
84HWTEST_F(FutexTest, testPthreadCondattrSetclock, Function | MediumTest | Level3)
85{
86    clockid_t clk;
87    const int invalidClock = -100;
88    pthread_condattr_t condattr;
89    EXPECT_EQ(pthread_condattr_init(&condattr), 0);
90
91    // default
92    EXPECT_EQ(pthread_condattr_getclock(&condattr, &clk), 0) << "> return errno";
93    EXPECT_EQ(clk, DEF_PROCESS_CONDATTR_CLOCK);
94
95    EXPECT_EQ(pthread_condattr_setclock(&condattr, CLOCK_REALTIME), 0) << "> return errno";
96    EXPECT_EQ(pthread_condattr_getclock(&condattr, &clk), 0) << "> return errno";
97    EXPECT_EQ(clk, CLOCK_REALTIME);
98
99    struct timespec ts = {0};
100    EXPECT_EQ(clock_getres(CLOCK_MONOTONIC, &ts), 0) << "> return errno";
101    EXPECT_EQ(pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC), 0) << "> return errno";
102    EXPECT_EQ(pthread_condattr_getclock(&condattr, &clk), 0) << "> return errno";
103    EXPECT_EQ(clk, CLOCK_MONOTONIC);
104
105    EXPECT_EQ(pthread_condattr_setclock(&condattr, invalidClock), EINVAL) << "> return errno";
106}
107
108pthread_mutex_t g_mtx1 = PTHREAD_MUTEX_INITIALIZER;
109pthread_cond_t g_cond1 = PTHREAD_COND_INITIALIZER;
110
111// pthread_cond_signal
112void *ThreadPthreadCondSignalBefore1(void *arg)
113{
114    Msleep(20);
115    EXPECT_EQ(pthread_mutex_lock(&g_mtx1), 0);
116    LOG("step = %lx", CheckStep(2));
117    EXPECT_EQ(pthread_cond_signal(&g_cond1), 0);
118    LOG("step = %lx", CheckStep(3));
119    EXPECT_EQ(pthread_mutex_unlock(&g_mtx1), 0);
120    return arg;
121}
122
123// pthread_cond_wait
124void *ThreadPthreadCondSignalBefore2(void *arg)
125{
126    EXPECT_EQ(pthread_mutex_lock(&g_mtx1), 0);
127    EXPECT_EQ(pthread_cond_wait(&g_cond1, &g_mtx1), 0);
128    LOG("step = %lx", CheckStep(4));
129    EXPECT_EQ(pthread_mutex_unlock(&g_mtx1), 0);
130    return arg;
131}
132
133/**
134 * @tc.number   SUB_KERNEL_PTHREAD_COND_SIGNAL_0100
135 * @tc.name     Use pthread_cond_signal to release the conditional semaphore, pthread_cond_signal front
136 * @tc.desc     [C- SOFTWARE -0200]
137 */
138HWTEST_F(FutexTest, testPthreadCondSignalBefore, Function | MediumTest | Level3)
139{
140    pthread_t tid[2];
141    LOG("step = %lx", CheckStep(1));
142
143    ASSERT_EQ(pthread_create(&tid[0], nullptr, ThreadPthreadCondSignalBefore1, nullptr), 0) << "> return errno";
144    ASSERT_EQ(pthread_create(&tid[1], nullptr, ThreadPthreadCondSignalBefore2, nullptr), 0) << "> return errno";
145
146    Msleep(100);
147    pthread_join(tid[0], nullptr);
148    pthread_join(tid[1], nullptr);
149    EXPECT_EQ(pthread_cond_destroy(&g_cond1), 0);
150    EXPECT_EQ(pthread_mutex_destroy(&g_mtx1), 0);
151    EXPECT_EQ(CheckStep(5), (uint64_t)0x12345);
152}
153
154pthread_mutex_t g_mtx2 = PTHREAD_MUTEX_INITIALIZER;
155pthread_cond_t g_cond2 = PTHREAD_COND_INITIALIZER;
156
157// pthread_cond_signal
158void *ThreadTestCondSignalWaitAfter1(void *arg)
159{
160    Msleep(20);
161    EXPECT_EQ(pthread_mutex_lock(&g_mtx2), 0);
162    LOG("step = %lx", CheckStep(2));
163    EXPECT_EQ(pthread_mutex_unlock(&g_mtx2), 0);
164    EXPECT_EQ(pthread_cond_signal(&g_cond2), 0);
165    return arg;
166}
167
168// pthread_cond_wait
169void *ThreadTestCondSignalWaitAfter2(void *arg)
170{
171    EXPECT_EQ(pthread_mutex_lock(&g_mtx2), 0);
172    EXPECT_EQ(pthread_cond_wait(&g_cond2, &g_mtx2), 0);
173    LOG("step = %lx", CheckStep(3));
174    EXPECT_EQ(pthread_mutex_unlock(&g_mtx2), 0);
175    return arg;
176}
177
178/**
179 * @tc.number   SUB_KERNEL_PTHREAD_COND_SIGNAL_0200
180 * @tc.name     Use pthread_cond_signal to release the conditional semaphore, pthread_cond_signal in the back
181 * @tc.desc     [C- SOFTWARE -0200]
182 */
183HWTEST_F(FutexTest, testPthreadCondSignalAfter, Function | MediumTest | Level3)
184{
185    pthread_t tid[2];
186    LOG("step = %lx", CheckStep(1));
187
188    ASSERT_EQ(pthread_create(&tid[0], nullptr, ThreadTestCondSignalWaitAfter1, nullptr), 0) << "> return errno";
189    ASSERT_EQ(pthread_create(&tid[1], nullptr, ThreadTestCondSignalWaitAfter2, nullptr), 0) << "> return errno";
190
191    Msleep(100);
192    pthread_join(tid[0], nullptr);
193    pthread_join(tid[1], nullptr);
194    EXPECT_EQ(pthread_cond_destroy(&g_cond2), 0);
195    EXPECT_EQ(pthread_mutex_destroy(&g_mtx2), 0);
196    EXPECT_EQ(CheckStep(4), (uint64_t)0x1234);
197}
198
199pthread_mutex_t g_mtx3 = PTHREAD_MUTEX_INITIALIZER;
200pthread_cond_t g_cond3 = PTHREAD_COND_INITIALIZER;
201
202// pthread_cond_broadcast
203void *ThreadPthreadCondBroadcast1(void *arg)
204{
205    int *testIntP = (int *)arg;
206    Msleep(20);
207    EXPECT_EQ(pthread_mutex_lock(&g_mtx3), 0);
208    *testIntP = 10;
209    EXPECT_EQ(pthread_cond_broadcast(&g_cond3), 0);
210    EXPECT_EQ(pthread_mutex_unlock(&g_mtx3), 0);
211    return arg;
212}
213
214// pthread_cond_wait
215void *ThreadPthreadCondBroadcast2(void *arg)
216{
217    int *testIntP = (int *)arg;
218    EXPECT_EQ(pthread_mutex_lock(&g_mtx3), 0);
219    EXPECT_EQ(pthread_cond_wait(&g_cond3, &g_mtx3), 0);
220    (*testIntP)++;
221    EXPECT_EQ(pthread_mutex_unlock(&g_mtx3), 0);
222    return arg;
223}
224
225/**
226 * @tc.number   SUB_KERNEL_PTHREAD_COND_BROADCAST_0100
227 * @tc.name     Use pthread_cond_broadcast to release conditional semaphore
228 * @tc.desc     [C- SOFTWARE -0200]
229 */
230HWTEST_F(FutexTest, testPthreadCondBroadcast, Function | MediumTest | Level3)
231{
232    pthread_t tid[3];
233    int testInt = 0;
234
235    ASSERT_EQ(pthread_create(&tid[0], nullptr, ThreadPthreadCondBroadcast1, (void*)&testInt), 0) << "> return errno";
236    ASSERT_EQ(pthread_create(&tid[1], nullptr, ThreadPthreadCondBroadcast2, (void*)&testInt), 0) << "> return errno";
237    ASSERT_EQ(pthread_create(&tid[2], nullptr, ThreadPthreadCondBroadcast2, (void*)&testInt), 0) << "> return errno";
238
239    Msleep(100);
240    pthread_join(tid[0], nullptr);
241    pthread_join(tid[1], nullptr);
242    pthread_join(tid[2], nullptr);
243    EXPECT_EQ(pthread_cond_destroy(&g_cond3), 0);
244    EXPECT_EQ(pthread_mutex_destroy(&g_mtx3), 0);
245    EXPECT_EQ(testInt, 12);
246}
247
248pthread_mutex_t g_mtx4 = PTHREAD_MUTEX_INITIALIZER;
249pthread_cond_t g_cond4 = PTHREAD_COND_INITIALIZER;
250
251// pthread_cond_signal
252void *ThreadPthreadCondTimedwait1(void *arg)
253{
254    Msleep(50);
255    EXPECT_EQ(pthread_mutex_lock(&g_mtx4), 0);
256    LOG("step = %lx", CheckStep(2));
257    EXPECT_EQ(pthread_mutex_unlock(&g_mtx4), 0);
258    EXPECT_EQ(pthread_cond_signal(&g_cond4), 0);
259    return arg;
260}
261
262// pthread_cond_timedwait
263void *ThreadPthreadCondTimedwait2(void *arg)
264{
265    const unsigned int nsecPerSec = 1000000000;
266    const unsigned int nsecPer100Ms = 100000000;
267    struct timespec ts = {0};
268    EXPECT_EQ(pthread_mutex_lock(&g_mtx4), 0);
269
270    clock_gettime(CLOCK_REALTIME, &ts);
271    ts.tv_sec = ts.tv_sec + (ts.tv_nsec + nsecPer100Ms) / nsecPerSec;
272    ts.tv_nsec = (ts.tv_nsec + nsecPer100Ms) % nsecPerSec;
273
274    EXPECT_EQ(pthread_cond_timedwait(&g_cond4, &g_mtx4,  &ts), 0);
275    LOG("step = %lx", CheckStep(3));
276    EXPECT_EQ(pthread_mutex_unlock(&g_mtx4), 0);
277    return arg;
278}
279
280/**
281 * @tc.number   SUB_KERNEL_PTHREAD_COND_TIMEDWAIT_0100
282 * @tc.name     Use pthread_cond_timedwait to get conditional semaphore
283 * @tc.desc     [C- SOFTWARE -0200]
284 */
285HWTEST_F(FutexTest, testPthreadCondTimedwait, Function | MediumTest | Level3)
286{
287    pthread_t tid1;
288    pthread_t tid2;
289    LOG("step = %lx", CheckStep(1));
290
291    ASSERT_EQ(pthread_create(&tid1, nullptr, ThreadPthreadCondTimedwait1, nullptr), 0) << "> return errno";
292    ASSERT_EQ(pthread_create(&tid2, nullptr, ThreadPthreadCondTimedwait2, nullptr), 0) << "> return errno";
293
294    Msleep(100);
295    pthread_join(tid1, nullptr);
296    pthread_join(tid2, nullptr);
297    EXPECT_EQ(pthread_cond_destroy(&g_cond4), 0);
298    EXPECT_EQ(pthread_mutex_destroy(&g_mtx4), 0);
299    EXPECT_EQ(CheckStep(4), (uint64_t)0x1234);
300}
301
302pthread_mutex_t g_mtx5 = PTHREAD_MUTEX_INITIALIZER;
303pthread_cond_t g_cond5 = PTHREAD_COND_INITIALIZER;
304
305// pthread_cond_timedwait
306void *ThreadPthreadCondTimedwaitOut(void *arg)
307{
308    struct timespec ts = {0};
309    struct timespec tsNow = {0};
310    EXPECT_EQ(pthread_mutex_lock(&g_mtx5), 0);
311
312    GetDelayedTime(&ts, 100);
313    EXPECT_EQ(pthread_cond_timedwait(&g_cond5, &g_mtx5, &ts), ETIMEDOUT) << "> return should errno";
314    LOG("step = %lx", CheckStep(2));
315    clock_gettime(CLOCK_REALTIME, &tsNow);
316
317    int timeDiff = GetTimeDiff(tsNow, ts); // calculate time different
318    EXPECT_GE(timeDiff, 0);
319    EXPECT_LE(timeDiff, 20);
320
321    EXPECT_EQ(pthread_mutex_unlock(&g_mtx5), 0);
322    return arg;
323}
324
325/**
326 * @tc.number   SUB_KERNEL_PTHREAD_COND_TIMEDWAIT_0200
327 * @tc.name     Use pthread_cond_timedwait to time out time measurement
328 * @tc.desc     [C- SOFTWARE -0200]
329 */
330HWTEST_F(FutexTest, testPthreadCondTimedwaitOut, Function | MediumTest | Level3)
331{
332    pthread_t tid;
333    LOG("step = %lx", CheckStep(1));
334
335    ASSERT_EQ(pthread_create(&tid, nullptr, ThreadPthreadCondTimedwaitOut, nullptr), 0) << "> return errno";
336
337    Msleep(200);
338    pthread_join(tid, nullptr);
339    EXPECT_EQ(pthread_cond_destroy(&g_cond5), 0);
340    EXPECT_EQ(pthread_mutex_destroy(&g_mtx5), 0);
341    EXPECT_EQ(CheckStep(3), (uint64_t)0x123);
342}
343
344pthread_mutex_t g_mtx6 = PTHREAD_MUTEX_INITIALIZER;
345pthread_cond_t g_cond6 = PTHREAD_COND_INITIALIZER;
346
347// pthread_cond_timedwait
348void *ThreadPthreadCondTimedwaitEinval(void *arg)
349{
350    const long einvalNsec = 1000000000;
351    struct timespec ts = {0};
352    EXPECT_EQ(pthread_mutex_lock(&g_mtx6), 0);
353
354    ts.tv_sec = 1;
355    ts.tv_nsec = einvalNsec;
356    EXPECT_EQ(pthread_cond_timedwait(&g_cond6, &g_mtx6, &ts), EINVAL) << "> return should errno";
357    CheckStep(2);
358
359    EXPECT_EQ(pthread_mutex_unlock(&g_mtx6), 0);
360    return arg;
361}
362
363/**
364 * @tc.number   SUB_KERNEL_PTHREAD_COND_TIMEDWAIT_0300
365 * @tc.name     test pthread_cond_timedwait EINVAL
366 * @tc.desc     [C- SOFTWARE -0200]
367 */
368HWTEST_F(FutexTest, testPthreadCondTimedwaitEinval, Function | MediumTest | Level3)
369{
370    pthread_t tid;
371    CheckStep(1);
372
373    ASSERT_EQ(pthread_create(&tid, nullptr, ThreadPthreadCondTimedwaitEinval, nullptr), 0) << "> return errno";
374
375    Msleep(200);
376    pthread_join(tid, nullptr);
377    EXPECT_EQ(pthread_cond_destroy(&g_cond6), 0);
378    EXPECT_EQ(pthread_mutex_destroy(&g_mtx6), 0);
379    EXPECT_EQ(CheckStep(3), (uint64_t)0x123);
380}