/*
 * 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 <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <time.h>
#include <sched.h>

extern int nanosleep(const struct timespec *req, struct timespec *rem);

// 全局变量
static pthread_mutex_t g_mux = PTHREAD_MUTEX_INITIALIZER;
static volatile int g_testAtforkCount = 0;
static int g_testAtforkPrepare = 0;
static int g_testAtforkParent = 0;

// 函数原型
static void *Doit(void *arg);
static void *Doit1(void *arg);
static void Prepare(void);
static void Parent(void);
static void *PthreadAtforkTest(void *arg);
static int Testcase(void);
void ItTestPthreadAtfork002(void);

// Doit 函数（线程 1）
static void *Doit(void *arg)
{
    int err;
    struct timespec ts = { 2, 0 }; // 睡眠 2 秒

    // 确保全局变量 g_testAtforkCount 为 1
    if (g_testAtforkCount != 1) {
        return NULL;
    }

    // 锁住互斥锁
    err = pthread_mutex_lock(&g_mux);
    if (err != 0) return NULL;

    (void)nanosleep(&ts, NULL);  // 睡眠 2 秒
    err = pthread_mutex_unlock(&g_mux);  // 解锁互斥锁
    if (err != 0) return NULL;

    return NULL;
}

// Doit1 函数（线程 2 - 子进程）
static void *Doit1(void *arg)
{
    int err;
    struct timespec ts = { 2, 0 }; // 睡眠 2 秒

    // 确保全局变量 g_testAtforkCount 为 1
    if (g_testAtforkCount != 1) {
        return NULL;
    }

    // 锁住互斥锁
    err = pthread_mutex_lock(&g_mux);
    if (err != 0) return NULL;

    (void)nanosleep(&ts, NULL);  // 睡眠 2 秒
    err = pthread_mutex_unlock(&g_mux);  // 解锁互斥锁
    if (err != 0) return NULL;

    return NULL;
}

// Prepare 函数（在 fork 前调用）
static void Prepare(void)
{
    int err;

    err = pthread_mutex_unlock(&g_mux);  // 在 fork 前解锁互斥锁
    if (err != 0) return;
    g_testAtforkPrepare++;  // 增加 prepare 计数
}

// Parent 函数（在 fork 后父进程中调用）
static void Parent(void)
{
    int err = pthread_mutex_lock(&g_mux);  // 在父进程中锁住互斥锁
    if (err != 0) return;
    g_testAtforkParent++;  // 增加父进程计数
}

// PthreadAtforkTest 函数（主测试函数）
static void *PthreadAtforkTest(void *arg)
{
    int err, ret;
    int pid;
    int status = 0;
    struct timespec ts = { 1, 0 };
    pthread_t tid;

    g_testAtforkCount = 0;
    g_testAtforkPrepare = 0;
    g_testAtforkParent = 0;

    // 注册 pthread_atfork 的回调函数
    err = pthread_atfork(Prepare, Parent, NULL);  
    if (err != 0) return NULL;

    g_testAtforkCount++;  // 增加计数用于测试

    // 创建一个线程执行 Doit 函数
    err = pthread_create(&tid, NULL, Doit, NULL);  
    if (err != 0) return NULL;

    nanosleep(&ts, NULL);  // 睡眠 1 秒
    pid = fork();  // 创建子进程

    // 检查 Prepare 函数是否被调用
    if (g_testAtforkPrepare != 1) {
        return NULL;
    }

    if (pid == 0) {
        Doit1(NULL);  // 在子进程中执行 Doit1 函数
        exit(10);  // 子进程退出，返回状态 10
    }

    if (pid <= 0) {
        return NULL;
    }

    // 检查 Parent 函数是否被调用
    if (g_testAtforkParent != 1) {
        return NULL;
    }

    // 等待线程执行完毕
    err = pthread_join(tid, NULL);  
    if (err != 0) return NULL;

    // 等待子进程结束
    err = waitpid(pid, &status, 0);  
    status = WEXITSTATUS(status);  // 获取子进程退出状态
    if (err != pid || status != 10) {
        return NULL;
    }

    return NULL;
}

// Testcase 函数（初始化线程调度参数并执行测试）
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);
    if (ret != 0) return ret;

    curThreadPri = param.sched_priority;

    // 初始化线程属性
    ret = pthread_attr_init(&a);  
    if (ret != 0) return ret;

    pthread_attr_setinheritsched(&a, PTHREAD_EXPLICIT_SCHED);
    param.sched_priority = curThreadPri + 2;  // 设置线程优先级为当前优先级 + 2
    pthread_attr_setschedparam(&a, &param);

    // 创建新线程执行 PthreadAtforkTest 函数
    ret = pthread_create(&newPthread, &a, PthreadAtforkTest, 0);  
    if (ret != 0) return ret;

    // 等待新线程执行完毕
    ret = pthread_join(newPthread, NULL);  
    if (ret != 0) return ret;

    return 0;
}

// ItTestPthreadAtfork002 函数（测试用例入口）
void ItTestPthreadAtfork002(void)
{
    TEST_ADD_CASE("IT_PTHREAD_ATFORK_002", Testcase, TEST_POSIX, TEST_MEM, TEST_LEVEL0, TEST_FUNCTION);
    TEST_ADD_CASE("IT_POSIX_PTHREAD_COND_001", TestCase, TEST_POSIX, TEST_PTHREAD, TEST_LEVEL2, TEST_FUNCTION);
}//超级大傻逼 
}

