mirror of
https://github.com/azure-rtos/threadx
synced 2025-02-06 08:08:27 +08:00
185 lines
8.6 KiB
C
185 lines
8.6 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_join PORTABLE C */
|
|
/* 6.1.7 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* William E. Lamie, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function shall suspend execution of the calling thread until */
|
|
/* the target thread terminates, unless the target thread has already */
|
|
/* terminated. On return from a successful pthread_join ( ) call with */
|
|
/* a non-NULL value_ptr argument, the value passed to pthread_exit( ) */
|
|
/* by the terminating thread shall be made available in the location */
|
|
/* referenced by value_ptr. When a pthread_join returns successfully, */
|
|
/* the target thread has been terminated. The results of multiple */
|
|
/* simultaneous calls to pthread_join specifying the same target thread*/
|
|
/* are undefined. If the thread calling pthread_join is canceled, then */
|
|
/* the target thread shall not be detached. */
|
|
/* Eventually, you should call pthread_join() or pthread_detach() for */
|
|
/* every thread that is created joinable (with a detachstate of */
|
|
/* PTHREAD_CREATE_JOINABLE)so that the system can reclaim all resources*/
|
|
/* associated with the thread. Failure to join to or detach joinable */
|
|
/* threads will result in memory and other resource leaks until the */
|
|
/* process ends. If thread doesn't represent a valid undetached thread,*/
|
|
/* pthread_detach() will return ESRCH. */
|
|
/* */
|
|
/* Note: this function must be called from a POSIX context; if it is */
|
|
/* called from ThreadX context an error is returned. */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* thread pthread handle to the target thread */
|
|
/* value_ptr To receive return value of terminating */
|
|
/* thread */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* zero If successful */
|
|
/* error number If fails */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* Application Code */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 06-02-2021 William E. Lamie Initial Version 6.1.7 */
|
|
/* */
|
|
/**************************************************************************/
|
|
INT pthread_join(pthread_t thread, VOID **value_ptr)
|
|
|
|
{
|
|
TX_INTERRUPT_SAVE_AREA
|
|
|
|
POSIX_TCB *current_ptr, *target_ptr;
|
|
TX_THREAD *target_thread;
|
|
|
|
|
|
/* Get the TCB for the currently running pthread */
|
|
current_ptr = posix_thread2tcb(tx_thread_identify());
|
|
|
|
/* Make sure that a TCB was returned. */
|
|
if (!current_ptr)
|
|
{
|
|
posix_errno = ECANCELED;
|
|
posix_set_pthread_errno(ECANCELED);
|
|
return(ECANCELED);
|
|
}
|
|
|
|
/* Check trying to join to self ! */
|
|
if ( current_ptr->pthreadID == thread)
|
|
{
|
|
posix_errno= EDEADLK;
|
|
posix_set_pthread_errno(EDEADLK);
|
|
return(EDEADLK);
|
|
}
|
|
/* Check if calling thread is already joined to other thread */
|
|
|
|
if ( current_ptr->is_joined_to == TX_TRUE)
|
|
{
|
|
posix_errno= EINVAL;
|
|
posix_set_pthread_errno(EINVAL);
|
|
return(EINVAL);
|
|
}
|
|
/* Sure, calling pthread can be joined to target pthread */
|
|
|
|
target_thread = posix_tid2thread(thread);
|
|
|
|
if (!target_thread)
|
|
{
|
|
/* Invalid target pthread object */
|
|
posix_errno= ESRCH;
|
|
posix_set_pthread_errno(ESRCH);
|
|
return(ESRCH);
|
|
}
|
|
|
|
if ( (target_thread->tx_thread_state == TX_COMPLETED) || (target_thread->tx_thread_state == TX_TERMINATED) )
|
|
{
|
|
/* but target pthread is already terminated */
|
|
/* return the return value of the terminated thread */
|
|
target_ptr = posix_tid2tcb(thread);
|
|
if(value_ptr)*value_ptr = target_ptr->value_ptr;
|
|
return(OK);
|
|
}
|
|
|
|
/* Now check the target thread, whether it is already joined to any other thread? */
|
|
target_ptr = posix_tid2tcb(thread);
|
|
|
|
/* Now check the target thread, whether it is already joined to any other thread? */
|
|
if (target_ptr->is_joined_by == TX_TRUE)
|
|
{
|
|
/* but target pthread is already terminated */
|
|
posix_errno= EINVAL;
|
|
posix_set_pthread_errno(EINVAL);
|
|
return(EINVAL);
|
|
}
|
|
|
|
/* check joinability of target thread */
|
|
if ( target_ptr->detach_state != PTHREAD_CREATE_JOINABLE)
|
|
{
|
|
posix_errno= EINVAL;
|
|
posix_set_pthread_errno(EINVAL);
|
|
return(EINVAL);
|
|
}
|
|
|
|
/* Now it is Okay to join */
|
|
|
|
TX_DISABLE
|
|
|
|
/* declare that this calling pthread is joined to other pthread */
|
|
current_ptr->is_joined_to = TX_TRUE;
|
|
/* register the target pthread */
|
|
current_ptr->joined_to_pthreadID = thread;
|
|
/* declare that the target pthread is joined by calling pthread */
|
|
target_ptr->is_joined_by = TX_TRUE;
|
|
/* and register the caller pthread with target pthread */
|
|
target_ptr->joined_by_pthreadID = current_ptr->pthreadID ;
|
|
|
|
TX_RESTORE
|
|
|
|
/* Now calling pthread will suspend itself and wait till target pthread exits */
|
|
tx_thread_suspend ( &(current_ptr->thread_info));
|
|
/* target pthread exited and thus current pthread will resume now */
|
|
/* store return value if value_ptr is valid */
|
|
if(value_ptr)*value_ptr = target_ptr->value_ptr;
|
|
return(OK);
|
|
}
|