/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <algorithm>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/resource.h>
#include "eu/cpu_worker.h"
#include "eu/osattr_manager.h"
#include "eu/qos_interface.h"
#include "util/name_manager.h"
#include "util/ffrt_facade.h"
#include "internal_inc/osal.h"
#include "util/white_list.h"

namespace {
constexpr int CFS_PRIO_MIN = 1;
constexpr int CFS_PRIO_DEFAULT = 20;
constexpr int CFS_PRIO_MAX = 40;
constexpr int VIP_PRIO_MIN = 41;
constexpr int VIP_PRIO_MAX = 50;
constexpr int RT_PRIO_MIN = 51;
constexpr int RT_PRIO_MAX = 139;
constexpr int THREAD_INDEX_MAX = 99999;
}

namespace ffrt {
void CPUWorker::WorkerSetup()
{
    static std::atomic<uint64_t> threadIndex[QoS::MaxNum()] = {0};
    std::string qosStr = std::to_string(qos());
    uint64_t index = threadIndex[qos()].fetch_add(1, std::memory_order_seq_cst);
    if (index > THREAD_INDEX_MAX) {
        index %= THREAD_INDEX_MAX;
    }
    std::string threadName = std::string(WORKER_THREAD_NAME_PREFIX) + qosStr +
        std::string(WORKER_THREAD_SYMBOL) + std::to_string(index);
    if (qosStr == "") {
        FFRT_SYSEVENT_LOGE("ffrt threadName qos[%d] index[%d]", qos(), index);
    }
    pthread_setname_np(pthread_self(), threadName.c_str());
}

int SetCpuAffinity(unsigned long affinity, int tid)
{
    cpu_set_t mask;
    CPU_ZERO(&mask);
    for (unsigned long i = 0; i < sizeof(affinity) * 8; i++) {
        if ((affinity & (static_cast<unsigned long>(1) << i)) != 0) {
            CPU_SET(i, &mask);
        }
    }
    int ret = syscall(__NR_sched_setaffinity, tid, sizeof(mask), &mask);
    if (ret != 0) {
        FFRT_SYSEVENT_LOGE("set qos affinity failed for tid %d, ret:%d\n", tid, ret);
    }
    return ret;
}

void SetDefaultThreadAttr(CPUWorker* thread, const QoS& qos)
{
    int fd = thread->GetQosCtrlFd();
    if (qos() <= qos_max) {
        FFRTQosApplyForOther(qos(), thread->Id(), fd);
        FFRT_LOGD("qos apply tid[%d] level[%d]\n", thread->Id(), qos());
    }
}

void CPUWorker::SetThreadAttr(const QoS& newQos)
{
    SetDefaultThreadAttr(this, newQos);
}
}