<commit_before>/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-01-26     Bernard      Fix pthread_detach issue for a none-joinable
 *                             thread.
 * 2019-02-07     Bernard      Add _pthread_destroy to release pthread resource.
 */

#include <pthread.h>
#include <sched.h>
#include "pthread_internal.h"

#include <rthw.h>
RT_DEFINE_SPINLOCK(pth_lock);
_pthread_data_t *pth_table[PTHREAD_NUM_MAX] = {NULL};

_pthread_data_t *_pthread_get_data(pthread_t thread)
{
    RT_DECLARE_SPINLOCK(pth_lock);
    _pthread_data_t *ptd;

    if (thread >= PTHREAD_NUM_MAX) return NULL;

    rt_hw_spin_lock(&pth_lock);
    ptd = pth_table[thread];
    rt_hw_spin_unlock(&pth_lock);

    if (ptd && ptd->magic == PTHREAD_MAGIC) return ptd;

    return NULL;
}

pthread_t _pthread_data_get_pth(_pthread_data_t *ptd)
{
    int index;
    RT_DECLARE_SPINLOCK(pth_lock);

    rt_hw_spin_lock(&pth_lock);
    for (index = 0; index < PTHREAD_NUM_MAX; index ++)
    {
        if (pth_table[index] == ptd) break;
    }
    rt_hw_spin_unlock(&pth_lock);

    return index;
}

pthread_t _pthread_data_create(void)
{
    int index;
    _pthread_data_t *ptd = NULL;
    RT_DECLARE_SPINLOCK(pth_lock);

    ptd = (_pthread_data_t*)rt_malloc(sizeof(_pthread_data_t));
    if (!ptd) return PTHREAD_NUM_MAX;

    memset(ptd, 0x0, sizeof(_pthread_data_t));
    ptd->canceled = 0;
    ptd->cancelstate = PTHREAD_CANCEL_DISABLE;
    ptd->canceltype = PTHREAD_CANCEL_DEFERRED;
    ptd->magic = PTHREAD_MAGIC;

    rt_hw_spin_lock(&pth_lock);
    for (index = 0; index < PTHREAD_NUM_MAX; index ++)
    {
        if (pth_table[index] == NULL)
        {
            pth_table[index] = ptd;
            break;
        }
    }
    rt_hw_spin_unlock(&pth_lock);

    return index;
}

void _pthread_data_destroy(pthread_t pth)
{
    RT_DECLARE_SPINLOCK(pth_lock);

    _pthread_data_t *ptd = _pthread_get_data(pth);
    if (ptd)
    {
        /* remove from pthread table */
        rt_hw_spin_lock(&pth_lock);
        pth_table[pth] = NULL;
        rt_hw_spin_unlock(&pth_lock);

        /* delete joinable semaphore */
        if (ptd->joinable_sem != RT_NULL)
            rt_sem_delete(ptd->joinable_sem);

        /* release thread resource */
        if (ptd->attr.stackaddr == RT_NULL)
        {
            /* release thread allocated stack */
            rt_free(ptd->tid->stack_addr);
        }
        /* clean stack addr pointer */
        ptd->tid->stack_addr = RT_NULL;
        
        /*
        * if this thread create the local thread data,
        * delete it
        */
        if (ptd->tls != RT_NULL) rt_free(ptd->tls);
        rt_free(ptd->tid);

        /* clean magic */
        ptd->magic = 0x0;

        /* free ptd */
        rt_free(ptd);
    }
}

int pthread_system_init(void)
{
    /* initialize key area */
    pthread_key_system_init();
    /* initialize posix mqueue */
    posix_mq_system_init();
    /* initialize posix semaphore */
    posix_sem_system_init();

    return 0;
}
INIT_COMPONENT_EXPORT(pthread_system_init);

static void _pthread_destroy(_pthread_data_t *ptd)
{
    pthread_t pth = _pthread_data_get_pth(ptd);
    if (pth != PTHREAD_NUM_MAX)
    {
        _pthread_data_destroy(pth);
    }

    return;
}

static void _pthread_cleanup(rt_thread_t tid)
{
    _pthread_data_t *ptd;

    /* get pthread data from user data of thread */
    ptd = (_pthread_data_t *)tid->user_data;
    RT_ASSERT(ptd != RT_NULL);

    /* clear cleanup function */
    tid->cleanup = RT_NULL;
    if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE)
    {
        rt_sem_release(ptd->joinable_sem);
    }
    else
    {
        /* release pthread resource */
        _pthread_destroy(ptd);
    }
}

static void pthread_entry_stub(void *parameter)
{
    void *value;
    _pthread_data_t *ptd;

    ptd = (_pthread_data_t *)parameter;

    /* execute pthread entry */
    value = ptd->thread_entry(ptd->thread_parameter);
    /* set value */
    ptd->return_value = value;
}

int pthread_create(pthread_t            *pid,
                   const pthread_attr_t *attr,
                   void *(*start)(void *), void *parameter)
{
    int ret = 0;
    void *stack;
    char name[RT_NAME_MAX];
    static rt_uint16_t pthread_number = 0;

    pthread_t pth_id;
    _pthread_data_t *ptd;

    /* tid shall be provided */
    RT_ASSERT(pid != RT_NULL);

    /* allocate posix thread data */
    pth_id = _pthread_data_create();
    if (pth_id == PTHREAD_NUM_MAX) 
    {
        ret = ENOMEM;
        goto __exit;
    }

    /* get pthread data */
    ptd = _pthread_get_data(pth_id);<commit_msg>[pthreads] fix the free ptd issue when there is no pthread slot.<commit_after>/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-01-26     Bernard      Fix pthread_detach issue for a none-joinable
 *                             thread.
 * 2019-02-07     Bernard      Add _pthread_destroy to release pthread resource.
 */

#include <rthw.h>
#include <pthread.h>
#include <sched.h>
#include "pthread_internal.h"

RT_DEFINE_SPINLOCK(pth_lock);
_pthread_data_t *pth_table[PTHREAD_NUM_MAX] = {NULL};

_pthread_data_t *_pthread_get_data(pthread_t thread)
{
    RT_DECLARE_SPINLOCK(pth_lock);
    _pthread_data_t *ptd;

    if (thread >= PTHREAD_NUM_MAX) return NULL;

    rt_hw_spin_lock(&pth_lock);
    ptd = pth_table[thread];
    rt_hw_spin_unlock(&pth_lock);

    if (ptd && ptd->magic == PTHREAD_MAGIC) return ptd;

    return NULL;
}

pthread_t _pthread_data_get_pth(_pthread_data_t *ptd)
{
    int index;
    RT_DECLARE_SPINLOCK(pth_lock);

    rt_hw_spin_lock(&pth_lock);
    for (index = 0; index < PTHREAD_NUM_MAX; index ++)
    {
        if (pth_table[index] == ptd) break;
    }
    rt_hw_spin_unlock(&pth_lock);

    return index;
}

pthread_t _pthread_data_create(void)
{
    int index;
    _pthread_data_t *ptd = NULL;
    RT_DECLARE_SPINLOCK(pth_lock);

    ptd = (_pthread_data_t*)rt_malloc(sizeof(_pthread_data_t));
    if (!ptd) return PTHREAD_NUM_MAX;

    memset(ptd, 0x0, sizeof(_pthread_data_t));
    ptd->canceled = 0;
    ptd->cancelstate = PTHREAD_CANCEL_DISABLE;
    ptd->canceltype = PTHREAD_CANCEL_DEFERRED;
    ptd->magic = PTHREAD_MAGIC;

    rt_hw_spin_lock(&pth_lock);
    for (index = 0; index < PTHREAD_NUM_MAX; index ++)
    {
        if (pth_table[index] == NULL)
        {
            pth_table[index] = ptd;
            break;
        }
    }
    rt_hw_spin_unlock(&pth_lock);

    /* full of pthreads, clean magic and release ptd */
    if (index == PTHREAD_NUM_MAX)
    {
        ptd->magic = 0x0;
        rt_free(ptd);
    }

    return index;
}

void _pthread_data_destroy(pthread_t pth)
{
    RT_DECLARE_SPINLOCK(pth_lock);

    _pthread_data_t *ptd = _pthread_get_data(pth);
    if (ptd)
    {
        /* remove from pthread table */
        rt_hw_spin_lock(&pth_lock);
        pth_table[pth] = NULL;
        rt_hw_spin_unlock(&pth_lock);

        /* delete joinable semaphore */
        if (ptd->joinable_sem != RT_NULL)
            rt_sem_delete(ptd->joinable_sem);

        /* release thread resource */
        if (ptd->attr.stackaddr == RT_NULL)
        {
            /* release thread allocated stack */
            rt_free(ptd->tid->stack_addr);
        }
        /* clean stack addr pointer */
        ptd->tid->stack_addr = RT_NULL;

        /*
        * if this thread create the local thread data,
        * delete it
        */
        if (ptd->tls != RT_NULL) rt_free(ptd->tls);
        rt_free(ptd->tid);

        /* clean magic */
        ptd->magic = 0x0;

        /* free ptd */
        rt_free(ptd);
    }
}

int pthread_system_init(void)
{
    /* initialize key area */
    pthread_key_system_init();
    /* initialize posix mqueue */
    posix_mq_system_init();
    /* initialize posix semaphore */
    posix_sem_system_init();

    return 0;
}
INIT_COMPONENT_EXPORT(pthread_system_init);

static void _pthread_destroy(_pthread_data_t *ptd)
{
    pthread_t pth = _pthread_data_get_pth(ptd);
    if (pth != PTHREAD_NUM_MAX)
    {
        _pthread_data_destroy(pth);
    }

    return;
}

static void _pthread_cleanup(rt_thread_t tid)
{
    _pthread_data_t *ptd;

    /* get pthread data from user data of thread */
    ptd = (_pthread_data_t *)tid->user_data;
    RT_ASSERT(ptd != RT_NULL);

    /* clear cleanup function */
    tid->cleanup = RT_NULL;
    if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE)
    {
        rt_sem_release(ptd->joinable_sem);
    }
    else
    {
        /* release pthread resource */
        _pthread_destroy(ptd);
    }
}

static void pthread_entry_stub(void *parameter)
{
    void *value;
    _pthread_data_t *ptd;

    ptd = (_pthread_data_t *)parameter;

    /* execute pthread entry */
    value = ptd->thread_entry(ptd->thread_parameter);
    /* set value */
    ptd->return_value = value;
}

int pthread_create(pthread_t            *pid,
                   const pthread_attr_t *attr,
                   void *(*start)(void *), void *parameter)
{
    int ret = 0;
    void *stack;
    char name[RT_NAME_MAX];
    static rt_uint16_t pthread_number = 0;

    pthread_t pth_id;
    _pthread_data_t *ptd;

    /* pid shall be provided */
    RT_ASSERT(pid != RT_NULL);

    /* allocate posix thread data */
    pth_id = _pthread_data_create();
    if (pth_id == PTHREAD_NUM_MAX) 
    {
        ret = ENOMEM;
        goto __exit;
    }
    /* get pthread data */
    ptd = _pthread_get_data(pth_id);
{'fraction_non_alphanumeric': 0.11171152447261769, 'fraction_numerical': 0.008105580380338772, 'mean_word_length': 2.497093023255814, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 58, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6940247', 'n_tokens_mistral': 3648, 'n_tokens_neox': 3519, 'n_words': 666}