/**

 * Copyright (c) 2025 Huawei Technologies Co., Ltd.

 * This program is free software, you can redistribute it and/or modify it under the terms and conditions of

 * CANN Open Software License Agreement Version 2.0 (the "License").

 * Please refer to the License for details. You may not use this file except in compliance with the License.

 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,

 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.

 * See LICENSE in the root of the software repository for the full text of the License.

 */



#include <pthread.h>

#include <sys/types.h>

#include <unistd.h>



#include "securec.h"

#include "ascend_hal.h"

#include "esched_ioctl.h"

#include "event_sched.h"

#include "esched_user_interface.h"

#include "dpa_user_interface.h"





#define UNINITED_STATUS 0

#define INITED_STATUS 1



#ifdef CFG_SOC_PLATFORM_CLOUD_V4

#define SVM_SMM_MMAP_EVENT     (DRV_SUBEVENT_SVM_DEV_OPEN_MSG + 6)

#define SVM_SMM_MUNMAP_EVENT   (DRV_SUBEVENT_SVM_DEV_OPEN_MSG + 7)

#define SVM_VA_RESERVE_EVENT   (DRV_SUBEVENT_SVM_DEV_OPEN_MSG + 13)

#endif



THREAD__ int32_t sync_init_status[ESCHED_DEV_NUM] = {0, };

THREAD__ pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;



struct sync_event_res {

    struct event_res res;

    bool occupied_flag;

    pthread_mutex_t res_lock;

};



struct sync_event_aicpu_res {

    int32_t sync_init_status;

    struct sync_event_res thead_res;

};



struct sync_event_wait_info {

    uint32_t grp_id;

    uint32_t thread_id;

    int32_t pid;

    EVENT_ID event_id;

    uint32_t subevent_id;

    int32_t timeout;

};

#define DRV_MSG_EVENT_RES_MAX_NUM 128

THREAD__ struct sync_event_res drv_sync_res[ESCHED_DEV_NUM][DRV_MSG_EVENT_RES_MAX_NUM];



#define EVENT_RES_MAX_NUM 64

THREAD__ struct sync_event_res ccpu_sync_res[ESCHED_DEV_NUM][COMM_EVENT_TYPE_MAX][EVENT_RES_MAX_NUM];

THREAD__ struct sync_event_aicpu_res aicpu_sync_res[ESCHED_DEV_NUM][EVENT_RES_MAX_NUM];

THREAD__ uint32_t aicpu_sync_res_grp[ESCHED_DEV_NUM];



STATIC bool esched_is_svm_alloc_event(uint32_t event_id, uint32_t sub_event_id)

{

#ifdef CFG_SOC_PLATFORM_CLOUD_V4

    return ((event_id == EVENT_DRV_MSG_EX) && ((sub_event_id == SVM_SMM_MMAP_EVENT) ||

        (sub_event_id == SVM_SMM_MUNMAP_EVENT) || (sub_event_id == SVM_VA_RESERVE_EVENT)));

#else

    (void)event_id;

    (void)sub_event_id;

    return false;

#endif

}



STATIC int32_t esched_init_thread_res(uint32_t dev_id, uint32_t gid, uint32_t event_id, uint32_t tid, struct sync_event_res *res)

{

    int32_t ret = 0;

    struct event_info back_event_info = {0};

    unsigned long long event_bitmap = (1UL << event_id);



    ret = (int)halEschedSubscribeEvent(dev_id, gid, tid, event_bitmap);

    if (ret != 0) {

        sched_err("Failed to invoke the halEschedSubscribeEvent. (ret=%d)\n", ret);

        return ret;

    }



    (void)halEschedWaitEvent(dev_id, gid, tid, 0, &back_event_info);

    res->res.gid = gid;

    res->res.tid = tid;

    res->res.event_id = event_id;

    res->res.subevent_id = 0;

    res->occupied_flag = false;

    (void)pthread_mutex_init(&res->res_lock, NULL);



    return DRV_ERROR_NONE;

}



static inline void esched_grp_para_cfg(struct esched_grp_para *grp_para, uint32_t grp_index)

{

    grp_para->type = GRP_TYPE_BIND_CP_CPU;

    grp_para->threadNum = SCHED_MAX_SYNC_THREAD_NUM_PER_GRP;

    (void)snprintf_s(grp_para->grp_name, EVENT_MAX_GRP_NAME_LEN, EVENT_MAX_GRP_NAME_LEN - 1,

        "%s_%u", "ESCHED_GRP", grp_index);

}



STATIC int32_t esched_init_ccpu_grp_res(uint32_t dev_id, uint32_t gid, uint32_t event_type, uint32_t grp_index)

{

    uint32_t thread_idx, event_id, tid;

    int32_t ret = 0;

    struct sync_event_res *res = NULL;



    thread_idx = grp_index * SCHED_MAX_SYNC_THREAD_NUM_PER_GRP;

    for (tid = 0; tid < SCHED_MAX_SYNC_THREAD_NUM_PER_GRP; tid++) {

        res = &ccpu_sync_res[dev_id][event_type][thread_idx];

        event_id = SCHED_SYNC_START_EVENT_ID + tid;

        ret = esched_init_thread_res(dev_id, gid, event_id, tid, res);

        if (ret != 0) {

            sched_err("Failed to init sync thread. (ret=%d; dev_id=%d; gid=%d;)\n", ret, dev_id, gid);

            return ret;

        }

        thread_idx ++;

    }

    return DRV_ERROR_NONE;

}



static long esched_get_cpu(unsigned int *cpu, unsigned int *node)

{

    return syscall(SYS_getcpu, cpu, node, NULL);

}



STATIC struct sync_event_res *esched_get_aicpu_res(uint32_t dev_id)

{

    uint32_t gid, event_id, cpu_id, node;

    int32_t ret = 0;

    struct sync_event_aicpu_res *sync_res = NULL;



    if (esched_get_cpu(&cpu_id, &node) != 0) {

        sched_err("Failed to get cpu id. (dev_id=%u)\n", dev_id);

        return NULL;

    }

    if (cpu_id >= EVENT_RES_MAX_NUM) {

        sched_err("cpu id is invalid. (dev_id=%u; cpu_id=%u)\n", dev_id, cpu_id);

        return NULL;

    }

    

    (void)pthread_mutex_lock(&init_mutex);

    sync_res = &aicpu_sync_res[dev_id][cpu_id];

    if (sync_res->sync_init_status == INITED_STATUS) {

        goto out;

    }



    gid = aicpu_sync_res_grp[dev_id];

    event_id = SCHED_SYNC_START_EVENT_ID + cpu_id;

    ret = esched_init_thread_res(dev_id, gid, event_id, cpu_id, &sync_res->thead_res);

    if (ret != 0) {

        sched_err("Failed to subscribe thread. (ret=%d)\n", ret);

        (void)pthread_mutex_unlock(&init_mutex);

        return NULL;

    }

    sync_res->sync_init_status = INITED_STATUS;

    sched_info("Init aicpu sync msg thread. (cpu_id=%u; gid=%u)\n", cpu_id, gid);

out:

    (void)pthread_mutex_unlock(&init_mutex);

    return &sync_res->thead_res;

}



STATIC void esched_sync_res_invalid(uint32_t dev_id)

{

    uint32_t tid, cpuid, event_type;

    struct sync_event_res *res = NULL;

    for (event_type = NORMAL_EVENT; event_type < COMM_EVENT_TYPE_MAX; event_type++) {

        for (tid = 0; tid < EVENT_RES_MAX_NUM; tid++) {

            res = &ccpu_sync_res[dev_id][event_type][tid];

            res->occupied_flag = true;

        }

    }



    for (cpuid = 0; cpuid < EVENT_RES_MAX_NUM; cpuid++) {

        res = &aicpu_sync_res[dev_id][cpuid].thead_res;

        res->occupied_flag = true;

    }



    for (cpuid = 0; cpuid < DRV_MSG_EVENT_RES_MAX_NUM; cpuid++) {

        res = &drv_sync_res[dev_id][cpuid];

        res->occupied_flag = true;

    }



    aicpu_sync_res_grp[dev_id] = 0;

}



void esched_sync_res_reset(uint32_t dev_id)

{

    uint32_t i;



    (void)pthread_mutex_lock(&init_mutex);

    sync_init_status[dev_id] = UNINITED_STATUS;

    for (i = 0; i < EVENT_RES_MAX_NUM; i++) {

        aicpu_sync_res[dev_id][i].sync_init_status = UNINITED_STATUS;

    }

    aicpu_sync_res_grp[dev_id] = 0;

    (void)pthread_mutex_unlock(&init_mutex);

}



STATIC int32_t esched_ccpu_res_init(uint32_t dev_id)

{

    int32_t ret = 0;

    uint32_t inited_num = 0;

    uint32_t gid, curr_grp_index, i, event_type, cur_grp_num;

    struct esched_grp_para grp_para = {0};

    int32_t grp_num_per_event_type[COMM_EVENT_TYPE_MAX] = {4, 4, 4, 4};



    /* support gid_index(0-15) and event_id(28-43) used for sync event res */

    for (event_type = 0; event_type < COMM_EVENT_TYPE_MAX; event_type++) {

        cur_grp_num = (uint32_t)grp_num_per_event_type[event_type];

        if ((cur_grp_num + inited_num) > SCHED_MAX_SYNC_GRP_NUM) {

            sched_err("sync group config error. (grp_inited_num=%u; event_type=%u)\n", inited_num, event_type);

            return DRV_ERROR_PARA_ERROR;

        }

        for (i = 0; i < cur_grp_num; i++) {

            curr_grp_index = i + inited_num;

            esched_grp_para_cfg(&grp_para, curr_grp_index);

            ret = (int)halEschedCreateGrpEx(dev_id, &grp_para, &gid);

            if (ret != 0) {

                sched_err("Failed to create group. (grp_index=%u; ret=%d)\n", curr_grp_index, ret);

                return ret;

            }

            ret = esched_init_ccpu_grp_res(dev_id, gid, event_type, i);

            if (ret != 0) {

                sched_err("Failed to init sync group. (grp_index=%u; ret=%d)\n", curr_grp_index, ret);

                return ret;

            }

        }

        inited_num += cur_grp_num;

    }

    return ret;

}



STATIC int32_t esched_aicpu_res_init(uint32_t dev_id)

{

    int32_t ret, len;

    uint32_t gid;

    struct esched_grp_para grp_para = {0};



    grp_para.type = GRP_TYPE_BIND_DP_CPU;

    grp_para.threadNum = EVENT_RES_MAX_NUM;

    len = snprintf_s(grp_para.grp_name, EVENT_MAX_GRP_NAME_LEN, EVENT_MAX_GRP_NAME_LEN - 1, "%s", "ESCHED_GRP_AI");

    if (len <= 0) {

        sched_err("Failed to init grp_name. (dev_id=%d)\n", dev_id);

        return DRV_ERROR_PARA_ERROR;

    }



    ret = (int)halEschedCreateGrpEx(dev_id, &grp_para, &gid);

    if (ret != 0) {

        sched_err("Failed to create aicpu group. (ret=%d)\n", ret);

        return ret;

    }

    aicpu_sync_res_grp[dev_id] = gid;

    sched_info("Init aicpu sync msg grp. (gid=%u)\n", gid);

    return ret;

}



STATIC int32_t esched_drv_res_init(uint32_t dev_id)

{

    drvError_t ret;

    int32_t len;

    uint32_t gid, tid;

    struct esched_grp_para grp_para = {0};

    struct sync_event_res *res = NULL;



    grp_para.type = GRP_TYPE_BIND_CP_CPU;

    grp_para.threadNum = DRV_MSG_EVENT_RES_MAX_NUM;

    len = snprintf_s(grp_para.grp_name, EVENT_MAX_GRP_NAME_LEN, EVENT_MAX_GRP_NAME_LEN - 1, "%s", "DRV_ESCHED_GRP");

    if (len <= 0) {

        sched_err("Failed to init grp_name. (dev_id=%d)\n", dev_id);

        return DRV_ERROR_PARA_ERROR;

    }



    ret = halEschedCreateGrpEx(dev_id, &grp_para, &gid);

    if (ret != DRV_ERROR_NONE) {

        sched_err("Call hal_esched_create_grp failed. (dev_id=%u, ret=%d)\n", dev_id, (int)ret);

        return ret;

    }



    for (tid = 0; tid < DRV_MSG_EVENT_RES_MAX_NUM; tid++) {

        res = &drv_sync_res[dev_id][tid];

        ret = esched_init_thread_res(dev_id, gid, EVENT_DRV_MSG_EX, tid, res);

        if (ret != 0) {

            sched_err("Failed to init sync thread. (ret=%d; dev_id=%d; gid=%d;)\n", ret, dev_id, gid);

            return ret;

        }

    }

    sched_info("Init drv inner sync res group success. (dev_id=%u, gid=%u)\n", dev_id, gid);



    return DRV_ERROR_NONE;

}



STATIC int32_t esched_res_init(uint32_t dev_id)

{

    int32_t ret = 0;



    (void)pthread_mutex_lock(&init_mutex);

    if (sync_init_status[dev_id] == INITED_STATUS) {

        goto out;

    }

    esched_sync_res_invalid(dev_id);



    ret = (int)halEschedAttachDevice(dev_id);

    if ((ret != 0) && (ret != DRV_ERROR_PROCESS_REPEAT_ADD)) {

        sched_err("Failed to attach device. (ret=%d)\n", ret);

        goto out;

    }



    ret = esched_ccpu_res_init(dev_id);

    if (ret != 0) {

        sched_err("Failed to init comm res. (ret=%d)\n", ret);

        goto out;

    }



    ret = esched_aicpu_res_init(dev_id);

    if (ret != 0) {

        sched_err("Failed to init aicpu res. (ret=%d)\n", ret);

        goto out;

    }



    ret = esched_drv_res_init(dev_id);

    if (ret != 0) {

        sched_err("Failed to init drv res. (ret=%d)\n", ret);

        goto out;

    }

    sync_init_status[dev_id] = INITED_STATUS;

    sched_info("Init sync res group success. (dev_id=%u)\n", dev_id);

out:

    (void)pthread_mutex_unlock(&init_mutex);

    return ret;

}



STATIC struct sync_event_res *esched_get_event_res_pool(uint32_t dev_id, int32_t event_type, int32_t *max_thread)

{

    int32_t thread_num;

    struct sync_event_res *res = NULL;



    switch (event_type) {

        case DRV_INNER_EVENT:

            thread_num = DRV_MSG_EVENT_RES_MAX_NUM;

            res = &drv_sync_res[dev_id][0];

            break;

        case QUEUE_ACPU_EVENT:

            thread_num = 1;

            res = esched_get_aicpu_res(dev_id);

            break;

        default :

            thread_num = EVENT_RES_MAX_NUM;

            res = &ccpu_sync_res[dev_id][event_type][0];

            break;

    }

    *max_thread = thread_num;

    return res;

}



STATIC int32_t esched_find_idle_res(struct sync_event_res *res, int32_t max_thread, struct event_res *e_res)

{

#ifndef EMU_VCAST_ST

    int32_t i;



    for (i = 0; i < max_thread; i++) {

        (void)pthread_mutex_lock(&res[i].res_lock);

        if (res[i].occupied_flag == false) {

            res[i].res.subevent_id++;

            res[i].res.subevent_id = (res[i].res.subevent_id >= SCHED_SYNC_MAX_SUB_EVENT_ID) ? 0 : res[i].res.subevent_id;

            *e_res = res[i].res;

            res[i].occupied_flag = true;

            (void)pthread_mutex_unlock(&res[i].res_lock);

            return 0;

        }

        (void)pthread_mutex_unlock(&res[i].res_lock);

    }

    return (int32_t)DRV_ERROR_NO_EVENT_RESOURCES;

#else

    return 0;

#endif

}



int32_t esched_alloc_event_res(uint32_t dev_id, int32_t event_type, struct event_res *e_res)

{

    int32_t max_thread, ret;

    struct sync_event_res *res = NULL;



    if ((esched_device_check(dev_id) != 0) || (event_type >= EVENT_TYPE_BUTT)) {

        sched_err("Invalid para. (dev_id=%u; event_type=%d)\n", dev_id, event_type);

        return DRV_ERROR_PARA_ERROR;

    }



    ret = esched_res_init(dev_id);

    if (ret != 0) {

        sched_err("esched_res_init failed. (ret=%d; dev_id=%u; event_type=%d)\n", ret, dev_id, event_type);

        return ret;

    }



    res = esched_get_event_res_pool(dev_id, event_type, &max_thread);

    if (res == NULL) {

        sched_err("sync res alloc failed. (ret=%d; dev_id=%u; event_type=%d)\n", ret, dev_id, event_type);

        return ret;

    }



    return esched_find_idle_res(res, max_thread, e_res);

}



STATIC void esched_ccpu_res_free(uint32_t devId, int32_t event_type, const struct event_res *e_res)

{

    struct sync_event_res *res = NULL;

    int32_t i;



    for (i = 0; i < (int32_t)EVENT_RES_MAX_NUM; i++) {

        res = &ccpu_sync_res[devId][event_type][i];

        (void)pthread_mutex_lock(&res->res_lock);

        if ((e_res->gid == res->res.gid) && (e_res->tid == res->res.tid) && (e_res->event_id == res->res.event_id)) {

            res->occupied_flag = false;

            (void)pthread_mutex_unlock(&res->res_lock);

            return;

        }

        (void)pthread_mutex_unlock(&res->res_lock);

    }

}



STATIC void esched_aicpu_res_free(uint32_t dev_id)

{

    struct sync_event_res *res = esched_get_aicpu_res(dev_id);



    if (res == NULL) {

        sched_err("get res failed. (dev_id=%u)\n", dev_id);

        return;

    }



    (void)pthread_mutex_lock(&res->res_lock);

    if (res->occupied_flag == false) {

        (void)pthread_mutex_unlock(&res->res_lock);

        sched_info("aicpu sync res exception. (dev_id=%u; tid=%d)\n", dev_id, res->res.tid);

        return;

    }

    res->occupied_flag = false;

    (void)pthread_mutex_unlock(&res->res_lock);

}



STATIC void esched_drv_res_free(uint32_t dev_id, const struct event_res *e_res)

{

    struct sync_event_res *res = NULL;

    uint32_t tid = e_res->tid;



    if (tid >= DRV_MSG_EVENT_RES_MAX_NUM) {

        sched_err("Invalid para. (dev_id=%u; tid=%d)\n", dev_id, tid);

        return;

    }



    res = &drv_sync_res[dev_id][tid];

    (void)pthread_mutex_lock(&res->res_lock);

    if (res->occupied_flag == false) {

        (void)pthread_mutex_unlock(&res->res_lock);

        sched_err("sync res exception. (dev_id=%u; tid=%d)\n", dev_id, tid);

        return;

    }

    res->occupied_flag = false;

    (void)pthread_mutex_unlock(&res->res_lock);

}





void esched_free_event_res(uint32_t dev_id, int32_t event_type, const struct event_res *e_res)

{

    if ((esched_device_check(dev_id) != 0) || (event_type >= EVENT_TYPE_BUTT)) {

        sched_err("Invalid para. (dev_id=%u; event_type=%d)\n", dev_id, event_type);

        return;

    }



    switch (event_type) {

        case DRV_INNER_EVENT:

            esched_drv_res_free(dev_id, e_res);

            break;

        case QUEUE_ACPU_EVENT:

            esched_aicpu_res_free(dev_id);

            break;

        default :

            esched_ccpu_res_free(dev_id, event_type, e_res);

            break;

    }

    return;

}



void esched_fill_sync_msg(struct event_summary *event, const struct event_res *res)

{

    unsigned int dst_engine;



    (void)dst_engine;

    dst_engine = event->dst_engine;

    ((struct event_sync_msg *)event->msg)->pid = (uint32_t)GETPID() & 0x3FFFFF;



#if !defined (CFG_SOC_PLATFORM_HELPER)

#ifdef CFG_ENV_HOST

    if ((dst_engine == ACPU_DEVICE) || (dst_engine == CCPU_DEVICE) || (dst_engine == DCPU_DEVICE)) {

        ((struct event_sync_msg *)event->msg)->pid = (uint32_t)drvDeviceGetBareTgid() & 0x3FFFFF;

    }

#else

    if ((dst_engine == ACPU_HOST) || (dst_engine == CCPU_HOST)) {

        ((struct event_sync_msg *)event->msg)->pid = drvDeviceGetBareTgid();

    }

#endif

#endif



#ifdef CFG_ENV_HOST

    ((struct event_sync_msg *)event->msg)->dst_engine = CCPU_HOST;

#else

#ifdef CFG_SOC_PLATFORM_HELPER

    ((struct event_sync_msg *)event->msg)->dst_engine = CCPU_HOST;

#else

    ((struct event_sync_msg *)event->msg)->dst_engine = CCPU_DEVICE;

#endif

#endif

    ((struct event_sync_msg *)event->msg)->gid = (uint32_t)res->gid & 0x3F;

    ((struct event_sync_msg *)event->msg)->event_id = (uint32_t)res->event_id & 0x3F;

    ((struct event_sync_msg *)event->msg)->subevent_id = res->subevent_id;

    ((struct event_sync_msg *)event->msg)->tid = (uint32_t)res->tid & 0xFF;

}



void esched_fill_sync_msg_for_peer_que(uint32_t dev_id, uint32_t phy_dev_id, struct event_summary *event, const struct event_res *res)

{

    esched_fill_sync_msg(event, res);



#ifdef CFG_ENV_HOST

    uint32_t host_id = ESCHED_DEV_NUM;

    drvError_t ret = halGetHostID(&host_id);

    if (ret != DRV_ERROR_NONE) {

        sched_err("drv update host_id failed. (ret=%d)\n", ret);

    }

    if (dev_id == host_id) {

        ((struct event_sync_msg *)event->msg)->dst_engine = VIRTUAL_CCPU_HOST;

    }

#else

    unsigned int sched_mode = esched_get_cpu_mode(dev_id);

    ((struct event_sync_msg *)event->msg)->dst_engine = (sched_mode) ? SPECIFYED_ACPU_DEVICE : SPECIFYED_CCPU_DEVICE;

    ((struct event_sync_msg *)event->msg)->tid = res->tid;

#endif

    ((struct event_sync_msg *)event->msg)->dev_id = (uint32_t)phy_dev_id & 0x3F;

}



#if defined(CFG_ENV_HOST) && defined(CFG_SOC_PLATFORM_CLOUD_V4)

#define SVM_SYNC_EVENT_SINGLE_WAIT_TIME (10 * 1000)  /* 10s */

#endif

static int esched_wait_sync_event(uint32_t dev_id, struct sync_event_wait_info *wait_info, struct event_info *back_event_info)

{

#if defined(CFG_ENV_HOST) && defined(CFG_SOC_PLATFORM_CLOUD_V4)

    int32_t ret;

    int32_t timeout = wait_info->timeout;

    int32_t wait_time;

    int32_t query_ret;



    if ((wait_info->subevent_id >= DRV_SUBEVENT_SVM_DEV_OPEN_MSG) && (wait_info->subevent_id < DRV_SUBEVENT_HDC_CREATE_LINK_MSG)) {

        if (timeout > SVM_SYNC_EVENT_SINGLE_WAIT_TIME) {

            while (timeout > 0) {

                wait_time = timeout > SVM_SYNC_EVENT_SINGLE_WAIT_TIME ? SVM_SYNC_EVENT_SINGLE_WAIT_TIME : timeout;

                timeout = timeout - wait_time;

                ret = (int)esched_wait_event_ex(dev_id, wait_info->grp_id, wait_info->thread_id, wait_time, back_event_info);

                if (ret != DRV_ERROR_WAIT_TIMEOUT) {

                    return ret;

                }

                query_ret = halQueryMasterPidByDeviceSlave(dev_id, wait_info->pid, NULL, NULL);

                if (query_ret != 0) {

                    sched_run_info("Query device pid not success. (devid=%d, pid=%d; ret=%d)\n", dev_id, wait_info->pid, query_ret);

                    return query_ret;

                }

            }

        } else {

            ret = (int)esched_wait_event_ex(dev_id, wait_info->grp_id, wait_info->thread_id, timeout, back_event_info);

        }

    } else {

        ret = (int)esched_wait_event_ex(dev_id, wait_info->grp_id, wait_info->thread_id, timeout, back_event_info);

    }

    return ret;

#else

    return (int)esched_wait_event_ex(dev_id, wait_info->grp_id, wait_info->thread_id, wait_info->timeout, back_event_info);

#endif

}



static void esched_fill_wait_info(struct sync_event_wait_info *wait_info, struct event_summary *event,

    struct event_res *res, int32_t timeout)

{

    wait_info->grp_id = res->gid;

    wait_info->thread_id = res->tid;

    wait_info->pid = event->pid;

    wait_info->event_id = event->event_id;

    wait_info->subevent_id = event->subevent_id;

    wait_info->timeout = timeout;

    return;

}



drvError_t halEschedSubmitEventSync(uint32_t devId, struct event_summary *event, int32_t timeout,

    struct event_reply *reply)

{

    int wait_succ_cnt = 0;

    int32_t ret, event_type;

    struct event_res res;

    struct event_info back_event_info;

    esched_event_buffer *event_buffer = (esched_event_buffer *)back_event_info.priv.msg;

    unsigned long long timestamp = esched_get_cur_cpu_tick();

    struct sync_event_wait_info wait_info = {0};



    if (event == NULL || reply == NULL) {

        sched_err("The variable event or reply is NULL.\n");

        return DRV_ERROR_PARA_ERROR;

    }



    if (event->msg == NULL || event->msg_len < sizeof(struct event_sync_msg)) {

        sched_err("The event->msg is NULL or event->msg_len is invalid. (msg_len=%u)\n", event->msg_len);

        return DRV_ERROR_PARA_ERROR;

    }



    event_type = (event->event_id == EVENT_DRV_MSG_EX) ? DRV_INNER_EVENT : NORMAL_EVENT;

    ret = esched_alloc_event_res(devId, event_type, &res);

    if (ret != 0) {

        sched_err("Failed to invoke the Esched_sync_init. (ret=%d)\n", ret);

        return ret;

    }



    if (event_type == DRV_INNER_EVENT) {

        res.subevent_id = (uint32_t)event->subevent_id & 0xFFF;

    }

    esched_fill_sync_msg(event, &res);

    ret = (int)halEschedSubmitEvent(devId, event);

    if (ret != 0) {

        /* flowgw maybe not ready, client will retry. */

        sched_warn("Unable to invoke the halEschedSubmitEvent. (devId=%u, event_id=%u; ret=%d)\n",

            devId, event->event_id, ret);

        esched_free_event_res(devId, event_type, &res);

        return ret;

    }



    event_buffer->msg = reply->buf;

    event_buffer->msg_len = reply->buf_len;



    do {

        esched_fill_wait_info(&wait_info, event, &res, timeout);

        ret = esched_wait_sync_event(devId, &wait_info, &back_event_info);

        if (ret != 0) {

            if ((ret == DRV_ERROR_WAIT_TIMEOUT) || (esched_is_svm_alloc_event(event->event_id, event->subevent_id))) {

                sched_run_info("Sync event not success. (ret=%d; dst_pid=%d; event_id=%u; subevent_id=%u; "

                    "sync_gid=%u; sync_event_id=%u; sync_subevent_id=%u; sync_tid=%u; timeout=%dms; current_tick=%llu)\n",

                    ret, event->pid, event->event_id, event->subevent_id, res.gid, res.event_id, res.subevent_id, res.tid, timeout, timestamp);

            } else {

                sched_err("Sync event failed. (ret=%d; dst_pid=%d; event_id=%u; subevent_id=%u; "

                    "sync_gid=%u; sync_event_id=%u; sync_subevent_id=%u; sync_tid=%u; timeout=%dms; current_tick=%llu)\n",

                    ret, event->pid, event->event_id, event->subevent_id, res.gid, res.event_id, res.subevent_id, res.tid, timeout, timestamp);

            }

            if (ret == DRV_ERROR_WAIT_TIMEOUT) {

                esched_query_sync_msg_trace(devId, event, res.gid, res.tid);

            }

            esched_free_event_res(devId, event_type, &res);

            return ret;

        }



        wait_succ_cnt++;

        if ((back_event_info.comm.submit_timestamp >= timestamp) &&

            (back_event_info.comm.subevent_id == res.subevent_id)) {

            break;

        }



        sched_run_info("Successfully waited for an event but the condition was not met. (devid=%u; gid=%u; "

            "tid=%u; cnt=%d; check_time=%llu; back_time=%llu; check_subevent=%u; back_subevent=%u)\n",

            devId, res.gid, res.tid, wait_succ_cnt, timestamp, back_event_info.comm.submit_timestamp,

            res.subevent_id, back_event_info.comm.subevent_id);

    } while (1);



    esched_free_event_res(devId, event_type, &res);



    reply->reply_len = back_event_info.priv.msg_len;



    return 0;

}