1/* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * SPDX-License-Identifier: GPL-2.0 4 * 5 * Unless required by applicable law or agreed to in writing, software 6 * distributed under the License is distributed on an "AS IS" BASIS, 7 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8 * See the License for the specific language governing permissions and 9 * limitations under the License. 10 */ 11 12#include "rtg_test.h" 13#include <cstdio> 14#include <cstdlib> 15#include <fcntl.h> 16#include <cerrno> 17#include <unistd.h> 18#include <sys/types.h> 19#include <sys/stat.h> 20#include <sys/mman.h> 21#include <sys/wait.h> 22#include <sys/ioctl.h> 23#include <ctime> 24#include <climits> 25#include <pthread.h> 26#include <sys/syscall.h> 27#include <securec.h> 28#include <string> 29#include <vector> 30 31using namespace testing::ext; 32using namespace std; 33 34constexpr size_t MAX_LENGTH = 100; 35const char RTG_SCHED_IPC_MAGIC = 0xAB; 36const int RTG_ERR = -1; 37const int RTG_SUCC = 0; 38const int MAX_TID_NUM = 5; 39const int MULTI_FRAME_NUM = 5; 40 41#define CMD_ID_SET_ENABLE \ 42 _IOWR(RTG_SCHED_IPC_MAGIC, SET_ENABLE, struct RtgEnableData) 43#define CMD_ID_SET_RTG \ 44 _IOWR(RTG_SCHED_IPC_MAGIC, SET_RTG, struct RtgStrData) 45#define CMD_ID_BEGIN_FRAME_FREQ \ 46 _IOWR(RTG_SCHED_IPC_MAGIC, BEGIN_FRAME_FREQ, struct ProcStateData) 47#define CMD_ID_END_FRAME_FREQ \ 48 _IOWR(RTG_SCHED_IPC_MAGIC, END_FRAME_FREQ, struct ProcStateData) 49#define CMD_ID_END_SCENE \ 50 _IOWR(RTG_SCHED_IPC_MAGIC, END_SCENE, struct ProcStateData) 51#define CMD_ID_SET_MIN_UTIL \ 52 _IOWR(RTG_SCHED_IPC_MAGIC, SET_MIN_UTIL, struct ProcStateData) 53#define CMD_ID_SET_MARGIN \ 54 _IOWR(RTG_SCHED_IPC_MAGIC, SET_MARGIN, struct ProcStateData) 55#define CMD_ID_SET_RTG_ATTR \ 56 _IOWR(RTG_SCHED_IPC_MAGIC, SET_RTG_ATTR, struct RtgStrData) 57#define CMD_ID_SET_CONFIG \ 58 _IOWR(RTG_SCHED_IPC_MAGIC, SET_CONFIG, struct RtgStrData) 59 60struct RtgEnableData { 61 int enable; 62 int len; 63 char *data; 64}; 65 66struct RtgStrData { 67 int type; 68 int len; 69 char *data; 70}; 71 72struct ProcStateData { 73 int grpId; 74 int stateParam; 75}; 76 77enum GrpCtrlCmd { 78 CMD_CREATE_RTG_GRP, 79 CMD_ADD_RTG_THREAD, 80 CMD_REMOVE_RTG_THREAD, 81 CMD_CLEAR_RTG_GRP, 82 CMD_DESTROY_RTG_GRP 83}; 84 85struct RtgGrpData { 86 int rtgCmd; 87 int grpId; 88 int prioType; 89 int rtCnt; 90 int tidNum; 91 int tids[MAX_TID_NUM]; 92}; 93 94struct RtgInfo { 95 int rtgNum; 96 int rtgs[MULTI_FRAME_NUM]; 97}; 98 99enum RtgSchedCmdid { 100 SET_ENABLE = 1, 101 SET_RTG, 102 SET_CONFIG, 103 SET_RTG_ATTR, 104 BEGIN_FRAME_FREQ = 5, 105 END_FRAME_FREQ, 106 END_SCENE, 107 SET_MIN_UTIL, 108 SET_MARGIN, 109 LIST_RTG = 10, 110 LIST_RTG_THREAD, 111 SEARCH_RTG, 112 GET_ENABLE, 113 RTG_CTRL_MAX_NR, 114}; 115 116enum RtgType : int { 117 VIP = 0, 118 TOP_TASK_KEY, 119 NORMAL_TASK, 120 RTG_TYPE_MAX, 121}; 122 123static int BasicOpenRtgNode() 124{ 125 char fileName[] = "/proc/self/sched_rtg_ctrl"; 126 127 int fd = open(fileName, O_RDWR); 128 if (fd < 0) { 129 cout << "open node err." << endl; 130 } 131 132 return fd; 133} 134 135static int EnableRtg(bool flag) 136{ 137 struct RtgEnableData enableData; 138 char configStr[] = "load_freq_switch:1;sched_cycle:1"; 139 140 enableData.enable = flag; 141 enableData.len = sizeof(configStr); 142 enableData.data = configStr; 143 int fd = BasicOpenRtgNode(); 144 if (fd < 0) { 145 return RTG_ERR; 146 } 147 if (ioctl(fd, CMD_ID_SET_ENABLE, &enableData)) { 148 close(fd); 149 return RTG_ERR; 150 } 151 152 close(fd); 153 return 0; 154} 155 156static int CreateNewRtgGrp(int prioType, int rtNum) 157{ 158 struct RtgGrpData grpData; 159 int ret; 160 int fd = BasicOpenRtgNode(); 161 if (fd < 0) { 162 return RTG_ERR; 163 } 164 (void)memset_s(&grpData, sizeof(struct RtgGrpData), 0, sizeof(struct RtgGrpData)); 165 if ((prioType > 0) && (prioType < RTG_TYPE_MAX)) { 166 grpData.prioType = prioType; 167 } 168 if (rtNum > 0) { 169 grpData.rtCnt = rtNum; 170 } 171 grpData.rtgCmd = CMD_CREATE_RTG_GRP; 172 ret = ioctl(fd, CMD_ID_SET_RTG, &grpData); 173 174 close(fd); 175 return ret; 176} 177 178static int DestroyRtgGrp(int grpId) 179{ 180 struct RtgGrpData grpData; 181 int ret; 182 int fd = BasicOpenRtgNode(); 183 if (fd < 0) { 184 return fd; 185 } 186 (void)memset_s(&grpData, sizeof(struct RtgGrpData), 0, sizeof(struct RtgGrpData)); 187 grpData.rtgCmd = CMD_DESTROY_RTG_GRP; 188 grpData.grpId = grpId; 189 ret = ioctl(fd, CMD_ID_SET_RTG, &grpData); 190 191 close(fd); 192 return ret; 193} 194 195static int AddThreadToRtg(int tid, int grpId, int prioType) 196{ 197 struct RtgGrpData grpData; 198 int ret; 199 int fd = BasicOpenRtgNode(); 200 if (fd < 0) { 201 return fd; 202 } 203 (void)memset_s(&grpData, sizeof(struct RtgGrpData), 0, sizeof(struct RtgGrpData)); 204 grpData.tidNum = 1; 205 grpData.tids[0] = tid; 206 grpData.grpId = grpId; 207 grpData.rtgCmd = CMD_ADD_RTG_THREAD; 208 grpData.prioType = prioType; 209 ret = ioctl(fd, CMD_ID_SET_RTG, &grpData); 210 211 close(fd); 212 return ret; 213} 214 215static int BeginFrameFreq(int stateParam) 216{ 217 int ret = 0; 218 struct ProcStateData stateData; 219 stateData.stateParam = stateParam; 220 int fd = BasicOpenRtgNode(); 221 if (fd < 0) { 222 return fd; 223 } 224 ret = ioctl(fd, CMD_ID_BEGIN_FRAME_FREQ, &stateData); 225 226 close(fd); 227 return ret; 228} 229 230static int EndFrameFreq(int stateParam) 231{ 232 int ret = 0; 233 struct ProcStateData stateData; 234 stateData.stateParam = stateParam; 235 int fd = BasicOpenRtgNode(); 236 if (fd < 0) { 237 return fd; 238 } 239 ret = ioctl(fd, CMD_ID_END_FRAME_FREQ, &stateData); 240 241 close(fd); 242 return ret; 243} 244 245static int EndScene(int grpId) 246{ 247 int ret = 0; 248 struct ProcStateData stateData; 249 stateData.grpId = grpId; 250 251 int fd = BasicOpenRtgNode(); 252 if (fd < 0) { 253 return fd; 254 } 255 ret = ioctl(fd, CMD_ID_END_SCENE, &stateData); 256 257 close(fd); 258 return ret; 259} 260 261static int SetStateParam(unsigned int cmd, int stateParam) 262{ 263 int ret = 0; 264 struct ProcStateData stateData; 265 stateData.stateParam = stateParam; 266 267 int fd = BasicOpenRtgNode(); 268 if (fd < 0) { 269 return fd; 270 } 271 ret = ioctl(fd, cmd, &stateData); 272 273 close(fd); 274 return ret; 275} 276 277static int SetFrameRateAndPrioType(int rtgId, int rate, int rtgType) 278{ 279 int ret = 0; 280 char formatData[MAX_LENGTH] = {}; 281 (void)sprintf_s(formatData, sizeof(formatData), "rtgId:%d;rate:%d;type:%d", rtgId, rate, rtgType); 282 struct RtgStrData strData; 283 strData.len = strlen(formatData); 284 strData.data = formatData; 285 286 int fd = BasicOpenRtgNode(); 287 if (fd < 0) { 288 return fd; 289 } 290 ret = ioctl(fd, CMD_ID_SET_RTG_ATTR, &strData); 291 292 close(fd); 293 return ret; 294} 295 296static int AddThreadsToRtg(vector<int> tids, int grpId, int prioType) 297{ 298 struct RtgGrpData grpData; 299 int ret; 300 301 int fd = BasicOpenRtgNode(); 302 if (fd < 0) { 303 return fd; 304 } 305 (void)memset_s(&grpData, sizeof(struct RtgGrpData), 0, sizeof(struct RtgGrpData)); 306 int num = static_cast<int>(tids.size()); 307 if (num > MAX_TID_NUM) { 308 return -1; 309 } 310 grpData.tidNum = num; 311 grpData.grpId = grpId; 312 grpData.rtgCmd = CMD_ADD_RTG_THREAD; 313 grpData.prioType = prioType; 314 for (int i = 0; i < num; i++) { 315 if (tids[i] < 0) { 316 return -1; 317 } 318 grpData.tids[i] = tids[i]; 319 } 320 ret = ioctl(fd, CMD_ID_SET_RTG, &grpData); 321 322 close(fd); 323 return ret; 324} 325 326void RtgTest::SetUp() 327{ 328 // must enable rtg before use the interface 329 int ret = EnableRtg(true); 330 ASSERT_EQ(RTG_SUCC, ret); 331} 332 333void RtgTest::TearDown() 334{ 335 // disable rtg after use the interface 336 int ret = EnableRtg(false); 337 ASSERT_EQ(RTG_SUCC, ret); 338} 339 340void RtgTest::SetUpTestCase() {} 341 342void RtgTest::TearDownTestCase() {} 343 344/** 345 * @tc.name: setEnableSucc 346 * @tc.desc: Verify the enable rtg function. 347 * @tc.type: FUNC 348 */ 349HWTEST_F(RtgTest, setEnableSucc, Function | MediumTest | Level1) 350{ 351 int ret; 352 353 // test set enable again 354 ret = EnableRtg(true); 355 ASSERT_EQ(RTG_SUCC, ret); 356 357 // test set disable again 358 ret = EnableRtg(false); 359 ASSERT_EQ(RTG_SUCC, ret); 360} 361 362/** 363 * @tc.name: createAndDestroyRtgSucc 364 * @tc.desc: Verify the create and destroy rtggrp function. 365 * @tc.type: FUNC 366 */ 367HWTEST_F(RtgTest, createAndDestroyRtgSucc, Function | MediumTest | Level1) 368{ 369 int ret; 370 int grpId; 371 372 grpId = CreateNewRtgGrp(NORMAL_TASK, 0); 373 ASSERT_GT(grpId, 0); 374 ret = DestroyRtgGrp(grpId); 375 ASSERT_EQ(ret, 0); 376} 377 378/** 379 * @tc.name: destoryErrorRtgGrp 380 * @tc.desc: Verify Destroy function with error param. 381 * @tc.type: FUNC 382 */ 383HWTEST_F(RtgTest, destoryErrorRtgGrp, Function | MediumTest | Level1) 384{ 385 int ret; 386 ret = DestroyRtgGrp(-1); 387 ASSERT_NE(RTG_SUCC, ret); 388} 389 390/** 391 * @tc.name: addRtgGrpSucc 392 * @tc.desc: Verify add rtg function. 393 * @tc.type: FUNC 394 */ 395HWTEST_F(RtgTest, addRtgGrpSucc, Function | MediumTest | Level1) 396{ 397 int ret; 398 int grpId; 399 int pid = getpid(); 400 401 grpId = CreateNewRtgGrp(VIP, 0); 402 ASSERT_GT(grpId, 0); 403 ret = AddThreadToRtg(pid, grpId, VIP); 404 ASSERT_EQ(ret, 0); 405 ret = DestroyRtgGrp(grpId); 406 ASSERT_EQ(ret, 0); 407} 408 409/** 410 * @tc.name: addRtgGrpFail 411 * @tc.desc: Verify add rtg function with error param. 412 * @tc.type: FUNC 413 */ 414HWTEST_F(RtgTest, addRtgGrpFail, Function | MediumTest | Level1) 415{ 416 int ret; 417 int grpId; 418 int pid = getpid(); 419 420 grpId = CreateNewRtgGrp(VIP, 0); 421 ASSERT_GT(grpId, 0); 422 423 // error tid 424 ret = AddThreadToRtg(-1, grpId, VIP); 425 ASSERT_NE(ret, 0); 426 427 // error grpid 428 ret = AddThreadToRtg(pid, -1, VIP); 429 ASSERT_NE(ret, RTG_SUCC); 430 ret = DestroyRtgGrp(grpId); 431 ASSERT_EQ(ret, 0); 432} 433 434/** 435 * @tc.name: begainFrameFreqSucc 436 * @tc.desc: Verify rtg frame start function. 437 * @tc.type: FUNC 438 */ 439HWTEST_F(RtgTest, begainFrameFreqSucc, Function | MediumTest | Level1) 440{ 441 int ret; 442 int grpId; 443 int pid = getpid(); 444 vector<int> pids = {}; 445 pids.push_back(pid); 446 grpId = CreateNewRtgGrp(VIP, 0); 447 ASSERT_GT(grpId, 0); 448 ret = AddThreadsToRtg(pids, grpId, VIP); 449 ASSERT_EQ(ret, 0); 450 ret = BeginFrameFreq(0); 451 ASSERT_EQ(ret, 0); 452 ret = DestroyRtgGrp(grpId); 453 ASSERT_EQ(ret, 0); 454} 455 456/** 457 * @tc.name: RtgInterfaceBeginFrameFreqWithNoAddThreadtoGrp 458 * @tc.desc: Verify rtg frame start function with NoAddThreadtoGrp. 459 * @tc.type: FUNC 460 */ 461HWTEST_F(RtgTest, RtgInterfaceBeginFrameFreqWithNoAddThreadtoGrp, Function | MediumTest | Level1) 462{ 463 int ret; 464 int grpId; 465 grpId = CreateNewRtgGrp(VIP, 0); 466 ASSERT_GT(grpId, 0); 467 ret = BeginFrameFreq(0); 468 ASSERT_NE(ret, 0); 469 ret = DestroyRtgGrp(grpId); 470 ASSERT_EQ(ret, 0); 471} 472 473/** 474 * @tc.name: endFrameFreqSucc 475 * @tc.desc: Verify rtg frame end function. 476 * @tc.type: FUNC 477 */ 478HWTEST_F(RtgTest, endFrameFreqSucc, Function | MediumTest | Level1) 479{ 480 int ret; 481 int grpId; 482 int pid = getpid(); 483 vector<int> pids = {}; 484 pids.push_back(pid); 485 grpId = CreateNewRtgGrp(VIP, 0); 486 ASSERT_GT(grpId, 0); 487 ret = AddThreadsToRtg(pids, grpId, VIP); 488 ASSERT_EQ(ret, 0); 489 ret = EndFrameFreq(0); 490 ASSERT_EQ(ret, RTG_SUCC); 491 ret = DestroyRtgGrp(grpId); 492 ASSERT_EQ(ret, RTG_SUCC); 493} 494 495/** 496 * @tc.name: endFrameFreqWithNoAddThreadtoGrp 497 * @tc.desc: Verify rtg frame end function with NoAddThreadtoGrp. 498 * @tc.type: FUNC 499 */ 500HWTEST_F(RtgTest, endFrameFreqWithNoAddThreadtoGrp, Function | MediumTest | Level1) 501{ 502 int ret; 503 int grpId; 504 grpId = CreateNewRtgGrp(VIP, 0); 505 ASSERT_GT(grpId, 0); 506 ret = EndFrameFreq(0); 507 ASSERT_NE(ret, RTG_SUCC); 508 ret = DestroyRtgGrp(grpId); 509 ASSERT_EQ(ret, RTG_SUCC); 510} 511 512 513/** 514 * @tc.name: endSceneSucc 515 * @tc.desc: Verify scene end function. 516 * @tc.type: FUNC 517 */ 518HWTEST_F(RtgTest, endSceneSucc, Function | MediumTest | Level1) 519{ 520 int ret; 521 int grpId; 522 int pid = getpid(); 523 vector<int> pids = {}; 524 pids.push_back(pid); 525 grpId = CreateNewRtgGrp(VIP, 0); 526 ASSERT_GT(grpId, 0); 527 ret = AddThreadsToRtg(pids, grpId, VIP); 528 ASSERT_EQ(ret, 0); 529 ret = EndScene(grpId); 530 ASSERT_EQ(ret, RTG_SUCC); 531 ret = DestroyRtgGrp(grpId); 532 ASSERT_EQ(ret, RTG_SUCC); 533} 534 535/** 536 * @tc.name: endSceneFail 537 * @tc.desc: Verify scene end function. 538 * @tc.type: FUNC 539 */ 540HWTEST_F(RtgTest, endSceneFail, Function | MediumTest | Level1) 541{ 542 int ret; 543 544 ret = EndScene(-1); 545 ASSERT_NE(ret, RTG_SUCC); 546} 547 548/** 549 * @tc.name: setMinUtilSucc 550 * @tc.desc: Verify set min util function. 551 * @tc.type: FUNC 552 */ 553HWTEST_F(RtgTest, setMinUtilSucc, Function | MediumTest | Level1) 554{ 555 int ret; 556 int grpId; 557 int pid = getpid(); 558 vector<int> pids = {}; 559 pids.push_back(pid); 560 grpId = CreateNewRtgGrp(VIP, 0); 561 ASSERT_GT(grpId, 0); 562 ret = AddThreadsToRtg(pids, grpId, VIP); 563 ASSERT_EQ(ret, 0); 564 ret = SetStateParam(CMD_ID_SET_MIN_UTIL, 0); 565 ASSERT_EQ(ret, RTG_SUCC); 566 ret = DestroyRtgGrp(grpId); 567 ASSERT_EQ(ret, RTG_SUCC); 568} 569 570/** 571 * @tc.name: setMinUtilWithNoAddThreadtoGrp 572 * @tc.desc: Verify set min util function with NoAddThreadtoGrp. 573 * @tc.type: FUNC 574 */ 575HWTEST_F(RtgTest, setMinUtilWithNoAddThreadtoGrp, Function | MediumTest | Level1) 576{ 577 int ret; 578 int grpId; 579 grpId = CreateNewRtgGrp(VIP, 0); 580 ASSERT_GT(grpId, 0); 581 ret = SetStateParam(CMD_ID_SET_MIN_UTIL, 0); 582 ASSERT_NE(ret, RTG_SUCC); 583 ret = DestroyRtgGrp(grpId); 584 ASSERT_EQ(ret, RTG_SUCC); 585} 586 587/** 588 * @tc.name: setMarginSucc 589 * @tc.desc: Verify set min margin function. 590 * @tc.type: FUNC 591 */ 592HWTEST_F(RtgTest, setMarginSucc, Function | MediumTest | Level1) 593{ 594 int ret; 595 int grpId; 596 int pid = getpid(); 597 vector<int> pids = {}; 598 pids.push_back(pid); 599 grpId = CreateNewRtgGrp(VIP, 0); 600 ASSERT_GT(grpId, 0); 601 ret = AddThreadsToRtg(pids, grpId, VIP); 602 ASSERT_EQ(ret, 0); 603 ret = SetStateParam(CMD_ID_SET_MARGIN, 0); 604 ASSERT_EQ(ret, RTG_SUCC); 605 ret = DestroyRtgGrp(grpId); 606 ASSERT_EQ(ret, RTG_SUCC); 607} 608 609/** 610 * @tc.name: setMarginWithNoAddThreadtoGrp 611 * @tc.desc: Verify set min margin function with NoAddThreadtoGrp. 612 * @tc.type: FUNC 613 */ 614HWTEST_F(RtgTest, setMarginWithNoAddThreadtoGrp, Function | MediumTest | Level1) 615{ 616 int ret; 617 int grpId; 618 grpId = CreateNewRtgGrp(VIP, 0); 619 ASSERT_GT(grpId, 0); 620 ret = SetStateParam(CMD_ID_SET_MARGIN, 0); 621 ASSERT_NE(ret, RTG_SUCC); 622 ret = DestroyRtgGrp(grpId); 623 ASSERT_EQ(ret, RTG_SUCC); 624} 625 626/** 627 * @tc.name: SetRtgAttrSucc 628 * @tc.desc: Verify rtg attr set function. 629 * @tc.type: FUNC 630 */ 631HWTEST_F(RtgTest, SetRtgAttrSucc, Function | MediumTest | Level1) 632{ 633 int ret; 634 int grpId; 635 636 grpId = CreateNewRtgGrp(VIP, 0); 637 ASSERT_GT(grpId, 0); 638 ret = SetFrameRateAndPrioType(grpId, 60, VIP); 639 ASSERT_EQ(ret, RTG_SUCC); 640 ret = DestroyRtgGrp(grpId); 641 ASSERT_EQ(ret, RTG_SUCC); 642} 643 644/** 645 * @tc.name: SetRtgAttrFail 646 * @tc.desc: Verify rtg attr set function with error param. 647 * @tc.type: FUNC 648 */ 649HWTEST_F(RtgTest, SetRtgAttrFail, Function | MediumTest | Level1) 650{ 651 int ret; 652 int grpId; 653 grpId = CreateNewRtgGrp(VIP, 0); 654 ASSERT_GT(grpId, 0); 655 ret = SetFrameRateAndPrioType(grpId, 90, -1); 656 ASSERT_NE(ret, RTG_SUCC); 657 ret = DestroyRtgGrp(grpId); 658 ASSERT_EQ(ret, RTG_SUCC); 659} 660 661/** 662 * @tc.name: RtgAddMutipleThreadsSucc 663 * @tc.desc: Verify rtg multiple add function. 664 * @tc.type: FUNC 665 */ 666HWTEST_F(RtgTest, RtgAddMutipleThreadsSucc, Function | MediumTest | Level1) 667{ 668 int ret; 669 int pid[3]; 670 vector<int> threads; 671 int grpId; 672 673 for (int i = 0; i < 3; i++) { 674 pid[i] = fork(); 675 ASSERT_TRUE(pid[i] >= 0) << "> parent: fork errno = " << errno; 676 if (pid[i] == 0) { 677 usleep(50000); 678 _Exit(0); 679 } 680 threads.push_back(pid[i]); 681 } 682 grpId = CreateNewRtgGrp(NORMAL_TASK, 0); 683 ASSERT_GT(grpId, 0); 684 ret = AddThreadsToRtg(threads, grpId, NORMAL_TASK); 685 ASSERT_EQ(ret, RTG_SUCC); 686 ret = DestroyRtgGrp(grpId); 687 ASSERT_EQ(ret, RTG_SUCC); 688} 689 690/** 691 * @tc.name: RtgAddMutipleThreadsOutOfLimit 692 * @tc.desc: Verify rtg multiple add function with out of limit threads. 693 * @tc.type: FUNC 694 */ 695HWTEST_F(RtgTest, RtgAddMutipleThreadsOutOfLimit, Function | MediumTest | Level1) 696{ 697 int ret; 698 int pid[8]; 699 vector<int> threads; 700 int grpId; 701 702 for (int i = 0; i < 8; i++) { 703 pid[i] = fork(); 704 ASSERT_TRUE(pid[i] >= 0) << "> parent: fork errno = " << errno; 705 if (pid[i] == 0) { 706 usleep(50000); 707 _Exit(0); 708 } 709 threads.push_back(pid[i]); 710 } 711 grpId = CreateNewRtgGrp(NORMAL_TASK, 0); 712 ASSERT_GT(grpId, 0); 713 ret = AddThreadsToRtg(threads, grpId, NORMAL_TASK); 714 ASSERT_NE(ret, RTG_SUCC); 715 ret = DestroyRtgGrp(grpId); 716 ASSERT_EQ(ret, RTG_SUCC); 717} 718