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
16#include <unistd.h>
17#include <pthread.h>
18#include <semaphore.h>
19#include <sys/resource.h>
20#include <gtest/gtest.h>
21#include "log.h"
22#include "utils.h"
23#include "mt_utils.h"
24#include "KernelConstants.h"
25
26using namespace testing::ext;
27// global variables used to communicate between threads
28static int g_policy = 0;
29static int g_prioriy = 0;
30
31class PthreadSchedApiTest : public testing::Test {
32};
33class PthreadAllPrioTest : public testing::TestWithParam<int> {
34};
35
36/**
37 * @tc.number   SUB_KERNEL_SCHED_API_PATTR_INHERIT_0100
38 * @tc.name     test the default value of inheritsched.
39 * @tc.desc     [C- SOFTWARE -0200]
40 */
41HWTEST_F(PthreadSchedApiTest, testAttrGetInheritsched, Function | MediumTest | Level1)
42{
43    pthread_attr_t attr;
44    ASSERT_EQ(pthread_attr_init(&attr), 0);
45
46    int inheritsched = -1;
47    int rt = pthread_attr_getinheritsched(&attr, &inheritsched);
48    EXPECT_EQ(rt, 0) << "pthread_attr_getinheritsched failed. errno=" << errno;
49    EXPECT_EQ(inheritsched, PTHREAD_INHERIT_SCHED)
50        << "check default inheritsched failed. expect PTHREAD_INHERIT_SCHED";
51}
52
53/**
54 * @tc.number   SUB_KERNEL_SCHED_API_PATTR_INHERIT_0200
55 * @tc.name     test set and get inheritsched.
56 * @tc.desc     [C- SOFTWARE -0200]
57 */
58HWTEST_F(PthreadSchedApiTest, testAttrSetInheritsched, Function | MediumTest | Level1)
59{
60    pthread_attr_t attr;
61    ASSERT_EQ(pthread_attr_init(&attr), 0);
62
63    int rt = pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
64    EXPECT_EQ(rt, 0) << "pthread_attr_setinheritsched failed. errno=" << errno;
65    int inheritsched = -1;
66    rt = pthread_attr_getinheritsched(&attr, &inheritsched);
67    EXPECT_EQ(rt, 0) << "pthread_attr_getinheritsched failed. errno=" << errno;
68    EXPECT_EQ(inheritsched, PTHREAD_INHERIT_SCHED) << "check inheritsched failed";
69
70    rt = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
71    EXPECT_EQ(rt, 0) << "pthread_attr_setinheritsched failed. errno=" << errno;
72    inheritsched = -1;
73    rt = pthread_attr_getinheritsched(&attr, &inheritsched);
74    EXPECT_EQ(rt, 0) << "pthread_attr_getinheritsched failed. errno=" << errno;
75    EXPECT_EQ(inheritsched, PTHREAD_EXPLICIT_SCHED) << "check inheritsched failed";
76}
77
78/**
79 * @tc.number   SUB_KERNEL_SCHED_API_PATTR_INHERIT_0300
80 * @tc.name     pthread_attr_setinheritsched error test.
81 * @tc.desc     [C- SOFTWARE -0200]
82 */
83HWTEST_F(PthreadSchedApiTest, testAttrSetInheritschedError, Function | MediumTest | Level1)
84{
85    pthread_attr_t attr;
86    ASSERT_EQ(pthread_attr_init(&attr), 0);
87
88    int n = -GetRandom(100);
89    int rt = pthread_attr_setinheritsched(&attr, n);
90    EXPECT_EQ(rt, EINVAL) << "pthread_attr_setinheritsched(" << n << ") should fail";
91    n = 2 + GetRandom(100);
92    rt = pthread_attr_setinheritsched(&attr, n);
93    EXPECT_EQ(rt, EINVAL) << "pthread_attr_setinheritsched(" << n << ") should fail";
94}
95
96/**
97 * @tc.number   SUB_KERNEL_SCHED_API_PATTR_SCHEDPARAM_0100
98 * @tc.name     test the default value of sched_param.
99 * @tc.desc     [C- SOFTWARE -0200]
100 */
101HWTEST_F(PthreadSchedApiTest, testAttrGetSchedParam, Function | MediumTest | Level1)
102{
103    pthread_attr_t attr;
104    ASSERT_EQ(pthread_attr_init(&attr), 0);
105
106    struct sched_param param = {0};
107    int rt = pthread_attr_getschedparam(&attr, &param);
108    EXPECT_EQ(rt, 0) << "pthread_attr_getschedparam failed. errno=" << errno;
109    EXPECT_EQ(param.sched_priority, DEFAULT_THREAD_PRIORITY) << "check default pthread priority failed";
110}
111
112/**
113 * @tc.number   SUB_KERNEL_SCHED_API_PATTR_SCHEDPARAM_0200
114 * @tc.name     test set and get sched param.
115 * @tc.desc     [C- SOFTWARE -0200]
116 */
117HWTEST_F(PthreadSchedApiTest, testAttrSetSchedParam, Function | MediumTest | Level1)
118{
119    pthread_attr_t attr;
120    ASSERT_EQ(pthread_attr_init(&attr), 0);
121
122    struct sched_param param = {0};
123    int rt = pthread_attr_getschedparam(&attr, &param);
124    EXPECT_EQ(rt, 0) << "pthread_attr_getschedparam failed. errno=" << errno;
125
126    param.sched_priority = 22;
127    rt = pthread_attr_setschedparam(&attr, &param);
128    EXPECT_EQ(rt, 0) << "pthread_attr_setschedparam failed. errno=" << errno;
129
130    rt = pthread_attr_getschedparam(&attr, &param);
131    EXPECT_EQ(rt, 0) << "pthread_attr_getschedparam failed. errno=" << errno;
132    EXPECT_EQ(param.sched_priority, 22) << "check pthread priority failed";
133}
134
135/**
136 * @tc.number   SUB_KERNEL_SCHED_API_PATTR_SCHEDPARAM_0300
137 * @tc.name     pthread_attr_setschedparam error test.
138 * @tc.desc     [C- SOFTWARE -0200]
139 */
140HWTEST_F(PthreadSchedApiTest, testAttrSetSchedParamError, Function | MediumTest | Level1)
141{
142    pthread_attr_t attr;
143    ASSERT_EQ(pthread_attr_init(&attr), 0);
144
145    struct sched_param param = {0};
146    int rt = pthread_attr_getschedparam(&attr, &param);
147    EXPECT_EQ(rt, 0) << "pthread_attr_getschedparam failed. errno=" << errno;
148
149    param.sched_priority = LOWEST_USER_THREAD_PRIORITY + 1;
150    rt = pthread_attr_setschedparam(&attr, &param);
151    EXPECT_EQ(rt, EINVAL);
152}
153
154/**
155 * @tc.number   SUB_KERNEL_SCHED_API_PATTR_SCHEDPOLICY_0100
156 * @tc.name     test the default value of sched policy.
157 * @tc.desc     [C- SOFTWARE -0200]
158 */
159HWTEST_F(PthreadSchedApiTest, testAttrGetSchedPolicy, Function | MediumTest | Level1)
160{
161    pthread_attr_t attr;
162    ASSERT_EQ(pthread_attr_init(&attr), 0);
163
164    int policy = -1;
165    int rt = pthread_attr_getschedpolicy(&attr, &policy);
166    EXPECT_EQ(rt, 0) << "pthread_attr_getschedpolicy failed. errno=" << errno;
167    EXPECT_EQ(policy, SCHED_RR) << "check default policy failed, expect SCHED_RR";
168}
169
170/**
171 * @tc.number   SUB_KERNEL_SCHED_API_PATTR_SCHEDPOLICY_0200
172 * @tc.name     test set and get sched policy.
173 * @tc.desc     [C- SOFTWARE -0200]
174 */
175HWTEST_F(PthreadSchedApiTest, testAttrSetSchedPolicy, Function | MediumTest | Level1)
176{
177    pthread_attr_t attr;
178    ASSERT_EQ(pthread_attr_init(&attr), 0);
179
180    int rt = pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
181    EXPECT_EQ(rt, 0) << "pthread_attr_setschedparam failed. errno=" << errno;
182    int policy = -1;
183    rt = pthread_attr_getschedpolicy(&attr, &policy);
184    EXPECT_EQ(rt, 0) << "pthread_attr_getschedpolicy failed. errno=" << errno;
185    EXPECT_EQ(policy, SCHED_FIFO);
186
187    rt = pthread_attr_setschedpolicy(&attr, SCHED_RR);
188    EXPECT_EQ(rt, 0) << "pthread_attr_setschedparam failed. errno=" << errno;
189    rt = pthread_attr_getschedpolicy(&attr, &policy);
190    EXPECT_EQ(rt, 0) << "pthread_attr_getschedpolicy failed. errno=" << errno;
191    EXPECT_EQ(policy, SCHED_RR);
192}
193
194/**
195 * @tc.number   SUB_KERNEL_SCHED_API_PATTR_SCHEDPOLICY_0300
196 * @tc.name     pthread_attr_setschedpolicy error test.
197 * @tc.desc     [C- SOFTWARE -0200]
198 */
199HWTEST_F(PthreadSchedApiTest, testAttrSetSchedPolicyError, Function | MediumTest | Level1)
200{
201    pthread_attr_t attr;
202    ASSERT_EQ(pthread_attr_init(&attr), 0);
203    int rt;
204
205    // SCHED_FIFO is 1, and SCHED_RR is 2
206    const int testLoop = 7;
207    int invalidPolicy[testLoop] = {SCHED_OTHER, SCHED_BATCH, SCHED_IDLE, SCHED_RESET_ON_FORK};
208    invalidPolicy[4] = GetRandom(10000);
209    invalidPolicy[5] = -GetRandom(10000) + 6;
210    invalidPolicy[6] = GetRandom(10000) + 6;
211    for (int i = 0; i < testLoop; i++) {
212        rt = pthread_attr_setschedpolicy(&attr, invalidPolicy[i]);
213        EXPECT_EQ(rt, EINVAL) << "errno check fail for policy=" << invalidPolicy[i];
214    }
215}
216
217/**
218 * @tc.number   SUB_KERNEL_SCHED_API_PATTR_SCOPE_0100
219 * @tc.name     test the default value of sched scope.
220 * @tc.desc     [C- SOFTWARE -0200]
221 */
222HWTEST_F(PthreadSchedApiTest, testAttrGetScope, Function | MediumTest | Level1)
223{
224    pthread_attr_t attr;
225    ASSERT_EQ(pthread_attr_init(&attr), 0);
226
227    int scope = -1;
228    int rt = pthread_attr_getscope(&attr, &scope);
229    EXPECT_EQ(rt, 0) << "pthread_attr_getscope failed. errno=" << errno;
230    EXPECT_EQ(scope, PTHREAD_SCOPE_PROCESS) << "check default scope failed. expect PTHREAD_SCOPE_PROCESS";
231}
232
233/**
234 * @tc.number   SUB_KERNEL_SCHED_API_PATTR_SCOPE_0200
235 * @tc.name     test set and get scope.
236 * @tc.desc     [C- SOFTWARE -0200]
237 */
238HWTEST_F(PthreadSchedApiTest, testAttrSetScope, Function | MediumTest | Level1)
239{
240    pthread_attr_t attr;
241    ASSERT_EQ(pthread_attr_init(&attr), 0);
242
243    int rt = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
244    EXPECT_EQ(rt, ENOTSUP); // liteos support PTHREAD_SCOPE_PROCESS only
245
246    rt = pthread_attr_setscope(&attr, -GetRandom(10000));
247    EXPECT_EQ(rt, EINVAL);
248
249    rt = pthread_attr_setscope(&attr, GetRandom(10000) + 2);
250    EXPECT_EQ(rt, EINVAL);
251
252    int scope = -1;
253    rt = pthread_attr_getscope(&attr, &scope);
254    EXPECT_EQ(rt, 0) << "pthread_attr_getscope failed. errno=" << errno;
255    EXPECT_EQ(scope, PTHREAD_SCOPE_PROCESS) << "check scope failed. expect PTHREAD_SCOPE_PROCESS";
256}
257
258void* ThreadFunc1(void* arg)
259{
260    sem_t *sem = (sem_t*)arg;
261
262    int policy;
263    struct sched_param param = {0};
264    EXPECT_EQ(pthread_getschedparam(pthread_self(), &policy, &param), 0);
265    EXPECT_EQ(policy, g_policy);
266    EXPECT_EQ(param.sched_priority, g_prioriy);
267
268    LOG("wait main thread check this thread para...");
269    sem_wait(sem);
270    return nullptr;
271}
272/**
273 * @tc.number   SUB_KERNEL_SCHED_API_PTHREAD_GETSCHEDPARAM_0100
274 * @tc.name     pthread_getschedparam basic test.
275 * @tc.desc     [C- SOFTWARE -0200]
276 */
277HWTEST_F(PthreadSchedApiTest, testGetSchedParam, Function | MediumTest | Level1)
278{
279    sem_t sem;
280    ASSERT_EQ(sem_init(&sem, 0, 0), 0) << "sem_init errno = " << errno;
281
282    pthread_t ptSub;
283    pthread_attr_t attr;
284    struct sched_param param = {0};
285    ASSERT_EQ(pthread_attr_init(&attr), 0);
286    g_policy = SCHED_FIFO;
287    param.sched_priority = g_prioriy = GetRandom(LOWEST_USER_THREAD_PRIORITY);
288
289    EXPECT_EQ(pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED), 0);
290    EXPECT_EQ(pthread_attr_setschedpolicy(&attr, g_policy), 0);
291    EXPECT_EQ(pthread_attr_setschedparam(&attr, &param), 0);
292    int rt = pthread_create(&ptSub, &attr, ThreadFunc1, (void*)&sem);
293    ASSERT_EQ(rt, 0) << "pthread_create failed!";
294
295    LOG("check sub thread's para");
296    int policy;
297    EXPECT_EQ(pthread_getschedparam(ptSub, &policy, &param), 0);
298    EXPECT_EQ(policy, g_policy);
299    EXPECT_EQ(param.sched_priority, g_prioriy);
300
301    LOGD("main:before post sem...");
302    sem_post(&sem);
303    LOGD("main:after post sem...");
304    pthread_join(ptSub, nullptr);
305}
306
307/**
308 * @tc.number   SUB_KERNEL_SCHED_API_PTHREAD_SETSCHEDPARAM_0100
309 * @tc.name     pthread_setschedparam basic test.
310 * @tc.desc     [C- SOFTWARE -0200]
311 */
312HWTEST_P(PthreadAllPrioTest, testSetSchedParam, Function | MediumTest | Level1)
313{
314    pthread_t ptSub;
315    pthread_t ptSelf = pthread_self();
316    sem_t sem;
317    ASSERT_EQ(sem_init(&sem, 0, 0), 0) << "sem_init errno = " << errno;
318
319    // change self sched para
320    struct sched_param param = {0};
321    int policy;
322    EXPECT_EQ(pthread_getschedparam(ptSelf, &policy, &param), 0);
323    param.sched_priority = g_prioriy = GetParam();
324    if (GetRandom(100)%2) {
325        policy = g_policy = SCHED_RR;
326    } else {
327        policy = g_policy = SCHED_FIFO;
328    }
329    LOG("========= Test policy(%d) and prioriy(%d) =========", g_policy, g_prioriy);
330
331    int rt = pthread_setschedparam(ptSelf, policy, &param);
332    ASSERT_EQ(rt, 0) << "pthread_setschedparam failed!";
333
334    LOG("create sub thread");
335    pthread_attr_t attr;
336    ASSERT_EQ(pthread_attr_init(&attr), 0);
337    EXPECT_EQ(pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED), 0);
338    rt = pthread_create(&ptSub, &attr, ThreadFunc1, (void*)&sem);
339    ASSERT_EQ(rt, 0) << "pthread_create failed!";
340
341    LOG("check self and sub thread's para");
342    EXPECT_EQ(pthread_getschedparam(ptSelf, &policy, &param), 0);
343    EXPECT_EQ(policy, g_policy);
344    EXPECT_EQ(param.sched_priority, g_prioriy);
345
346    EXPECT_EQ(pthread_getschedparam(ptSub, &policy, &param), 0);
347    EXPECT_EQ(policy, g_policy);
348    EXPECT_EQ(param.sched_priority, g_prioriy);
349
350    LOGD("main:before post sem...");
351    sem_post(&sem);
352    LOGD("main:after post sem...");
353    pthread_join(ptSub, nullptr);
354
355
356    LOG("restore...");
357    policy = SCHED_RR;
358    param.sched_priority = DEFAULT_THREAD_PRIORITY;
359    rt = pthread_setschedparam(ptSelf, policy, &param);
360    ASSERT_EQ(rt, 0) << "pthread_setschedparam failed!";
361}
362INSTANTIATE_TEST_CASE_P(PthreadSchedApiTest, PthreadAllPrioTest,
363    testing::Range(HIGHEST_USER_THREAD_PRIORITY, LOWEST_USER_THREAD_PRIORITY + 1));
364
365void* ThrdFuncForSetSchedParamTest(void* arg)
366{
367    sem_t *sem = (sem_t*)arg;
368    pthread_t ptSelf = pthread_self();
369    int rt, policy;
370    struct sched_param param = {0};
371    EXPECT_EQ(pthread_getschedparam(ptSelf, &policy, &param), 0);
372
373    LOG("invalid policy test:");
374    const int testLoop = 7;
375    int invalidPolicy[testLoop] = {
376        SCHED_OTHER, SCHED_BATCH, SCHED_IDLE, SCHED_DEADLINE, SCHED_RESET_ON_FORK,
377        -(int)GetRandom(10000), (int)GetRandom(10000) + SCHED_DEADLINE
378    };
379    for (int i = 0; i < testLoop; i++) {
380        rt = pthread_setschedparam(ptSelf, invalidPolicy[i], &param);
381        EXPECT_EQ(rt, EINVAL) << "pthread_setschedparam should fail for policy=" << invalidPolicy[i];
382    }
383
384    LOG("invalid 'priority' test:");
385    param.sched_priority = HIGHEST_USER_THREAD_PRIORITY - 1;
386    EXPECT_EQ(pthread_setschedparam(ptSelf, SCHED_RR, &param), EINVAL);
387    param.sched_priority = LOWEST_USER_THREAD_PRIORITY + 1;
388    EXPECT_EQ(pthread_setschedparam(ptSelf, SCHED_RR, &param), EINVAL);
389
390    LOG("tell main thread check this thread para...");
391    sem_post(sem);
392    Msleep(100);
393    LOG("thread exit...");
394    return nullptr;
395}
396/**
397 * @tc.number   SUB_KERNEL_SCHED_API_PTHREAD_SETSCHEDPARAM_0200
398 * @tc.name     pthread_setschedparam api error test.
399 * @tc.desc     [C- SOFTWARE -0200]
400 */
401HWTEST_F(PthreadSchedApiTest, testSetSchedParamError, Function | MediumTest | Level3)
402{
403    sem_t sem;
404    ASSERT_EQ(sem_init(&sem, 0, 0), 0) << "sem_init errno = " << errno;
405
406    pthread_t ptSub;
407    pthread_attr_t attr;
408    struct sched_param param = {0};
409    ASSERT_EQ(pthread_attr_init(&attr), 0);
410    g_policy = SCHED_FIFO;
411    param.sched_priority = g_prioriy = GetRandom(LOWEST_USER_THREAD_PRIORITY);
412
413    EXPECT_EQ(pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED), 0);
414    EXPECT_EQ(pthread_attr_setschedpolicy(&attr, g_policy), 0);
415    EXPECT_EQ(pthread_attr_setschedparam(&attr, &param), 0);
416    int rt = pthread_create(&ptSub, &attr, ThrdFuncForSetSchedParamTest, (void*)&sem);
417    ASSERT_EQ(rt, 0) << "pthread_create failed!";
418
419    LOGD("main:wait sub-thread...");
420    sem_wait(&sem);
421    LOG("check sub thread's para doesn't changed");
422    int policy;
423    EXPECT_EQ(pthread_getschedparam(ptSub, &policy, &param), 0);
424    EXPECT_EQ(policy, g_policy);
425    EXPECT_EQ(param.sched_priority, g_prioriy);
426
427    pthread_join(ptSub, nullptr);
428}
429
430void* ThrdFuncForSetSchedPrioTest(void* arg)
431{
432    sem_t *sem = (sem_t*)arg;
433    pthread_t ptSelf = pthread_self();
434
435    LOG("invalid 'priority' test:");
436    EXPECT_EQ(pthread_setschedprio(ptSelf, HIGHEST_USER_THREAD_PRIORITY - 1), EINVAL);
437    EXPECT_EQ(pthread_setschedprio(ptSelf, LOWEST_USER_THREAD_PRIORITY + 1), EINVAL);
438
439    LOG("valid 'priority' test:");
440    EXPECT_EQ(pthread_setschedprio(ptSelf, LOWEST_USER_THREAD_PRIORITY), 0);
441
442    LOG("tell main thread check this thread para...");
443    sem_post(sem);
444    Msleep(100);
445    LOG("thread exit...");
446    return nullptr;
447}
448/**
449 * @tc.number   SUB_KERNEL_SCHED_API_PTHREAD_SETSCHEDPRIO_0100
450 * @tc.name     pthread_setschedprio api basic test.
451 * @tc.desc     [C- SOFTWARE -0200]
452 */
453HWTEST_F(PthreadSchedApiTest, testSetSchedPrio, Function | MediumTest | Level1)
454{
455    sem_t sem;
456    ASSERT_EQ(sem_init(&sem, 0, 0), 0) << "sem_init errno = " << errno;
457
458    pthread_t ptSub;
459    pthread_attr_t attr;
460    struct sched_param param = {0};
461    ASSERT_EQ(pthread_attr_init(&attr), 0);
462    g_policy = SCHED_RR;
463    param.sched_priority = g_prioriy = HIGHEST_USER_THREAD_PRIORITY;
464
465    EXPECT_EQ(pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED), 0);
466    EXPECT_EQ(pthread_attr_setschedpolicy(&attr, g_policy), 0);
467    EXPECT_EQ(pthread_attr_setschedparam(&attr, &param), 0);
468    int rt = pthread_create(&ptSub, &attr, ThrdFuncForSetSchedPrioTest, (void*)&sem);
469    ASSERT_EQ(rt, 0) << "pthread_create failed!";
470
471    LOGD("main:wait sub-thread...");
472    sem_wait(&sem);
473    LOG("check sub thread's priority has changed");
474    int policy;
475    EXPECT_EQ(pthread_getschedparam(ptSub, &policy, &param), 0);
476    EXPECT_EQ(policy, g_policy);
477    EXPECT_EQ(param.sched_priority, LOWEST_USER_THREAD_PRIORITY);
478    pthread_join(ptSub, nullptr);
479}
480
481// second
482void *ThreadTestFifoSched1(void *arg)
483{
484    sem_t *sem = (sem_t*)arg;
485    EXPECT_EQ(sem_wait(sem), 0) << "sem_wait errno = " << errno;
486    CheckStep(3);
487    LOG("> This is ThreadSched1");
488    return arg;
489}
490
491// first
492void *ThreadTestFifoSched2(void *arg)
493{
494    sem_t *sem = (sem_t*)arg;
495    EXPECT_EQ(sem_wait(sem), 0) << "sem_wait errno = " << errno;
496    CheckStep(2);
497    LOG("> This is ThreadSched2");
498    return arg;
499}
500
501/**
502 * @tc.number   SUB_KERNEL_SCHED_API_PTHREAD_SCHED_ALL_0100
503 * @tc.name     test thread high ang low priority function
504 * @tc.desc     [C- SOFTWARE -0200]
505 */
506HWTEST_F(PthreadSchedApiTest, testSchedFifo, Function | MediumTest | Level3)
507{
508    pthread_t tid1;
509    pthread_t tid2;
510    int param;
511    pthread_attr_t attr;
512    struct sched_param schedParam = {0};
513    sem_t sem;
514    CheckStep(1);
515
516    ASSERT_EQ(sem_init(&sem, 0, 0), 0) << "> sem_init errno = " << errno;
517
518    // low
519    EXPECT_EQ(pthread_attr_init(&attr), 0);
520    EXPECT_EQ(pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED), 0) << "> return errno";
521    EXPECT_EQ(pthread_attr_setschedpolicy(&attr, SCHED_FIFO), 0) << "> return errno";
522    EXPECT_EQ(pthread_attr_getschedpolicy(&attr, &param), 0);
523    EXPECT_EQ(param, SCHED_FIFO);
524
525    schedParam.sched_priority = 22;
526    EXPECT_EQ(pthread_attr_setschedparam(&attr, &schedParam), 0) << "> return errno";
527
528    ASSERT_EQ(pthread_create(&tid1, &attr, ThreadTestFifoSched1, (void*)&sem), 0) << "> return errno";
529    EXPECT_EQ(pthread_attr_destroy(&attr), 0);
530
531    // high
532    EXPECT_EQ(pthread_attr_init(&attr), 0);
533    EXPECT_EQ(pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED), 0) << "> return errno";
534    EXPECT_EQ(pthread_attr_setschedpolicy(&attr, SCHED_FIFO), 0) << "> return errno";
535
536    schedParam.sched_priority = 21;
537    EXPECT_EQ(pthread_attr_setschedparam(&attr, &schedParam), 0) << "> return errno";
538
539    ASSERT_EQ(pthread_create(&tid2, &attr, ThreadTestFifoSched2, (void*)&sem), 0) << "> return errno";
540    EXPECT_EQ(pthread_attr_destroy(&attr), 0);
541
542    Msleep(10);
543    EXPECT_EQ(sem_post(&sem), 0) << "sem_post errno = " << errno;
544    Msleep(10);
545    EXPECT_EQ(sem_post(&sem), 0) << "sem_post errno = " << errno;
546
547    EXPECT_EQ(pthread_join(tid1, nullptr), 0) << "> return errno";
548    EXPECT_EQ(pthread_join(tid2, nullptr), 0) << "> return errno";
549
550    EXPECT_EQ(CheckStep(4), 0x1234Ull);    // make sure ThreadTestFifoSched2 ahead
551}