You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openharmonydocs/pthread_atfork_test_002.cpp

212 lines
7.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "it_pthread_test.h"
#include <time.h>
// 引入系统函数nanosleep该函数用于使当前线程休眠指定的时间。
extern int nanosleep(const struct timespec *req, struct timespec *rem);
// 定义全局互斥锁 g_mux用于同步多线程操作。
static pthread_mutex_t g_mux = PTHREAD_MUTEX_INITIALIZER;
// 定义全局变量跟踪fork相关的操作计数和状态。
static volatile int g_testAtforkCount = 0; // 记录fork次数的计数器
static int g_testAtforkPrepare = 0; // 用于标识准备状态的计数器
static int g_testAtforkParent = 0; // 用于标识父进程状态的计数器
// 线程函数Doit用于在锁保护下进行nanosleep操作。
static void *Doit(void *arg)
{
int err;
struct timespec ts = { 2, 0 }; // 设置休眠时间为2秒第二个参数为纳秒0表示不需要额外的纳秒部分
// 检查g_testAtforkCount是否为1如果不是跳转到EXIT标签。
ICUNIT_GOTO_EQUAL(g_testAtforkCount, 1, g_testAtforkCount, EXIT);
// 锁住g_mux互斥锁保证对共享资源的访问是线程安全的。
err = pthread_mutex_lock(&g_mux);
ICUNIT_GOTO_EQUAL(err, 0, err, EXIT);
// 让当前线程休眠2秒。
(void)nanosleep(&ts, NULL);
// 解锁g_mux互斥锁。
err = pthread_mutex_unlock(&g_mux);
ICUNIT_GOTO_EQUAL(err, 0, err, EXIT);
EXIT:
// 函数结束返回NULL表示没有错误。
return NULL;
}
// 线程函数Doit1与Doit函数功能相同都是进行互斥锁保护下的nanosleep操作。
static void *Doit1(void *arg)
{
int err;
struct timespec ts = { 2, 0 }; // 设置休眠时间为2秒。
// 检查g_testAtforkCount是否为1如果不是跳转到EXIT标签。
ICUNIT_GOTO_EQUAL(g_testAtforkCount, 1, g_testAtforkCount, EXIT);
// 锁住g_mux互斥锁保证对共享资源的访问是线程安全的。
err = pthread_mutex_lock(&g_mux);
ICUNIT_GOTO_EQUAL(err, 0, err, EXIT);
// 让当前线程休眠2秒。
(void)nanosleep(&ts, NULL);
// 解锁g_mux互斥锁。
err = pthread_mutex_unlock(&g_mux);
ICUNIT_GOTO_EQUAL(err, 0, err, EXIT);
EXIT:
// 函数结束返回NULL表示没有错误。
return NULL;
}
// Prepare函数用于准备阶段释放锁并更新g_testAtforkPrepare计数器。
static void Prepare(void)
{
int err;
// 尝试解锁g_mux互斥锁若没有锁住则返回错误。
err = pthread_mutex_unlock(&g_mux);
ICUNIT_ASSERT_EQUAL_VOID(err, 0, err); // 校验解锁是否成功,若不成功则会引发错误。
// 更新g_testAtforkPrepare计数器表示已准备好。
g_testAtforkPrepare++;
}
// Parent函数用于父进程阶段获取锁并更新g_testAtforkParent计数器。
static void Parent(void)
{
int err = pthread_mutex_lock(&g_mux); // 锁住g_mux互斥锁。
ICUNIT_ASSERT_EQUAL_VOID(err, 0, err); // 校验锁住是否成功,若不成功则会引发错误。
// 更新g_testAtforkParent计数器表示父进程已进入阶段。
g_testAtforkParent++;
}
// PthreadAtforkTest函数的作用是进行多线程与fork操作的测试验证pthread_atfork()的行为。
static void *PthreadAtforkTest(void *arg)
{
int err, ret;
int pid;
int status = 0;
struct timespec ts = { 1, 0 }; // 定义一个timespec结构指定nanosleep时休眠1秒。
pthread_t tid; // 定义一个线程ID变量用于存储创建的线程的ID。
// 初始化全局变量跟踪fork相关的操作计数和状态。
g_testAtforkCount = 0;
g_testAtforkPrepare = 0;
g_testAtforkParent = 0;
// 使用pthread_atfork注册处理函数分别为子进程准备函数Prepare和父进程函数Parent。
// NULL表示没有为子进程注册处理函数。
err = pthread_atfork(Prepare, Parent, NULL);
ICUNIT_GOTO_EQUAL(err, 0, err, EXIT); // 如果pthread_atfork返回错误跳转到EXIT标签。
// 将g_testAtforkCount计数器加1表示准备开始执行fork操作。
g_testAtforkCount++;
// 创建一个新线程线程的执行函数是Doit。
err = pthread_create(&tid, NULL, Doit, NULL);
ICUNIT_GOTO_EQUAL(err, 0, err, EXIT); // 如果pthread_create失败跳转到EXIT标签。
// 让当前线程休眠1秒确保线程和主线程有足够的时间进入适当的执行阶段。
nanosleep(&ts, NULL);
// 执行fork系统调用创建一个新进程。
pid = fork();
ICUNIT_GOTO_EQUAL(g_testAtforkPrepare, 1, g_testAtforkPrepare, EXIT); // 确保在fork后Prepare函数已经被调用。
if (pid == 0) { // 子进程执行的代码。
// 调用Doit1函数子进程将在此执行休眠2秒。
Doit1(NULL);
exit(10); // 10表示子进程的退出状态。
}
// 检查pid值是否合法确保fork操作成功并且pid不会超过100000。
ICUNIT_GOTO_WITHIN_EQUAL(pid, 0, 100000, pid, EXIT_WAIT);
// 确保父进程调用了Parent函数更新了g_testAtforkParent计数器。
ICUNIT_GOTO_EQUAL(g_testAtforkParent, 1, g_testAtforkParent, EXIT_WAIT);
// 等待创建的线程结束。
err = pthread_join(tid, NULL);
ICUNIT_GOTO_EQUAL(err, 0, err, EXIT_WAIT); // 如果pthread_join失败跳转到EXIT_WAIT标签。
// 等待子进程结束,并获取其退出状态。
err = waitpid(pid, &status, 0);
status = WEXITSTATUS(status); // 获取子进程的退出状态。
ICUNIT_GOTO_EQUAL(err, pid, err, EXIT); // 检查waitpid返回值是否与pid一致。
ICUNIT_GOTO_EQUAL(status, 10, status, EXIT); // 确保子进程的退出状态是10。
EXIT:
return NULL; // 函数结束返回NULL。
EXIT_WAIT:
// 如果到达EXIT_WAIT标签表示需要等待子进程的结束防止僵尸进程。
(void)waitpid(pid, 0, 0);
return NULL;
}
static int Testcase(void)
{
int ret;
pthread_t newPthread;
int curThreadPri, curThreadPolicy;
pthread_attr_t a = { 0 };
struct sched_param param = { 0 };
ret = pthread_getschedparam(pthread_self(), &curThreadPolicy, &param);
ICUNIT_ASSERT_EQUAL(ret, 0, -ret);
curThreadPri = param.sched_priority;
ret = pthread_attr_init(&a);
pthread_attr_setinheritsched(&a, PTHREAD_EXPLICIT_SCHED);
param.sched_priority = curThreadPri + 2; // 2, adjust the priority.
pthread_attr_setschedparam(&a, &param);
ret = pthread_create(&newPthread, &a, PthreadAtforkTest, 0);
ICUNIT_ASSERT_EQUAL(ret, 0, ret);
ret = pthread_join(newPthread, NULL);
ICUNIT_ASSERT_EQUAL(ret, 0, ret);
return 0;
}
void ItTestPthreadAtfork002(void)
{
TEST_ADD_CASE("IT_PTHREAD_ATFORK_002", Testcase, TEST_POSIX, TEST_MEM, TEST_LEVEL0, TEST_FUNCTION);
}