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 <semaphore.h>
19#include <pthread.h>
20#include <gtest/gtest.h>
21#include "utils.h"
22#include "log.h"
23
24using namespace testing::ext;
25
26static const unsigned int KERNEL_NS_PER_SECOND = 1000000000;
27static const unsigned int KERNEL_100MS_BY_NS = 100000000;
28
29class SemTest : public::testing::Test {
30};
31
32/**
33 * @tc.number   SUB_KERNEL_IPC_SEM_INIT_0100
34 * @tc.name     Use sem_init initialize the semaphore with 0
35 * @tc.desc     [C- SOFTWARE -0200]
36 */
37HWTEST_F(SemTest, testSemInitA, Function | MediumTest | Level2)
38{
39    sem_t sem;
40    int semValue = 0;
41    int testValue = 0;
42
43    EXPECT_NE(sem_init(&sem, 0, testValue), -1) << "> sem_init errno = " << errno;
44    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "> sem_getvalue errno = " << errno;
45    EXPECT_TRUE(semValue == testValue);
46    EXPECT_EQ(sem_destroy(&sem), 0) << "> sem_destroy errno = " << errno;
47}
48
49/**
50 * @tc.number   SUB_KERNEL_IPC_SEM_INIT_0110
51 * @tc.name     Use sem_init initialize the semaphore with 1
52 * @tc.desc     [C- SOFTWARE -0200]
53 */
54HWTEST_F(SemTest, testSemInitB, Function | MediumTest | Level2)
55{
56    sem_t sem;
57    int semValue = 0;
58    int testValue = 1;
59
60    EXPECT_NE(sem_init(&sem, 0, testValue), -1) << "> sem_init errno = " << errno;
61    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "> sem_getvalue errno = " << errno;
62    EXPECT_EQ(semValue, testValue);
63    EXPECT_EQ(sem_destroy(&sem), 0) << "> sem_destroy errno = " << errno;
64}
65
66/**
67 * @tc.number   SUB_KERNEL_IPC_SEM_INIT_0120
68 * @tc.name     Use sem_init initialize the semaphore with 100
69 * @tc.desc     [C- SOFTWARE -0200]
70 */
71HWTEST_F(SemTest, testSemInitC, Function | MediumTest | Level2)
72{
73    sem_t sem;
74    int semValue = 0;
75    int testValue = 10;
76
77    EXPECT_NE(sem_init(&sem, 0, testValue), -1) << "> sem_init errno = " << errno;
78    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "> sem_getvalue errno = " << errno;
79    EXPECT_EQ(semValue, testValue);
80    EXPECT_EQ(sem_destroy(&sem), 0) << "> sem_destroy errno = " << errno;
81}
82
83/**
84 * @tc.number   SUB_KERNEL_IPC_SEM_POST_0100
85 * @tc.name     sem_post increases the semaphore count
86 * @tc.desc     [C- SOFTWARE -0200]
87 */
88HWTEST_F(SemTest, testSemPost, Function | MediumTest | Level2)
89{
90    sem_t sem;
91    int semValue = 0;
92
93    ASSERT_NE(sem_init(&sem, 0, 0), -1) << "> sem_init errno = " << errno;
94    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "> sem_getvalue errno = " << errno;
95    EXPECT_EQ(semValue, 0);
96
97    EXPECT_EQ(sem_post(&sem), 0) << "> sem_post errno = " << errno;
98    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "> sem_getvalue errno = " << errno;
99    EXPECT_EQ(semValue, 1);
100
101    EXPECT_EQ(sem_post(&sem), 0) << "> sem_post errno = " << errno;
102    EXPECT_EQ(sem_post(&sem), 0) << "> sem_post errno = " << errno;
103    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "> sem_getvalue errno = " << errno;
104    EXPECT_EQ(semValue, 3);
105
106    EXPECT_EQ(sem_destroy(&sem), 0) << "> sem_destroy errno = " << errno;
107}
108
109/**
110 * @tc.number   SUB_KERNEL_IPC_SEM_WAIT_0100
111 * @tc.name     sem_wait get semaphore
112 * @tc.desc     [C- SOFTWARE -0200]
113 */
114HWTEST_F(SemTest, testSemWait, Function | MediumTest | Level2)
115{
116    sem_t sem;
117    int semValue = 0;
118
119    ASSERT_NE(sem_init(&sem, 0, 3), -1) << "> sem_init errno = " << errno;
120    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "> sem_getvalue errno = " << errno;
121    EXPECT_EQ(semValue, 3);
122
123    EXPECT_EQ(sem_wait(&sem), 0) << "> sem_wait errno = " << errno;
124    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "> sem_getvalue errno = " << errno;
125    EXPECT_EQ(semValue, 2);
126
127    EXPECT_EQ(sem_wait(&sem), 0) << "> sem_wait errno = " << errno;
128    EXPECT_EQ(sem_wait(&sem), 0) << "> sem_wait errno = " << errno;
129    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "> sem_getvalue errno = " << errno;
130    EXPECT_EQ(semValue, 0);
131
132    EXPECT_EQ(sem_destroy(&sem), 0) << "> sem_destroy errno = " << errno;
133}
134
135/**
136 * @tc.number   SUB_KERNEL_IPC_SEM_TRYWAIT_0100
137 * @tc.name     sem_trywait get semaphore
138 * @tc.desc     [C- SOFTWARE -0200]
139 */
140HWTEST_F(SemTest, testSemTryWait, Function | MediumTest | Level2)
141{
142    sem_t sem;
143    int semValue = 0;
144
145    ASSERT_NE(sem_init(&sem, 0, 3), -1) << "> sem_init errno = " << errno;
146    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "> sem_getvalue errno = " << errno;
147    EXPECT_EQ(semValue, 3);
148
149    EXPECT_EQ(sem_trywait(&sem), 0) << "> sem_trywait errno = " << errno;
150    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "> sem_getvalue errno = " << errno;
151    EXPECT_EQ(semValue, 2);
152
153    EXPECT_EQ(sem_trywait(&sem), 0) << "> sem_trywait errno = " << errno;
154    EXPECT_EQ(sem_trywait(&sem), 0) << "> sem_trywait errno = " << errno;
155    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "> sem_getvalue errno = " << errno;
156    EXPECT_EQ(semValue, 0);
157    EXPECT_EQ(sem_destroy(&sem), 0) << "> sem_destroy errno = " << errno;
158}
159
160/**
161 * @tc.number   SUB_KERNEL_IPC_SEM_DESTROY_0100
162 * @tc.name     check sem_destroy function
163 * @tc.desc     [C- SOFTWARE -0200]
164 */
165HWTEST_F(SemTest, testSemdestroy, Function | MediumTest | Level3)
166{
167    sem_t sem;
168    ASSERT_EQ(sem_init(&sem, 0, 0), 0) << "> sem_init errno = " << errno;
169    EXPECT_EQ(sem_destroy(&sem), 0) << "> sem_destroy errno = " << errno;
170}
171
172void *ThreadChat(void *arg)
173{
174    sem_t *sem = (sem_t*)arg;
175    int semValue = 0;
176
177    EXPECT_EQ(sem_getvalue(sem, &semValue), 0) << "sem_getvalue errno = " << errno;
178    EXPECT_EQ(semValue, 0);
179    EXPECT_EQ(sem_wait(sem), 0) << "sem_wait errno = " << errno;
180    return nullptr;
181}
182
183/**
184 * @tc.number   SUB_KERNEL_IPC_SEM_CHAT_0100
185 * @tc.name     Inter-thread communication, check sem_wait function
186 * @tc.desc     [C- SOFTWARE -0200]
187 */
188HWTEST_F(SemTest, testThreadChat, Function | MediumTest | Level3)
189{
190    pthread_t tid;
191    sem_t sem;
192    int reInt = 0;
193    int semValue = 0;
194
195    ASSERT_EQ(sem_init(&sem, 0, 0), 0) << "> sem_init errno = " << errno;
196
197    reInt = pthread_create(&tid, nullptr, ThreadChat, (void*)&sem);
198    ASSERT_EQ(reInt, 0) << "> pthread_create errno, reInt = " << reInt;
199
200    Msleep(20);
201    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "> sem_getvalue errno = " << errno;
202    EXPECT_EQ(semValue, 0);
203
204    EXPECT_EQ(sem_post(&sem), 0) << "sem_post errno = " << errno;
205    EXPECT_EQ(sem_post(&sem), 0) << "sem_post errno = " << errno;
206
207    Msleep(20);
208    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "> sem_getvalue errno = " << errno;
209    EXPECT_EQ(semValue, 1);
210
211    reInt = pthread_join(tid, nullptr);
212    EXPECT_EQ(reInt, 0) << "pthread_join failed, errno=" << reInt;
213    EXPECT_EQ(sem_destroy(&sem), 0) << "> sem_destroy errno = " << errno;
214}
215
216void *ThreadSemTryWait(void *arg)
217{
218    sem_t *sem = (sem_t*)arg;
219    int semValue = 0;
220    int loop = 10;
221
222    EXPECT_EQ(sem_getvalue(sem, &semValue), 0) << "sem_getvalue errno = " << errno;
223    EXPECT_EQ(semValue, 0);
224    for (int i = 0; i < loop; i++) {
225        if (sem_trywait(sem) == 0) {
226            break;
227
228        }
229        Msleep(10);
230    }
231    return nullptr;
232}
233
234/**
235 * @tc.number   SUB_KERNEL_IPC_SEM_CHAT_0200
236 * @tc.name     basic function test : Inter-thread communication, check sem_trywait function
237 * @tc.desc     [C- SOFTWARE -0200]
238 */
239HWTEST_F(SemTest, testThreadSemTryWait, Function | MediumTest | Level3)
240{
241    sem_t sem;
242    int reInt = 0;
243    int semValue = 0;
244
245    ASSERT_EQ(sem_init(&sem, 0, 0), 0) << "> sem_init errno = " << errno;
246
247    pthread_t tid;
248    reInt = pthread_create(&tid, nullptr, ThreadSemTryWait, (void*)&sem);
249    ASSERT_EQ(reInt, 0) << "> pthread_create errno, reInt = " << reInt;
250
251    Msleep(20);
252    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "> sem_getvalue errno = " << errno;
253    EXPECT_EQ(semValue, 0);
254
255    EXPECT_EQ(sem_post(&sem), 0) << "sem_post errno = " << errno;
256    EXPECT_EQ(sem_post(&sem), 0) << "sem_post errno = " << errno;
257
258    reInt = pthread_join(tid, nullptr);
259    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "> sem_getvalue errno = " << errno;
260
261    if (semValue == 1 || semValue == 2) {
262        EXPECT_TRUE(true);
263        LOG("semValue = %d", semValue);
264    } else {
265        EXPECT_TRUE(false);
266        LOG("semValue errno, semValue = %d", semValue);
267    }
268
269    EXPECT_EQ(reInt, 0) << "pthread_join failed, errno=" << reInt;
270    EXPECT_EQ(sem_destroy(&sem), 0) << "> sem_destroy errno = " << errno;
271}
272
273void *ThreadSemTimedWait(void *arg)
274{
275    struct timespec ts = {0};
276    sem_t *sem = (sem_t*)arg;
277    int semValue = 0;
278
279    EXPECT_EQ(sem_getvalue(sem, &semValue), 0) << "sem_getvalue errno = " << errno;
280    EXPECT_EQ(semValue, 0);
281
282    clock_gettime(CLOCK_REALTIME, &ts);
283    ts.tv_sec = ts.tv_sec + (ts.tv_nsec + KERNEL_100MS_BY_NS) / KERNEL_NS_PER_SECOND;
284    ts.tv_nsec = (ts.tv_nsec + KERNEL_100MS_BY_NS) % KERNEL_NS_PER_SECOND;
285    Msleep(50);
286    EXPECT_EQ(sem_timedwait(sem, &ts), 0) << "sem_timedwait errno = " << errno;
287    EXPECT_EQ(sem_getvalue(sem, &semValue), 0) << "sem_getvalue errno = " << errno;
288
289    Msleep(100);
290    EXPECT_EQ(semValue, 1);
291    return nullptr;
292}
293
294/**
295 * @tc.number   SUB_KERNEL_IPC_SEM_CHAT_0300
296 * @tc.name     Inter-thread communication, check sem_timedwait function
297 * @tc.desc     [C- SOFTWARE -0200]
298 */
299HWTEST_F(SemTest, testThreadSemTimedWait, Function | MediumTest | Level3)
300{
301    pthread_t tid;
302    sem_t sem;
303    int reInt = 0;
304    int semValue = 0;
305
306    ASSERT_EQ(sem_init(&sem, 0, 0), 0) << "> sem_init errno = " << errno;
307
308    reInt = pthread_create(&tid, nullptr, ThreadSemTimedWait, (void*)&sem);
309    ASSERT_EQ(reInt, 0) << "> pthread_create errno, reInt = " << reInt;
310
311    Msleep(10);
312    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "> sem_getvalue errno = " << errno;
313    EXPECT_EQ(semValue, 0);
314    EXPECT_EQ(sem_post(&sem), 0) << "> sem_post errno = " << errno;
315    EXPECT_EQ(sem_post(&sem), 0) << "> sem_post errno = " << errno;
316
317    reInt = pthread_join(tid, nullptr);
318    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "> sem_getvalue errno = " << errno;
319    EXPECT_EQ(semValue, 1);
320    EXPECT_EQ(reInt, 0) << "pthread_join failed, errno=" << reInt;
321    EXPECT_EQ(sem_destroy(&sem), 0) << "> sem_destroy errno = " << errno;
322}
323
324void *ThreadNThreadWait1(void *arg)
325{
326    sem_t *sem = (sem_t*)arg;
327    int semValue = 0;
328
329    Msleep(100);
330    EXPECT_EQ(sem_getvalue(sem, &semValue), 0) << "sem_getvalue errno = " << errno;
331    EXPECT_EQ(semValue, 0);
332    EXPECT_EQ(sem_wait(sem), 0) << "sem_wait errno = " << errno;
333    return nullptr;
334}
335
336void *ThreadNThreadWait2(void *arg)
337{
338    sem_t *sem = (sem_t*)arg;
339    int semValue = 0;
340    EXPECT_EQ(sem_getvalue(sem, &semValue), 0) << "sem_getvalue errno = " << errno;
341    EXPECT_EQ(semValue, 0);
342
343    Msleep(300);
344    EXPECT_EQ(sem_getvalue(sem, &semValue), 0) << "sem_getvalue errno = " << errno;
345    EXPECT_EQ(semValue, 0);
346
347    Msleep(200);
348    EXPECT_EQ(sem_getvalue(sem, &semValue), 0) << "sem_getvalue errno = " << errno;
349    EXPECT_EQ(semValue, 1);
350    EXPECT_EQ(sem_wait(sem), 0) << "sem_wait errno = " << errno;
351    return nullptr;
352}
353
354/**
355 * @tc.number   SUB_KERNEL_IPC_SEM_CHAT_0400
356 * @tc.name     N threads wait, main thread post
357 * @tc.desc     [C- SOFTWARE -0200]
358 */
359HWTEST_F(SemTest, testNThreadWait, Function | MediumTest | Level4)
360{
361    pthread_t tid1;
362    pthread_t tid2;
363    sem_t sem;
364    int reInt = 0;
365    int semValue = 0;
366
367    ASSERT_EQ(sem_init(&sem, 0, 0), 0) << "> sem_init errno = " << errno;
368
369    reInt = pthread_create(&tid1, nullptr, ThreadNThreadWait1, (void*)&sem);
370    ASSERT_EQ(reInt, 0) << "> pthread_create errno, reInt = " << reInt;
371
372    reInt = pthread_create(&tid2, nullptr, ThreadNThreadWait2, (void*)&sem);
373    ASSERT_EQ(reInt, 0) << "> pthread_create errno, reInt = " << reInt;
374
375    Msleep(200);
376    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "sem_getvalue errno = " << errno;
377    EXPECT_EQ(semValue, 0);
378    EXPECT_EQ(sem_post(&sem), 0) << "sem_post errno = " << errno;
379
380    Msleep(20);
381    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "sem_getvalue errno = " << errno;
382    EXPECT_EQ(semValue, 0);
383
384    Msleep(200);
385    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "sem_getvalue errno = " << errno;
386    EXPECT_EQ(semValue, 0);
387    EXPECT_EQ(sem_post(&sem), 0) << "sem_post errno = " << errno;
388
389    Msleep(20);
390    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "sem_getvalue errno = " << errno;
391    EXPECT_EQ(semValue, 1);
392
393    reInt = pthread_join(tid1, nullptr);
394    EXPECT_EQ(reInt, 0) << "pthread_join failed, errno=" << reInt;
395    reInt = pthread_join(tid2, nullptr);
396    EXPECT_EQ(reInt, 0) << "pthread_join failed, errno=" << reInt;
397    EXPECT_EQ(sem_destroy(&sem), 0) << "> sem_destroy errno = " << errno;
398}
399
400void *ThreadNThreadPost1(void *arg)
401{
402    sem_t *sem = (sem_t*)arg;
403    int semValue = 0;
404
405    Msleep(200);
406    EXPECT_EQ(sem_post(sem), 0) << "sem_post errno = " << errno;
407    Msleep(20);
408    EXPECT_EQ(sem_getvalue(sem, &semValue), 0) << "sem_getvalue errno = " << errno;
409    EXPECT_EQ(semValue, 0);
410    return nullptr;
411}
412
413void *ThreadNThreadPost2(void *arg)
414{
415    sem_t *sem = (sem_t*)arg;
416    int semValue = 0;
417
418    Msleep(300);
419    EXPECT_EQ(sem_post(sem), 0) << "sem_post errno = " << errno;
420    Msleep(20);
421    EXPECT_EQ(sem_getvalue(sem, &semValue), 0) << "sem_getvalue errno = " << errno;
422    EXPECT_EQ(semValue, 1);
423    return nullptr;
424}
425
426/**
427 * @tc.number   SUB_KERNEL_IPC_SEM_CHAT_0500
428 * @tc.name     N threads post, main thread wait
429 * @tc.desc     [C- SOFTWARE -0200]
430 */
431HWTEST_F(SemTest, testNThreadPost, Function | MediumTest | Level4)
432{
433    pthread_t tid1;
434    pthread_t tid2;
435    struct timespec ts = {0};
436    sem_t sem;
437    int reInt = 0;
438    int semValue = 0;
439
440    ASSERT_EQ(sem_init(&sem, 0, 0), 0) << "> sem_init errno = " << errno;
441
442    reInt = pthread_create(&tid1, nullptr, ThreadNThreadPost1, (void*)&sem);
443    ASSERT_EQ(reInt, 0) << "> pthread_create errno, reInt = " << reInt;
444
445    reInt = pthread_create(&tid2, nullptr, ThreadNThreadPost2, (void*)&sem);
446    ASSERT_EQ(reInt, 0) << "> pthread_create errno, reInt = " << reInt;
447
448    Msleep(100);
449    clock_gettime(CLOCK_REALTIME, &ts);
450    ts.tv_sec = ts.tv_sec + 1;
451    EXPECT_EQ(sem_timedwait(&sem, &ts), 0) << "> sem_timedwait errno = " << errno;
452
453    Msleep(400);
454    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "sem_getvalue errno = " << errno;
455    EXPECT_EQ(semValue, 1);
456    EXPECT_EQ(sem_trywait(&sem), 0) << "> sem_trywait errno = " << errno;
457    EXPECT_EQ(sem_getvalue(&sem, &semValue), 0) << "sem_getvalue errno = " << errno;
458    EXPECT_EQ(semValue, 0);
459
460    reInt = pthread_join(tid1, nullptr);
461    EXPECT_EQ(reInt, 0) << "pthread_join failed, errno=" << reInt;
462    reInt = pthread_join(tid2, nullptr);
463    EXPECT_EQ(reInt, 0) << "pthread_join failed, errno=" << reInt;
464    EXPECT_EQ(sem_destroy(&sem), 0) << "> sem_destroy errno = " << errno;
465}
466