1 /*
2 * Thread functions
3 *
4 * Copyright (C) 2012-2020, Joachim Metz <joachim.metz@gmail.com>
5 *
6 * Refer to AUTHORS for acknowledgements.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22 #include <common.h>
23 #include <memory.h>
24 #include <types.h>
25
26 #include <errno.h>
27
28 #if defined( WINAPI ) && ( WINVER >= 0x0602 )
29 #include <Processthreadsapi.h>
30 #include <Synchapi.h>
31 #endif
32
33 #if defined( HAVE_PTHREAD_H ) && !defined( WINAPI )
34 #include <pthread.h>
35 #endif
36
37 #include "libcthreads_libcerror.h"
38 #include "libcthreads_thread.h"
39 #include "libcthreads_thread_attributes.h"
40 #include "libcthreads_types.h"
41
42 #if !defined( HAVE_LOCAL_LIBCTHREADS ) || defined( HAVE_MULTI_THREAD_SUPPORT )
43
44 #if defined( WINAPI )
45
46 /* Start function helper function for WINAPI
47 * Returns 0 if successful or 1 on error
48 */
libcthreads_thread_callback_function_helper(void * arguments)49 DWORD WINAPI libcthreads_thread_callback_function_helper(
50 void *arguments )
51 {
52 libcthreads_internal_thread_t *internal_thread = NULL;
53 DWORD result = 1;
54 int callback_function_result = 0;
55
56 if( arguments != NULL )
57 {
58 internal_thread = (libcthreads_internal_thread_t *) arguments;
59
60 if( ( internal_thread != NULL )
61 && ( internal_thread->callback_function != NULL ) )
62 {
63 callback_function_result = internal_thread->callback_function(
64 internal_thread->callback_function_arguments );
65 }
66 result = (DWORD) ( callback_function_result != 1 );
67 }
68 ExitThread(
69 result );
70 }
71
72 #elif defined( HAVE_PTHREAD_H )
73
74 /* Start function helper function for pthread
75 * Returns a pointer to a newly allocated int containing 1 if successful or -1 on error
76 * NULL is return if the helper function was unable to run the callback
77 */
libcthreads_thread_callback_function_helper(void * arguments)78 void *libcthreads_thread_callback_function_helper(
79 void *arguments )
80 {
81 libcthreads_internal_thread_t *internal_thread = NULL;
82 int *result = NULL;
83
84 if( arguments != NULL )
85 {
86 internal_thread = (libcthreads_internal_thread_t *) arguments;
87
88 if( ( internal_thread != NULL )
89 && ( internal_thread->callback_function != NULL ) )
90 {
91 result = (int *) memory_allocate(
92 sizeof( int ) );
93
94 if( result != NULL )
95 {
96 *result = internal_thread->callback_function(
97 internal_thread->callback_function_arguments );
98 }
99 }
100 }
101 pthread_exit(
102 (void *) result );
103 }
104
105 #endif
106
107 /* Creates a thread
108 * Make sure the value thread is referencing, is set to NULL
109 *
110 * The callback_function should return 1 if successful and -1 on error
111 * Returns 1 if successful or -1 on error
112 */
libcthreads_thread_create(libcthreads_thread_t ** thread,const libcthreads_thread_attributes_t * thread_attributes,int (* callback_function)(void * arguments),void * callback_function_arguments,libcerror_error_t ** error)113 int libcthreads_thread_create(
114 libcthreads_thread_t **thread,
115 const libcthreads_thread_attributes_t *thread_attributes,
116 int (*callback_function)(
117 void *arguments ),
118 void *callback_function_arguments,
119 libcerror_error_t **error )
120 {
121 libcthreads_internal_thread_t *internal_thread = NULL;
122 static char *function = "libcthreads_thread_create";
123
124 #if defined( WINAPI )
125 SECURITY_ATTRIBUTES *security_attributes = NULL;
126 HANDLE thread_handle = NULL;
127 DWORD error_code = 0;
128
129 #elif defined( HAVE_PTHREAD_H )
130 pthread_attr_t *attributes = NULL;
131 int pthread_result = 0;
132 #endif
133
134 if( thread == NULL )
135 {
136 libcerror_error_set(
137 error,
138 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
139 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
140 "%s: invalid thread.",
141 function );
142
143 return( -1 );
144 }
145 if( *thread != NULL )
146 {
147 libcerror_error_set(
148 error,
149 LIBCERROR_ERROR_DOMAIN_RUNTIME,
150 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
151 "%s: invalid thread value already set.",
152 function );
153
154 return( -1 );
155 }
156 if( callback_function == NULL )
157 {
158 libcerror_error_set(
159 error,
160 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
161 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
162 "%s: invalid callback function.",
163 function );
164
165 return( -1 );
166 }
167 internal_thread = memory_allocate_structure(
168 libcthreads_internal_thread_t );
169
170 if( internal_thread == NULL )
171 {
172 libcerror_error_set(
173 error,
174 LIBCERROR_ERROR_DOMAIN_MEMORY,
175 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
176 "%s: unable to create thread.",
177 function );
178
179 goto on_error;
180 }
181 if( memory_set(
182 internal_thread,
183 0,
184 sizeof( libcthreads_internal_thread_t ) ) == NULL )
185 {
186 libcerror_error_set(
187 error,
188 LIBCERROR_ERROR_DOMAIN_MEMORY,
189 LIBCERROR_MEMORY_ERROR_SET_FAILED,
190 "%s: unable to clear thread.",
191 function );
192
193 memory_free(
194 internal_thread );
195
196 return( -1 );
197 }
198 internal_thread->callback_function = callback_function;
199 internal_thread->callback_function_arguments = callback_function_arguments;
200
201 #if defined( WINAPI )
202 if( thread_attributes != NULL )
203 {
204 security_attributes = &( ( (libcthreads_internal_thread_attributes_t *) thread_attributes )->security_attributes );
205 }
206 thread_handle = CreateThread(
207 security_attributes,
208 0, /* stack size */
209 &libcthreads_thread_callback_function_helper,
210 (void *) internal_thread,
211 0, /* creation flags */
212 &( internal_thread->thread_identifier ) );
213
214 if( thread_handle == NULL )
215 {
216 error_code = GetLastError();
217
218 libcerror_system_set_error(
219 error,
220 error_code,
221 LIBCERROR_ERROR_DOMAIN_RUNTIME,
222 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
223 "%s: unable to create thread handle.",
224 function );
225
226 goto on_error;
227 }
228 internal_thread->thread_handle = thread_handle;
229
230 #elif defined( HAVE_PTHREAD_H )
231 if( thread_attributes != NULL )
232 {
233 attributes = &( ( (libcthreads_internal_thread_attributes_t *) thread_attributes )->attributes );
234 }
235 pthread_result = pthread_create(
236 &( internal_thread->thread ),
237 attributes,
238 &libcthreads_thread_callback_function_helper,
239 (void *) internal_thread );
240
241 switch( pthread_result )
242 {
243 case 0:
244 break;
245
246 case EAGAIN:
247 libcerror_error_set(
248 error,
249 LIBCERROR_ERROR_DOMAIN_RUNTIME,
250 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
251 "%s: unable to create thread with error: Insufficient resources.",
252 function );
253
254 goto on_error;
255
256 default:
257 libcerror_system_set_error(
258 error,
259 pthread_result,
260 LIBCERROR_ERROR_DOMAIN_RUNTIME,
261 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
262 "%s: unable to create thread.",
263 function );
264
265 goto on_error;
266 }
267 #endif
268 *thread = (libcthreads_thread_t *) internal_thread;
269
270 return( 1 );
271
272 on_error:
273 if( internal_thread != NULL )
274 {
275 memory_free(
276 internal_thread );
277 }
278 return( -1 );
279 }
280
281 /* Joins the current with a specified thread
282 * The the thread is freed after join
283 * Returns 1 if successful or -1 on error
284 */
libcthreads_thread_join(libcthreads_thread_t ** thread,libcerror_error_t ** error)285 int libcthreads_thread_join(
286 libcthreads_thread_t **thread,
287 libcerror_error_t **error )
288 {
289 libcthreads_internal_thread_t *internal_thread = NULL;
290 static char *function = "libcthreads_thread_join";
291 int result = 1;
292
293 #if defined( WINAPI )
294 DWORD error_code = 0;
295 DWORD wait_status = 0;
296
297 #elif defined( HAVE_PTHREAD_H )
298 int *thread_return_value = NULL;
299 int pthread_result = 0;
300 #endif
301
302 if( thread == NULL )
303 {
304 libcerror_error_set(
305 error,
306 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
307 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
308 "%s: invalid thread.",
309 function );
310
311 return( -1 );
312 }
313 if( *thread == NULL )
314 {
315 libcerror_error_set(
316 error,
317 LIBCERROR_ERROR_DOMAIN_RUNTIME,
318 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
319 "%s: missing thread value.",
320 function );
321
322 return( -1 );
323 }
324 internal_thread = (libcthreads_internal_thread_t *) *thread;
325 *thread = NULL;
326
327 #if defined( WINAPI )
328 wait_status = WaitForSingleObject(
329 internal_thread->thread_handle,
330 INFINITE );
331
332 if( wait_status == WAIT_FAILED )
333 {
334 error_code = GetLastError();
335
336 libcerror_system_set_error(
337 error,
338 error_code,
339 LIBCERROR_ERROR_DOMAIN_RUNTIME,
340 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
341 "%s: wait for thread failed.",
342 function );
343
344 result = -1;
345 }
346
347 #elif defined( HAVE_PTHREAD_H )
348 pthread_result = pthread_join(
349 internal_thread->thread,
350 (void **) &thread_return_value );
351
352 if( pthread_result == EDEADLK )
353 {
354 libcerror_error_set(
355 error,
356 LIBCERROR_ERROR_DOMAIN_RUNTIME,
357 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
358 "%s: unable to join thread with error: Deadlock condition detected.",
359 function );
360
361 result = -1;
362 }
363 else if( pthread_result != 0 )
364 {
365 libcerror_system_set_error(
366 error,
367 pthread_result,
368 LIBCERROR_ERROR_DOMAIN_RUNTIME,
369 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
370 "%s: unable to join thread.",
371 function );
372
373 result = -1;
374 }
375 /* If the thread returns NULL it never got around to launching the callback function
376 */
377 else if( ( thread_return_value != NULL )
378 && ( *thread_return_value != 1 ) )
379 {
380 libcerror_error_set(
381 error,
382 LIBCERROR_ERROR_DOMAIN_RUNTIME,
383 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
384 "%s: thread returned an error status of: %d.",
385 function,
386 *thread_return_value );
387
388 result = -1;
389 }
390 if( thread_return_value != NULL )
391 {
392 memory_free(
393 thread_return_value );
394
395 thread_return_value = NULL;
396 }
397 #endif
398 memory_free(
399 internal_thread );
400
401 return( result );
402 }
403
404 #endif /* !defined( HAVE_LOCAL_LIBCTHREADS ) || defined( HAVE_MULTI_THREAD_SUPPORT ) */
405
406