1
0
mirror of https://github.com/azure-rtos/threadx synced 2025-02-06 08:08:27 +08:00
Bo Chen (from Dev Box) 8276bcf711 Update copyright.
2024-01-29 13:51:15 +08:00

265 lines
12 KiB
C

/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* SPDX-License-Identifier: MIT
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** POSIX wrapper for THREADX */
/** */
/** */
/** */
/**************************************************************************/
/**************************************************************************/
/* Include necessary system files. */
#include "tx_api.h" /* Threadx API */
#include "pthread.h" /* Posix API */
#include "px_int.h" /* Posix helper functions */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* pthread_create PORTABLE C */
/* 6.2.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This creates a new thread with attributes specified by attr within */
/* a process.If the attr is NULL,then default attributes are used. */
/* Upon successful completion, pthread_create() stores the ID of the */
/* created thread in the location referenced by thread. */
/* The thread is created executing start_routine with arg as its sole */
/* argument. */
/* Initially, threads are created from within a process. Once created, */
/* threads are peers, and may create other threads. Note that an */
/* "initial thread" exists by default which runs 'main' */
/* If pthread_create( ) fails,no new thread is created and the contents*/
/* of the location referenced by thread are undefined. */
/* */
/* INPUT */
/* */
/* thread place to store newly created thread ID */
/* Each thread in a process is uniquely */
/* identified during its lifetime by a */
/* value of type pthread_t called as */
/* thread ID. */
/* */
/* attr attributes object , NULL = Default attr.*/
/* start_routine thread start up routine */
/* arg arguments to start up routine by ref. */
/* */
/* OUTPUT */
/* */
/* zero If successful */
/* error number If fails */
/* pthread_create() function will fail if: */
/* [EAGAIN] system lacked the necessary */
/* resources to create a thread, */
/* or the system-imposed limit on */
/* the number of pthreads in */
/* a process PTHREAD_THREADS_MAX */
/* would be exceeded. */
/* [EINVAL] value specified by attr is */
/* invalid. */
/* [EPERM] The caller does not have */
/* appropriate permission to set */
/* the required scheduling */
/* parameters or scheduling policy*/
/* */
/* This call will not return an error code of [EINTR]*/
/* */
/* */
/* CALLS */
/* */
/* posix_in_thread_context To check calling context. */
/* posix_internal_error Internal error */
/* posix_allocate_pthread_t Allocate control block for pthread */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 06-02-2021 William E. Lamie Initial Version 6.1.7 */
/* 10-31-2022 Scott Larson Add 64-bit support, */
/* remove double parenthesis, */
/* resulting in version 6.2.0 */
/* */
/**************************************************************************/
INT pthread_create (pthread_t *thread, pthread_attr_t *attr,
void *(*start_routine)(void*),void *arg)
{
TX_INTERRUPT_SAVE_AREA
TX_THREAD *thread_ptr;
POSIX_TCB *pthread_ptr, *current_thread_ptr;
INT status,retval;
/* Make sure we're calling this routine from a thread context. */
if (!posix_in_thread_context())
{
/* return POSIX error. */
posix_internal_error(444);
}
/* Disable interrupts. */
/* check for any pthread_t attr suggested */
if (!attr)
{
/* no attributes passed so assume default attributes */
attr = &(posix_default_pthread_attr);
}
else
{
/* Check attributes passed , check for validity */
if ( (attr->inuse) == TX_FALSE)
{
/* attributes passed are not valid, return with an error */
posix_errno = EINVAL;
posix_set_pthread_errno(EINVAL);
return(EINVAL);
}
}
/* Get a pthread control block for this new pthread */
TX_DISABLE
status = posix_allocate_pthread_t(&pthread_ptr);
TX_RESTORE
/* Make sure we got a Thread control block */
if ((status == ERROR) || (!pthread_ptr))
{
/* Configuration/resource error. */
return(EAGAIN);
}
if(attr->inherit_sched==PTHREAD_INHERIT_SCHED)
{
/* get current thread tcb */
current_thread_ptr=posix_tid2tcb(pthread_self());
/* copy scheduling attributes */
pthread_ptr->current_priority = current_thread_ptr->current_priority ;
pthread_ptr->detach_state = current_thread_ptr->detach_state ;
pthread_ptr->inherit_sched = current_thread_ptr->inherit_sched ;
pthread_ptr->orig_priority = current_thread_ptr->orig_priority ;
pthread_ptr->sched_attr.sched_priority= current_thread_ptr->sched_attr.sched_priority ;
pthread_ptr->pthread_flags = current_thread_ptr->pthread_flags ;
pthread_ptr->sched_policy = current_thread_ptr->sched_policy;
pthread_ptr->stack_size = current_thread_ptr->stack_size ;
pthread_ptr->stack_address = NULL; /* will allocate our own stack */
pthread_ptr->threshold = pthread_ptr->current_priority ; /* preemption threshold */
}
else /* assume PTHREAD_EXPLICIT_SCHED */
{
/* copy pthread-attr to TCB */
posix_copy_pthread_attr(pthread_ptr,attr);
/* preemption treshold */
pthread_ptr->threshold = pthread_ptr->current_priority ;
/* scheduling */
if(pthread_ptr->sched_policy==SCHED_RR) pthread_ptr->time_slice = SCHED_RR_TIME_SLICE;
else pthread_ptr->time_slice = 0;
}
/* Now set up pthread initial parameters */
pthread_ptr->entry_parameter = arg;
pthread_ptr->start_routine = start_routine;
/* Newly created pthread not joined by anybody! */
pthread_ptr->is_joined_by = TX_FALSE;
pthread_ptr->joined_by_pthreadID =TX_FALSE;
/* Newly created pthread not yet joined to any other pthread */
pthread_ptr->is_joined_to = TX_FALSE;
pthread_ptr->joined_to_pthreadID = TX_FALSE;
/* Allow cancel */
pthread_ptr->cancel_state = PTHREAD_CANCEL_ENABLE;
pthread_ptr->cancel_type = PTHREAD_CANCEL_DEFERRED;
pthread_ptr->cancel_request = FALSE;
pthread_ptr->value_ptr = NULL;
/* default stack allocation */
if((attr->stack_address)==NULL)
{
pthread_ptr->stack_size = attr->stack_size ;
status = posix_memory_allocate( pthread_ptr->stack_size, &(pthread_ptr->stack_address));
/* problem allocating stack space */
if (status == ERROR)
{
/* Configuration/resource error. */
return(EAGAIN);
}
}
/* Create an event flags group for sigwait. */
retval = tx_event_flags_create(&(pthread_ptr -> signals.signal_event_flags), "posix sigwait events");
/* Get the thread info from the TCB. */
thread_ptr = posix_tcb2thread(pthread_ptr);
/* Now actually create and start the thread. */
/* convert Posix priorities to Threadx priority */
retval += tx_thread_create(thread_ptr,
"pthr",
posix_thread_wrapper,
(ULONG)(ALIGN_TYPE)pthread_ptr,
pthread_ptr->stack_address,
pthread_ptr->stack_size,
(TX_LOWEST_PRIORITY - pthread_ptr->current_priority + 1),
(TX_LOWEST_PRIORITY - pthread_ptr->threshold + 1),
pthread_ptr->time_slice,
TX_AUTO_START);
TX_THREAD_EXTENSION_PTR_SET(thread_ptr, pthread_ptr)
/* See if ThreadX encountered an error */
if (retval)
{
/* Internal error */
posix_error_handler(3333);
retval = EACCES;
}
else
{
/* Everything is fine. */
/* create a pthreadID by type casting POSIX_TCB into pthread_t */
pthread_ptr->pthreadID = (pthread_t )pthread_ptr;
*thread = pthread_ptr->pthreadID ;
retval = OK;
}
/* Everything worked fine if we got here */
return(retval);
}