1 /*
2  * Copyright (c) 2017 Oticon A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * Here is where things actually happen for the POSIX arch
9  *
10  * We isolate all functions here, to ensure they can be compiled as
11  * independently as possible to the remainder of Zephyr to avoid name clashes
12  * as Zephyr does provide functions with the same names as the POSIX threads
13  * functions
14  */
15 /**
16  * Principle of operation:
17  *
18  * The Zephyr OS and its app run as a set of native pthreads.
19  * The Zephyr OS only sees one of this thread executing at a time.
20  * Which is running is controlled using {cond|mtx}_threads and
21  * currently_allowed_thread.
22  *
23  * The main part of the execution of each thread will occur in a fully
24  * synchronous and deterministic manner, and only when commanded by the Zephyr
25  * kernel.
26  * But the creation of a thread will spawn a new pthread whose start
27  * is asynchronous to the rest, until synchronized in posix_wait_until_allowed()
28  * below.
29  * Similarly aborting and canceling threads execute a tail in a quite
30  * asynchronous manner.
31  *
32  * This implementation is meant to be portable in between POSIX systems.
33  * A table (threads_table) is used to abstract the native pthreads.
34  * And index in this table is used to identify threads in the IF to the kernel.
35  *
36  */
37 
38 #define POSIX_ARCH_DEBUG_PRINTS 0
39 
40 #include <pthread.h>
41 #include <stdbool.h>
42 #include <stdlib.h>
43 #include <string.h>
44 
45 #include "posix_core.h"
46 #include "posix_arch_internal.h"
47 #include <arch/posix/posix_soc_if.h>
48 #include "kernel_internal.h"
49 #include "kernel_structs.h"
50 #include "ksched.h"
51 #include "kswap.h"
52 
53 #define PREFIX     "POSIX arch core: "
54 #define ERPREFIX   PREFIX"error on "
55 #define NO_MEM_ERR PREFIX"Can't allocate memory\n"
56 
57 #if POSIX_ARCH_DEBUG_PRINTS
58 #define PC_DEBUG(fmt, ...) posix_print_trace(PREFIX fmt, __VA_ARGS__)
59 #else
60 #define PC_DEBUG(...)
61 #endif
62 
63 #define PC_ALLOC_CHUNK_SIZE 64
64 #define PC_REUSE_ABORTED_ENTRIES 0
65 /* tests/kernel/threads/scheduling/schedule_api fails when setting
66  * PC_REUSE_ABORTED_ENTRIES => don't set it by now
67  */
68 
69 static int threads_table_size;
70 struct threads_table_el {
71 	enum {NOTUSED = 0, USED, ABORTING, ABORTED, FAILED} state;
72 	bool running;     /* Is this the currently running thread */
73 	pthread_t thread; /* Actual pthread_t as returned by native kernel */
74 	int thead_cnt; /* For debugging: Unique, consecutive, thread number */
75 	/* Pointer to the status kept in the Zephyr thread stack */
76 	posix_thread_status_t *t_status;
77 };
78 
79 static struct threads_table_el *threads_table;
80 
81 static int thread_create_count; /* For debugging. Thread creation counter */
82 
83 /*
84  * Conditional variable to block/awake all threads during swaps()
85  * (we only need 1 mutex and 1 cond variable for all threads)
86  */
87 static pthread_cond_t cond_threads = PTHREAD_COND_INITIALIZER;
88 /* Mutex for the conditional variable posix_core_cond_threads */
89 static pthread_mutex_t mtx_threads = PTHREAD_MUTEX_INITIALIZER;
90 /* Token which tells which process is allowed to run now */
91 static int currently_allowed_thread;
92 
93 static bool terminate; /* Are we terminating the program == cleaning up */
94 
95 static void posix_wait_until_allowed(int this_th_nbr);
96 static void *posix_thread_starter(void *arg);
97 static void posix_preexit_cleanup(void);
98 
99 /**
100  * Helper function, run by a thread is being aborted
101  */
abort_tail(int this_th_nbr)102 static void abort_tail(int this_th_nbr)
103 {
104 	PC_DEBUG("Thread [%i] %i: %s: Aborting (exiting) (rel mut)\n",
105 		threads_table[this_th_nbr].thead_cnt,
106 		this_th_nbr,
107 		__func__);
108 
109 	threads_table[this_th_nbr].running = false;
110 	threads_table[this_th_nbr].state = ABORTED;
111 	posix_preexit_cleanup();
112 	pthread_exit(NULL);
113 }
114 
115 /**
116  *  Helper function to block this thread until it is allowed again
117  *  (somebody calls posix_let_run() with this thread number
118  *
119  * Note that we go out of this function (the while loop below)
120  * with the mutex locked by this particular thread.
121  * In normal circumstances, the mutex is only unlocked internally in
122  * pthread_cond_wait() while waiting for cond_threads to be signaled
123  */
posix_wait_until_allowed(int this_th_nbr)124 static void posix_wait_until_allowed(int this_th_nbr)
125 {
126 	threads_table[this_th_nbr].running = false;
127 
128 	PC_DEBUG("Thread [%i] %i: %s: Waiting to be allowed to run (rel mut)\n",
129 		threads_table[this_th_nbr].thead_cnt,
130 		this_th_nbr,
131 		__func__);
132 
133 	while (this_th_nbr != currently_allowed_thread) {
134 		pthread_cond_wait(&cond_threads, &mtx_threads);
135 
136 		if (threads_table &&
137 		    (threads_table[this_th_nbr].state == ABORTING)) {
138 			abort_tail(this_th_nbr);
139 		}
140 	}
141 
142 	threads_table[this_th_nbr].running = true;
143 
144 	PC_DEBUG("Thread [%i] %i: %s(): I'm allowed to run! (hav mut)\n",
145 		threads_table[this_th_nbr].thead_cnt,
146 		this_th_nbr,
147 		__func__);
148 }
149 
150 
151 /**
152  * Helper function to let the thread <next_allowed_th> run
153  * Note: posix_let_run() can only be called with the mutex locked
154  */
posix_let_run(int next_allowed_th)155 static void posix_let_run(int next_allowed_th)
156 {
157 	PC_DEBUG("%s: We let thread [%i] %i run\n",
158 		__func__,
159 		threads_table[next_allowed_th].thead_cnt,
160 		next_allowed_th);
161 
162 
163 	currently_allowed_thread = next_allowed_th;
164 
165 	/*
166 	 * We let all threads know one is able to run now (it may even be us
167 	 * again if fancied)
168 	 * Note that as we hold the mutex, they are going to be blocked until
169 	 * we reach our own posix_wait_until_allowed() while loop
170 	 */
171 	PC_SAFE_CALL(pthread_cond_broadcast(&cond_threads));
172 }
173 
174 
posix_preexit_cleanup(void)175 static void posix_preexit_cleanup(void)
176 {
177 	/*
178 	 * Release the mutex so the next allowed thread can run
179 	 */
180 	PC_SAFE_CALL(pthread_mutex_unlock(&mtx_threads));
181 
182 	/* We detach ourselves so nobody needs to join to us */
183 	pthread_detach(pthread_self());
184 }
185 
186 
187 /**
188  * Let the ready thread run and block this thread until it is allowed again
189  *
190  * called from arch_swap() which does the picking from the kernel structures
191  */
posix_swap(int next_allowed_thread_nbr,int this_th_nbr)192 void posix_swap(int next_allowed_thread_nbr, int this_th_nbr)
193 {
194 	posix_let_run(next_allowed_thread_nbr);
195 
196 	if (threads_table[this_th_nbr].state == ABORTING) {
197 		PC_DEBUG("Thread [%i] %i: %s: Aborting curr.\n",
198 			threads_table[this_th_nbr].thead_cnt,
199 			this_th_nbr,
200 			__func__);
201 		abort_tail(this_th_nbr);
202 	} else {
203 		posix_wait_until_allowed(this_th_nbr);
204 	}
205 }
206 
207 /**
208  * Let the ready thread (main) run, and exit this thread (init)
209  *
210  * Called from arch_switch_to_main_thread() which does the picking from the
211  * kernel structures
212  *
213  * Note that we could have just done a swap(), but that would have left the
214  * init thread lingering. Instead here we exit the init thread after enabling
215  * the new one
216  */
posix_main_thread_start(int next_allowed_thread_nbr)217 void posix_main_thread_start(int next_allowed_thread_nbr)
218 {
219 	posix_let_run(next_allowed_thread_nbr);
220 	PC_DEBUG("%s: Init thread dying now (rel mut)\n",
221 		__func__);
222 	posix_preexit_cleanup();
223 	pthread_exit(NULL);
224 }
225 
226 /**
227  * Handler called when any thread is cancelled or exits
228  */
posix_cleanup_handler(void * arg)229 static void posix_cleanup_handler(void *arg)
230 {
231 	/*
232 	 * If we are not terminating, this is just an aborted thread,
233 	 * and the mutex was already released
234 	 * Otherwise, release the mutex so other threads which may be
235 	 * caught waiting for it could terminate
236 	 */
237 
238 	if (!terminate) {
239 		return;
240 	}
241 
242 #if POSIX_ARCH_DEBUG_PRINTS
243 	posix_thread_status_t *ptr = (posix_thread_status_t *) arg;
244 
245 	PC_DEBUG("Thread %i: %s: Canceling (rel mut)\n",
246 		ptr->thread_idx,
247 		__func__);
248 #endif
249 
250 
251 	PC_SAFE_CALL(pthread_mutex_unlock(&mtx_threads));
252 
253 	/* We detach ourselves so nobody needs to join to us */
254 	pthread_detach(pthread_self());
255 }
256 
257 /**
258  * Helper function to start a Zephyr thread as a POSIX thread:
259  *  It will block the thread until a arch_swap() is called for it
260  *
261  * Spawned from posix_new_thread() below
262  */
posix_thread_starter(void * arg)263 static void *posix_thread_starter(void *arg)
264 {
265 	int thread_idx = (intptr_t)arg;
266 
267 	PC_DEBUG("Thread [%i] %i: %s: Starting\n",
268 		threads_table[thread_idx].thead_cnt,
269 		thread_idx,
270 		__func__);
271 
272 	/*
273 	 * We block until all other running threads reach the while loop
274 	 * in posix_wait_until_allowed() and they release the mutex
275 	 */
276 	PC_SAFE_CALL(pthread_mutex_lock(&mtx_threads));
277 
278 	/*
279 	 * The program may have been finished before this thread ever got to run
280 	 */
281 	/* LCOV_EXCL_START */ /* See Note1 */
282 	if (!threads_table) {
283 		posix_cleanup_handler(arg);
284 		pthread_exit(NULL);
285 	}
286 	/* LCOV_EXCL_STOP */
287 
288 	pthread_cleanup_push(posix_cleanup_handler, arg);
289 
290 	PC_DEBUG("Thread [%i] %i: %s: After start mutex (hav mut)\n",
291 		threads_table[thread_idx].thead_cnt,
292 		thread_idx,
293 		__func__);
294 
295 	/*
296 	 * The thread would try to execute immediately, so we block it
297 	 * until allowed
298 	 */
299 	posix_wait_until_allowed(thread_idx);
300 
301 	posix_new_thread_pre_start();
302 
303 	posix_thread_status_t *ptr = threads_table[thread_idx].t_status;
304 
305 	z_thread_entry(ptr->entry_point, ptr->arg1, ptr->arg2, ptr->arg3);
306 
307 	/*
308 	 * We only reach this point if the thread actually returns which should
309 	 * not happen. But we handle it gracefully just in case
310 	 */
311 	/* LCOV_EXCL_START */
312 	posix_print_trace(PREFIX"Thread [%i] %i [%lu] ended!?!\n",
313 			threads_table[thread_idx].thead_cnt,
314 			thread_idx,
315 			pthread_self());
316 
317 
318 	threads_table[thread_idx].running = false;
319 	threads_table[thread_idx].state = FAILED;
320 
321 	pthread_cleanup_pop(1);
322 
323 	return NULL;
324 	/* LCOV_EXCL_STOP */
325 }
326 
327 /**
328  * Return the first free entry index in the threads table
329  */
ttable_get_empty_slot(void)330 static int ttable_get_empty_slot(void)
331 {
332 
333 	for (int i = 0; i < threads_table_size; i++) {
334 		if ((threads_table[i].state == NOTUSED)
335 			|| (PC_REUSE_ABORTED_ENTRIES
336 			&& (threads_table[i].state == ABORTED))) {
337 			return i;
338 		}
339 	}
340 
341 	/*
342 	 * else, we run out table without finding an index
343 	 * => we expand the table
344 	 */
345 
346 	threads_table = realloc(threads_table,
347 				(threads_table_size + PC_ALLOC_CHUNK_SIZE)
348 				* sizeof(struct threads_table_el));
349 	if (threads_table == NULL) { /* LCOV_EXCL_BR_LINE */
350 		posix_print_error_and_exit(NO_MEM_ERR); /* LCOV_EXCL_LINE */
351 	}
352 
353 	/* Clear new piece of table */
354 	(void)memset(&threads_table[threads_table_size], 0,
355 		     PC_ALLOC_CHUNK_SIZE * sizeof(struct threads_table_el));
356 
357 	threads_table_size += PC_ALLOC_CHUNK_SIZE;
358 
359 	/* The first newly created entry is good: */
360 	return threads_table_size - PC_ALLOC_CHUNK_SIZE;
361 }
362 
363 /**
364  * Called from arch_new_thread(),
365  * Create a new POSIX thread for the new Zephyr thread.
366  * arch_new_thread() picks from the kernel structures what it is that we need
367  * to call with what parameters
368  */
posix_new_thread(posix_thread_status_t * ptr)369 void posix_new_thread(posix_thread_status_t *ptr)
370 {
371 	int t_slot;
372 
373 	t_slot = ttable_get_empty_slot();
374 	threads_table[t_slot].state = USED;
375 	threads_table[t_slot].running = false;
376 	threads_table[t_slot].thead_cnt = thread_create_count++;
377 	threads_table[t_slot].t_status = ptr;
378 	ptr->thread_idx = t_slot;
379 
380 	PC_SAFE_CALL(pthread_create(&threads_table[t_slot].thread,
381 				  NULL,
382 				  posix_thread_starter,
383 				  (void *)(intptr_t)t_slot));
384 
385 	PC_DEBUG("%s created thread [%i] %i [%lu]\n",
386 		__func__,
387 		threads_table[t_slot].thead_cnt,
388 		t_slot,
389 		threads_table[t_slot].thread);
390 
391 }
392 
393 /**
394  * Called from zephyr_wrapper()
395  * prepare whatever needs to be prepared to be able to start threads
396  */
posix_init_multithreading(void)397 void posix_init_multithreading(void)
398 {
399 	thread_create_count = 0;
400 
401 	currently_allowed_thread = -1;
402 
403 	threads_table = calloc(PC_ALLOC_CHUNK_SIZE,
404 				sizeof(struct threads_table_el));
405 	if (threads_table == NULL) { /* LCOV_EXCL_BR_LINE */
406 		posix_print_error_and_exit(NO_MEM_ERR); /* LCOV_EXCL_LINE */
407 	}
408 
409 	threads_table_size = PC_ALLOC_CHUNK_SIZE;
410 
411 
412 	PC_SAFE_CALL(pthread_mutex_lock(&mtx_threads));
413 }
414 
415 /**
416  * Free any allocated memory by the posix core and clean up.
417  * Note that this function cannot be called from a SW thread
418  * (the CPU is assumed halted. Otherwise we will cancel ourselves)
419  *
420  * This function cannot guarantee the threads will be cancelled before the HW
421  * thread exists. The only way to do that, would be  to wait for each of them in
422  * a join (without detaching them, but that could lead to locks in some
423  * convoluted cases. As a call to this function can come from an ASSERT or other
424  * error termination, we better do not assume things are working fine.
425  * => we prefer the supposed memory leak report from valgrind, and ensure we
426  * will not hang
427  *
428  */
posix_core_clean_up(void)429 void posix_core_clean_up(void)
430 {
431 
432 	if (!threads_table) { /* LCOV_EXCL_BR_LINE */
433 		return; /* LCOV_EXCL_LINE */
434 	}
435 
436 	terminate = true;
437 
438 	for (int i = 0; i < threads_table_size; i++) {
439 		if (threads_table[i].state != USED) {
440 			continue;
441 		}
442 
443 		/* LCOV_EXCL_START */
444 		if (pthread_cancel(threads_table[i].thread)) {
445 			posix_print_warning(
446 				PREFIX"cleanup: could not stop thread %i\n",
447 				i);
448 		}
449 		/* LCOV_EXCL_STOP */
450 	}
451 
452 	free(threads_table);
453 	threads_table = NULL;
454 }
455 
456 
posix_abort_thread(int thread_idx)457 void posix_abort_thread(int thread_idx)
458 {
459 	if (threads_table[thread_idx].state != USED) { /* LCOV_EXCL_BR_LINE */
460 		/* The thread may have been already aborted before */
461 		return; /* LCOV_EXCL_LINE */
462 	}
463 
464 	PC_DEBUG("Aborting not scheduled thread [%i] %i\n",
465 		threads_table[thread_idx].thead_cnt,
466 		thread_idx);
467 
468 	threads_table[thread_idx].state = ABORTING;
469 	/*
470 	 * Note: the native thread will linger in RAM until it catches the
471 	 * mutex or awakes on the condition.
472 	 * Note that even if we would pthread_cancel() the thread here, that
473 	 * would be the case, but with a pthread_cancel() the mutex state would
474 	 * be uncontrolled
475 	 */
476 }
477 
478 
479 #if defined(CONFIG_ARCH_HAS_THREAD_ABORT)
z_impl_k_thread_abort(k_tid_t thread)480 void z_impl_k_thread_abort(k_tid_t thread)
481 {
482 	unsigned int key;
483 	int thread_idx;
484 
485 	posix_thread_status_t *tstatus =
486 					(posix_thread_status_t *)
487 					thread->callee_saved.thread_status;
488 
489 	thread_idx = tstatus->thread_idx;
490 
491 	key = irq_lock();
492 
493 	if (_current == thread) {
494 		if (tstatus->aborted == 0) { /* LCOV_EXCL_BR_LINE */
495 			tstatus->aborted = 1;
496 		} else {
497 			posix_print_warning(/* LCOV_EXCL_LINE */
498 				PREFIX"The kernel is trying to abort and swap "
499 				"out of an already aborted thread %i. This "
500 				"should NOT have happened\n",
501 				thread_idx);
502 		}
503 		threads_table[thread_idx].state = ABORTING;
504 		PC_DEBUG("Thread [%i] %i: %s Marked myself "
505 			"as aborting\n",
506 			threads_table[thread_idx].thead_cnt,
507 			thread_idx,
508 			__func__);
509 	}
510 
511 	z_thread_abort(thread);
512 
513 	if (tstatus->aborted == 0) {
514 		PC_DEBUG("%s aborting now [%i] %i\n",
515 			__func__,
516 			threads_table[thread_idx].thead_cnt,
517 			thread_idx);
518 
519 		tstatus->aborted = 1;
520 		posix_abort_thread(thread_idx);
521 	} else {
522 		PC_DEBUG("%s ignoring re_abort of [%i] "
523 			"%i\n",
524 			__func__,
525 			threads_table[thread_idx].thead_cnt,
526 			thread_idx);
527 	}
528 
529 	/* The abort handler might have altered the ready queue. */
530 	z_reschedule_irqlock(key);
531 }
532 #endif
533 
534 
535 /*
536  * Notes about coverage:
537  *
538  * Note1:
539  *
540  * This condition will only be triggered in very unlikely cases
541  * (once every few full regression runs).
542  * It is therefore excluded from the coverage report to avoid confusing
543  * developers.
544  *
545  * Background: This arch creates a pthread as soon as the Zephyr kernel creates
546  * a Zephyr thread. A pthread creation is an asynchronous process handled by the
547  * host kernel.
548  *
549  * This architecture normally keeps only 1 thread executing at a time.
550  * But part of the pre-initialization during creation of a new thread
551  * and some cleanup at the tail of the thread termination are executed
552  * in parallel to other threads.
553  * That is, the execution of those code paths is a bit indeterministic.
554  *
555  * Only when the Zephyr kernel attempts to swap to a new thread does this
556  * architecture need to wait until its pthread is ready and initialized
557  * (has reached posix_wait_until_allowed())
558  *
559  * In some cases (tests) threads are created which are never actually needed
560  * (typically the idle thread). That means the test may finish before this
561  * thread's underlying pthread has reached posix_wait_until_allowed().
562  *
563  * In this unlikely cases the initialization or cleanup of the thread follows
564  * non-typical code paths.
565  * This code paths are there to ensure things work always, no matter
566  * the load of the host. Without them, very rare & mysterious segfault crashes
567  * would occur.
568  * But as they are very atypical and only triggered with some host loads,
569  * they will be covered in the coverage reports only rarely.
570  *
571  * Note2:
572  *
573  * Some other code will never or only very rarely trigger and is therefore
574  * excluded with LCOV_EXCL_LINE
575  *
576  */
577