/**
 * @file tkl_thread.c
 * @brief this file was auto-generated by tuyaos v&v tools, developer can add implements between BEGIN and END
 *
 * @warning: changes between user 'BEGIN' and 'END' will be keeped when run tuyaos v&v tools
 *           changes in other place will be overwrited and lost
 *
 * @copyright Copyright 2020-2021 Tuya Inc. All Rights Reserved.
 *
 */

// --- BEGIN: user defines and implements ---
#include "tkl_thread.h"
#include "tuya_error_code.h"
#include "tkl_memory.h"
#include <pthread.h>
#include <sys/prctl.h>
#include <string.h>

typedef struct {
    pthread_t id;
    THREAD_FUNC_T func;
    void *arg;
} THREAD_DATA;

static void *_tkl_thread_wrap_func(void *arg)
{
    THREAD_DATA *thread_data = (THREAD_DATA *)arg;
    if (thread_data && thread_data->func) {
        thread_data->func(thread_data->arg);
    }

    return NULL;
}
// --- END: user defines and implements ---

/**
 * @brief Create thread
 *
 * @param[out] thread: thread handle
 * @param[in] name: thread name
 * @param[in] stack_size: stack size of thread
 * @param[in] priority: priority of thread
 * @param[in] func: the main thread process function
 * @param[in] arg: the args of the func, can be null
 *
 * @note This API is used for creating thread.
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_thread_create(TKL_THREAD_HANDLE *thread, const char *name, uint32_t stack_size, uint32_t priority,
                              const THREAD_FUNC_T func, void *const arg)
{
    // --- BEGIN: user implements ---
    if (!thread) {
        return OPRT_INVALID_PARM;
    }

    int ret = 0;
    THREAD_DATA *thread_data = (THREAD_DATA *)tkl_system_malloc(sizeof(THREAD_DATA));
    if (thread_data == NULL) {
        return OPRT_MALLOC_FAILED;
    }

    memset(thread_data, 0, sizeof(THREAD_DATA));
    // THREAD_DATA thread_data;
    thread_data->id = 0;
    thread_data->func = func;
    thread_data->arg = arg;

    pthread_attr_t attr;
    pthread_attr_init(&attr);
    // pthread_attr_setstacksize(&attr, stack_size);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    ret = pthread_create(&(thread_data->id), &attr, _tkl_thread_wrap_func, thread_data);
    pthread_attr_destroy(&attr);
    if (0 != ret) {
        return OPRT_OS_ADAPTER_THRD_CREAT_FAILED;
    }

    *thread = (TKL_THREAD_HANDLE)thread_data;
    return ret;
    // --- END: user implements ---
}

/**
 * @brief Terminal thread and release thread resources
 *
 * @param[in] thread: thread handle
 *
 * @note This API is used to terminal thread and release thread resources.
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_thread_release(const TKL_THREAD_HANDLE thread)
{
    // --- BEGIN: user implements ---
    if (!thread) {
        return OPRT_INVALID_PARM;
    }

    THREAD_DATA *thread_data = (THREAD_DATA *)thread;
    tkl_system_free(thread_data);

    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief Get the thread stack's watermark
 *
 * @param[in] thread: thread handle
 * @param[out] watermark: watermark in Bytes
 *
 * @note This API is used to get the thread stack's watermark.
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_thread_get_watermark(const TKL_THREAD_HANDLE thread, uint32_t *watermark)
{
    // --- BEGIN: user implements ---
    return OPRT_NOT_SUPPORTED;
    // --- END: user implements ---
}

/**
 * @brief Get the thread thread handle
 *
 * @param[out] thread: thread handle
 *
 * @note This API is used to get the thread handle.
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_thread_get_id(TKL_THREAD_HANDLE *thread)
{
    // --- BEGIN: user implements ---
    pthread_t pid = pthread_self();
    *thread = (TKL_THREAD_HANDLE)pid;

    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief Set name of self thread
 *
 * @param[in] name: thread name
 *
 * @note This API is used to set name of self thread.
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_thread_set_self_name(const char *name)
{
    // --- BEGIN: user implements ---
    if (!name) {
        return OPRT_INVALID_PARM;
    }

    prctl(PR_SET_NAME, name);
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief Check thread is self thread
 *
 * @param[in] thread: thread handle
 * @param[out] is_self: is self thread or not
 *
 * @note This API is used to check thread is self thread.
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_thread_is_self(TKL_THREAD_HANDLE thread, BOOL_T *is_self)
{
    // --- BEGIN: user implements ---
    if (NULL == thread || NULL == is_self) {
        return OPRT_INVALID_PARM;
    }

    THREAD_DATA *thread_data = (THREAD_DATA *)thread;

    *is_self = pthread_equal(thread_data->id, pthread_self());
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief Get thread priority
 *
 * @param[in] thread: thread handle, If NULL indicates the current thread
 * @param[in] priority: thread priority
 *
 * @note This API is used to get thread priority.
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_thread_get_priority(TKL_THREAD_HANDLE thread, int *priority)
{
    // --- BEGIN: user implements ---
    return OPRT_NOT_SUPPORTED;
    // --- END: user implements ---
}

/**
 * @brief Set thread priority
 *
 * @param[in] thread: thread handle, If NULL indicates the current thread
 * @param[in] priority: thread priority
 *
 * @note This API is used to Set thread priority.
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_thread_set_priority(TKL_THREAD_HANDLE thread, int priority)
{
    // --- BEGIN: user implements ---
    return OPRT_NOT_SUPPORTED;
    // --- END: user implements ---
}

/**
 * @brief Diagnose the thread(dump task stack, etc.)
 *
 * @param[in] thread: thread handle
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_thread_diagnose(TKL_THREAD_HANDLE thread)
{
    // --- BEGIN: user implements ---
    return OPRT_NOT_SUPPORTED;
    // --- END: user implements ---
}
