1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
3  */
4 /*
5  * Copyright (c) 2022 Huawei Device Co., Ltd.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include <signal.h>
20 #include <stdlib.h>
21 #include <threads.h>
22 #include <pthread.h>
23 #include <stdio.h>
24 #include <time.h>
25 #include <errno.h>
26 #include "test.h"
27 
28 #define LOCK_SUCCESS (0)
29 #define LOCK_TIMEOUT (-1)
30 #define LOCK_WAIT_MAX_TIME_COUNT (50)
31 #define NSEC_TO_MS (1000000)
32 #define TRYLOCK_FAIL (-2)
33 
34 static thrd_t thr;
35 static int count = 0;
36 pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
37 
TrylockWithTimeout(pthread_mutex_t *mutex)38 int TrylockWithTimeout(pthread_mutex_t *mutex)
39 {
40     int rc;
41 
42     int sleepCount = 0;
43 
44     do {
45         rc = pthread_mutex_trylock(mutex);
46         if (rc == 0) {
47             return LOCK_SUCCESS;
48         } else if (rc != EBUSY) {
49             perror("pthread_mutex_trylock");
50             return TRYLOCK_FAIL;
51         }
52 
53         struct timespec req = { .tv_sec = 0, .tv_nsec = NSEC_TO_MS * 10 }; // 等待10毫秒
54         nanosleep(&req, NULL);
55 
56         sleepCount++;
57         if (sleepCount >= LOCK_WAIT_MAX_TIME_COUNT) {
58             return LOCK_TIMEOUT;
59         }
60     } while (1);
61 }
62 
threadfuncA(void *arg)63 int threadfuncA(void *arg)
64 {
65     pthread_mutex_t *mtx = (pthread_mutex_t *)arg;
66     pthread_mutex_lock(mtx);
67     count++;
68     thrd_t id = thrd_current();
69     if (!(thrd_equal(id, thr))) {
70         t_error("%s thrd_current failed", __func__);
71     }
72     pthread_mutex_unlock(mtx);
73     thrd_exit(thrd_success);
74 }
75 
threadfuncB(void *arg)76 int threadfuncB(void *arg)
77 {
78     int result = TrylockWithTimeout(&g_mutex);
79     if (result == LOCK_SUCCESS) {
80         count++;
81         pthread_mutex_unlock(&g_mutex);
82     } else if (result == LOCK_TIMEOUT) {
83         t_error("Lock acquisition timed out.\n");
84     } else {
85         t_error("Error pthread_mutex_trylock.\n");
86     }
87 
88     thrd_exit(thrd_success);
89 }
90 
91 /**
92  * @tc.name      : thrd_equal_0100
93  * @tc.desc      : Test that two threads have the same ID
94  * @tc.level     : Level 0
95  */
thrd_equal_0100(void)96 void thrd_equal_0100(void)
97 {
98     int result;
99     pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
100     pthread_mutex_lock(&mtx);
101     result = thrd_create(&thr, threadfuncA, (void *)&mtx);
102     pthread_mutex_unlock(&mtx);
103     pthread_mutex_destroy(&mtx);
104     if (result != thrd_success) {
105         t_error("%s thrd_create failed", __func__);
106     }
107 
108     result = thrd_sleep(&(struct timespec){.tv_sec = 1}, NULL);
109     if (result != 0) {
110         t_error("%s thrd_sleep failed", __func__);
111     }
112 
113     result = thrd_join(thr, NULL);
114     if (result != thrd_success) {
115         t_error("%s thrd_join failed", __func__);
116     }
117 
118     if (count != 1) {
119         t_error("%s failed, count is %d", __func__, count);
120     }
121     count = 0;
122 }
123 
124 /**
125  * @tc.name      : thrd_equal_0200
126  * @tc.desc      : Test that two threads have different ID
127  * @tc.level     : Level 1
128  */
thrd_equal_0200(void)129 void thrd_equal_0200(void)
130 {
131     thrd_t thr1, thr2;
132     int result;
133 
134     result = thrd_create(&thr1, threadfuncB, NULL);
135     if (result != thrd_success) {
136         t_error("%s thrd_create failed", __func__);
137     }
138 
139     result = thrd_create(&thr2, threadfuncB, NULL);
140     if (result != thrd_success) {
141         t_error("%s thrd_create failed", __func__);
142     }
143 
144     result = thrd_sleep(&(struct timespec){.tv_sec = 1}, NULL);
145     if (result != 0) {
146         t_error("%s thrd_sleep failed", __func__);
147     }
148 
149     if (thrd_equal(thr1, thr2)) {
150         t_error("%s failed, thr1 and thr2 equal", __func__);
151     }
152 
153     if (thrd_equal(thr1, thrd_current())) {
154         t_error("%s failed, thr1 and current thread equal", __func__);
155     }
156 
157     if (thrd_equal(thr2, thrd_current())) {
158         t_error("%s failed, thr2 and current thread equal", __func__);
159     }
160 
161     result = thrd_join(thr1, NULL);
162     if (result != thrd_success) {
163         t_error("%s thrd_join failed", __func__);
164     }
165 
166     result = thrd_join(thr2, NULL);
167     if (result != thrd_success) {
168         t_error("%s thrd_join failed", __func__);
169     }
170 
171     if (count != 2) {
172         t_error("%s failed, count is %d", __func__, count);
173     }
174     count = 0;
175 }
176 
main(int argc, char *argv[])177 int main(int argc, char *argv[])
178 {
179     thrd_equal_0100();
180     thrd_equal_0200();
181     return t_status;
182 }