1 /*
2  * Copyright (c) 2023 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 <climits>
16 #include <thread>
17 #include <cstdint>
18 #include <gtest/gtest.h>
19 
20 #include "param_atomic.h"
21 #include "param_common.h"
22 #include "param_utils.h"
23 
24 using namespace testing::ext;
25 const int THREAD_NUM = 5;
26 const int MAX_NUM = 10;
27 
28 namespace init_ut {
29 class AtomicUnitTest : public testing::Test {
30 public:
SetUpTestCase(void)31     static void SetUpTestCase(void) {};
TearDownTestCase(void)32     static void TearDownTestCase(void) {};
SetUp(void)33     void SetUp(void) {};
TearDown(void)34     void TearDown(void) {};
35 };
36 
37 /**
38  * 测试方法:
39  *  1,create 线程,执行全局变量写操作
40  *      store with dirty
41  *      sleep
42  *      store clear dirty
43  *      store commit ++
44  *  2,read 现成,执行全局变量读参数
45  *
46  */
47 using AtomicTestData = struct {
48     ATOMIC_UINT32 commitId;
49     uint32_t data;
50 };
51 
52 static AtomicTestData g_testData = { 0, 0 };
53 
TestSetData(void * args)54 static void *TestSetData(void *args)
55 {
56     while (g_testData.data < MAX_NUM) {
57         uint32_t commitId = ATOMIC_LOAD_EXPLICIT(&g_testData.commitId, MEMORY_ORDER_RELAXED);
58         ATOMIC_STORE_EXPLICIT(&g_testData.commitId, commitId | PARAM_FLAGS_MODIFY, MEMORY_ORDER_RELAXED);
59         g_testData.data++;
60         usleep(200 * 1000); // 200 * 1000 wait
61         printf("TestSetData data: %d commit: %d \n", g_testData.data, g_testData.commitId & PARAM_FLAGS_COMMITID);
62         uint32_t flags = commitId & ~PARAM_FLAGS_COMMITID;
63         ATOMIC_STORE_EXPLICIT(&g_testData.commitId, (++commitId) | flags, MEMORY_ORDER_RELEASE);
64         futex_wake(&g_testData.commitId, INT_MAX);
65         usleep(100); // 100 wait
66     }
67     return nullptr;
68 }
69 
TestReadCommitId(AtomicTestData * entry)70 static inline uint32_t TestReadCommitId(AtomicTestData *entry)
71 {
72     uint32_t commitId = ATOMIC_LOAD_EXPLICIT(&entry->commitId, MEMORY_ORDER_ACQUIRE);
73     while (commitId & PARAM_FLAGS_MODIFY) {
74         futex_wait(&entry->commitId, commitId);
75         commitId = ATOMIC_LOAD_EXPLICIT(&entry->commitId, MEMORY_ORDER_ACQUIRE);
76     }
77     return commitId & PARAM_FLAGS_COMMITID;
78 }
79 
TestReadParamValue(AtomicTestData * entry,uint32_t * commitId)80 static inline int TestReadParamValue(AtomicTestData *entry, uint32_t *commitId)
81 {
82     uint32_t data;
83     uint32_t id = *commitId;
84     do {
85         *commitId = id;
86         data = entry->data;
87         id = TestReadCommitId(entry);
88     } while (*commitId != id); // if change, must read
89     return data;
90 }
91 
TestReadData(void * args)92 static void *TestReadData(void *args)
93 {
94     uint32_t data = 0;
95     while (data < MAX_NUM) {
96         uint32_t commitId = TestReadCommitId(&g_testData);
97         data = TestReadParamValue(&g_testData, &commitId);
98         printf("[ %d] TestReadData data: %d commit: %d \n", gettid(), data, commitId);
99         usleep(10); // 10 wait
100     }
101     return nullptr;
102 }
103 
104 HWTEST_F(AtomicUnitTest, Init_AtomicUnitTest_001, TestSize.Level0)
105 {
106     printf("AtomicUnitTest_001 \n");
107     pthread_t writeThread = 0;
108     pthread_t readThread[THREAD_NUM] = { 0 };
109     pthread_create(&writeThread, nullptr, TestSetData, nullptr);
110     for (size_t i = 0; i < THREAD_NUM; i++) {
111         pthread_create(&readThread[i], nullptr, TestReadData, nullptr);
112     }
113     pthread_join(writeThread, nullptr);
114     printf("AtomicUnitTest_001 end \n");
115 }
116 }