1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** POSIX wrapper for THREADX */
17 /** */
18 /** */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 /* Include necessary system files. */
24
25 #include "tx_api.h" /* Threadx API */
26 #include "pthread.h" /* Posix API */
27 #include "px_int.h" /* Posix helper functions */
28
29
30 /**************************************************************************/
31 /* */
32 /* FUNCTION RELEASE */
33 /* */
34 /* pthread_join PORTABLE C */
35 /* 6.1.7 */
36 /* AUTHOR */
37 /* */
38 /* William E. Lamie, Microsoft Corporation */
39 /* */
40 /* DESCRIPTION */
41 /* */
42 /* This function shall suspend execution of the calling thread until */
43 /* the target thread terminates, unless the target thread has already */
44 /* terminated. On return from a successful pthread_join ( ) call with */
45 /* a non-NULL value_ptr argument, the value passed to pthread_exit( ) */
46 /* by the terminating thread shall be made available in the location */
47 /* referenced by value_ptr. When a pthread_join returns successfully, */
48 /* the target thread has been terminated. The results of multiple */
49 /* simultaneous calls to pthread_join specifying the same target thread*/
50 /* are undefined. If the thread calling pthread_join is canceled, then */
51 /* the target thread shall not be detached. */
52 /* Eventually, you should call pthread_join() or pthread_detach() for */
53 /* every thread that is created joinable (with a detachstate of */
54 /* PTHREAD_CREATE_JOINABLE)so that the system can reclaim all resources*/
55 /* associated with the thread. Failure to join to or detach joinable */
56 /* threads will result in memory and other resource leaks until the */
57 /* process ends. If thread doesn't represent a valid undetached thread,*/
58 /* pthread_detach() will return ESRCH. */
59 /* */
60 /* Note: this function must be called from a POSIX context; if it is */
61 /* called from ThreadX context an error is returned. */
62 /* */
63 /* INPUT */
64 /* */
65 /* thread pthread handle to the target thread */
66 /* value_ptr To receive return value of terminating */
67 /* thread */
68 /* */
69 /* OUTPUT */
70 /* */
71 /* zero If successful */
72 /* error number If fails */
73 /* */
74 /* CALLS */
75 /* */
76 /* */
77 /* CALLED BY */
78 /* */
79 /* Application Code */
80 /* */
81 /* RELEASE HISTORY */
82 /* */
83 /* DATE NAME DESCRIPTION */
84 /* */
85 /* 06-02-2021 William E. Lamie Initial Version 6.1.7 */
86 /* */
87 /**************************************************************************/
pthread_join(pthread_t thread,VOID ** value_ptr)88 INT pthread_join(pthread_t thread, VOID **value_ptr)
89
90 {
91 TX_INTERRUPT_SAVE_AREA
92
93 POSIX_TCB *current_ptr, *target_ptr;
94 TX_THREAD *target_thread;
95
96
97 /* Get the TCB for the currently running pthread */
98 current_ptr = posix_thread2tcb(tx_thread_identify());
99
100 /* Make sure that a TCB was returned. */
101 if (!current_ptr)
102 {
103 posix_errno = ECANCELED;
104 posix_set_pthread_errno(ECANCELED);
105 return(ECANCELED);
106 }
107
108 /* Check trying to join to self ! */
109 if ( current_ptr->pthreadID == thread)
110 {
111 posix_errno= EDEADLK;
112 posix_set_pthread_errno(EDEADLK);
113 return(EDEADLK);
114 }
115 /* Check if calling thread is already joined to other thread */
116
117 if ( current_ptr->is_joined_to == TX_TRUE)
118 {
119 posix_errno= EINVAL;
120 posix_set_pthread_errno(EINVAL);
121 return(EINVAL);
122 }
123 /* Sure, calling pthread can be joined to target pthread */
124
125 target_thread = posix_tid2thread(thread);
126
127 if (!target_thread)
128 {
129 /* Invalid target pthread object */
130 posix_errno= ESRCH;
131 posix_set_pthread_errno(ESRCH);
132 return(ESRCH);
133 }
134
135 if ( (target_thread->tx_thread_state == TX_COMPLETED) || (target_thread->tx_thread_state == TX_TERMINATED) )
136 {
137 /* but target pthread is already terminated */
138 /* return the return value of the terminated thread */
139 target_ptr = posix_tid2tcb(thread);
140 if(value_ptr)*value_ptr = target_ptr->value_ptr;
141 return(OK);
142 }
143
144 /* Now check the target thread, whether it is already joined to any other thread? */
145 target_ptr = posix_tid2tcb(thread);
146
147 /* Now check the target thread, whether it is already joined to any other thread? */
148 if (target_ptr->is_joined_by == TX_TRUE)
149 {
150 /* but target pthread is already terminated */
151 posix_errno= EINVAL;
152 posix_set_pthread_errno(EINVAL);
153 return(EINVAL);
154 }
155
156 /* check joinability of target thread */
157 if ( target_ptr->detach_state != PTHREAD_CREATE_JOINABLE)
158 {
159 posix_errno= EINVAL;
160 posix_set_pthread_errno(EINVAL);
161 return(EINVAL);
162 }
163
164 /* Now it is Okay to join */
165
166 TX_DISABLE
167
168 /* declare that this calling pthread is joined to other pthread */
169 current_ptr->is_joined_to = TX_TRUE;
170 /* register the target pthread */
171 current_ptr->joined_to_pthreadID = thread;
172 /* declare that the target pthread is joined by calling pthread */
173 target_ptr->is_joined_by = TX_TRUE;
174 /* and register the caller pthread with target pthread */
175 target_ptr->joined_by_pthreadID = current_ptr->pthreadID ;
176
177 TX_RESTORE
178
179 /* Now calling pthread will suspend itself and wait till target pthread exits */
180 tx_thread_suspend ( &(current_ptr->thread_info));
181 /* target pthread exited and thus current pthread will resume now */
182 /* store return value if value_ptr is valid */
183 if(value_ptr)*value_ptr = target_ptr->value_ptr;
184 return(OK);
185 }
186