1 /*
2  * Copyright (c) 2018 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <kernel.h>
8 #include <stdio.h>
9 #include <sys/atomic.h>
10 #include <ksched.h>
11 #include <wait_q.h>
12 #include <posix/pthread.h>
13 #include <sys/slist.h>
14 
15 #define PTHREAD_INIT_FLAGS	PTHREAD_CANCEL_ENABLE
16 #define PTHREAD_CANCELED	((void *) -1)
17 
18 PTHREAD_MUTEX_DEFINE(pthread_key_lock);
19 
20 static const pthread_attr_t init_pthread_attrs = {
21 	.priority = 0,
22 	.stack = NULL,
23 	.stacksize = 0,
24 	.flags = PTHREAD_INIT_FLAGS,
25 	.delayedstart = 0,
26 #if defined(CONFIG_PREEMPT_ENABLED)
27 	.schedpolicy = SCHED_RR,
28 #else
29 	.schedpolicy = SCHED_FIFO,
30 #endif
31 	.detachstate = PTHREAD_CREATE_JOINABLE,
32 	.initialized = true,
33 };
34 
35 static struct posix_thread posix_thread_pool[CONFIG_MAX_PTHREAD_COUNT];
36 PTHREAD_MUTEX_DEFINE(pthread_pool_lock);
37 
is_posix_prio_valid(uint32_t priority,int policy)38 static bool is_posix_prio_valid(uint32_t priority, int policy)
39 {
40 	if (priority >= sched_get_priority_min(policy) &&
41 	    priority <= sched_get_priority_max(policy)) {
42 		return true;
43 	}
44 
45 	return false;
46 }
47 
zephyr_to_posix_priority(int32_t z_prio,int * policy)48 static uint32_t zephyr_to_posix_priority(int32_t z_prio, int *policy)
49 {
50 	uint32_t prio;
51 
52 	if (z_prio < 0) {
53 		*policy = SCHED_FIFO;
54 		prio = -1 * (z_prio + 1);
55 		__ASSERT_NO_MSG(prio < CONFIG_NUM_COOP_PRIORITIES);
56 	} else {
57 		*policy = SCHED_RR;
58 		prio = (CONFIG_NUM_PREEMPT_PRIORITIES - z_prio - 1);
59 		__ASSERT_NO_MSG(prio < CONFIG_NUM_PREEMPT_PRIORITIES);
60 	}
61 
62 	return prio;
63 }
64 
posix_to_zephyr_priority(uint32_t priority,int policy)65 static int32_t posix_to_zephyr_priority(uint32_t priority, int policy)
66 {
67 	int32_t prio;
68 
69 	if (policy == SCHED_FIFO) {
70 		/* Zephyr COOP priority starts from -1 */
71 		__ASSERT_NO_MSG(priority < CONFIG_NUM_COOP_PRIORITIES);
72 		prio =  -1 * (priority + 1);
73 	} else {
74 		__ASSERT_NO_MSG(priority < CONFIG_NUM_PREEMPT_PRIORITIES);
75 		prio = (CONFIG_NUM_PREEMPT_PRIORITIES - priority - 1);
76 	}
77 
78 	return prio;
79 }
80 
81 /**
82  * @brief Set scheduling parameter attributes in thread attributes object.
83  *
84  * See IEEE 1003.1
85  */
pthread_attr_setschedparam(pthread_attr_t * attr,const struct sched_param * schedparam)86 int pthread_attr_setschedparam(pthread_attr_t *attr,
87 			       const struct sched_param *schedparam)
88 {
89 	int priority = schedparam->sched_priority;
90 
91 	if ((attr == NULL) || (attr->initialized == 0U) ||
92 	    (is_posix_prio_valid(priority, attr->schedpolicy) == false)) {
93 		return EINVAL;
94 	}
95 
96 	attr->priority = priority;
97 	return 0;
98 }
99 
100 /**
101  * @brief Set stack attributes in thread attributes object.
102  *
103  * See IEEE 1003.1
104  */
pthread_attr_setstack(pthread_attr_t * attr,void * stackaddr,size_t stacksize)105 int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr,
106 			  size_t stacksize)
107 {
108 	if (stackaddr == NULL) {
109 		return EACCES;
110 	}
111 
112 	attr->stack = stackaddr;
113 	attr->stacksize = stacksize;
114 	return 0;
115 }
116 
zephyr_thread_wrapper(void * arg1,void * arg2,void * arg3)117 static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3)
118 {
119 	void * (*fun_ptr)(void *) = arg3;
120 
121 	fun_ptr(arg1);
122 	pthread_exit(NULL);
123 }
124 
125 /**
126  * @brief Create a new thread.
127  *
128  * Pthread attribute should not be NULL. API will return Error on NULL
129  * attribute value.
130  *
131  * See IEEE 1003.1
132  */
pthread_create(pthread_t * newthread,const pthread_attr_t * attr,void * (* threadroutine)(void *),void * arg)133 int pthread_create(pthread_t *newthread, const pthread_attr_t *attr,
134 		   void *(*threadroutine)(void *), void *arg)
135 {
136 	int32_t prio;
137 	uint32_t pthread_num;
138 	pthread_condattr_t cond_attr;
139 	struct posix_thread *thread;
140 
141 	/*
142 	 * FIXME: Pthread attribute must be non-null and it provides stack
143 	 * pointer and stack size. So even though POSIX 1003.1 spec accepts
144 	 * attrib as NULL but zephyr needs it initialized with valid stack.
145 	 */
146 	if ((attr == NULL) || (attr->initialized == 0U)
147 	    || (attr->stack == NULL) || (attr->stacksize == 0)) {
148 		return EINVAL;
149 	}
150 
151 	pthread_mutex_lock(&pthread_pool_lock);
152 	for (pthread_num = 0;
153 	    pthread_num < CONFIG_MAX_PTHREAD_COUNT; pthread_num++) {
154 		thread = &posix_thread_pool[pthread_num];
155 		if (thread->state == PTHREAD_EXITED || thread->state == PTHREAD_TERMINATED) {
156 			thread->state = PTHREAD_JOINABLE;
157 			break;
158 		}
159 	}
160 	pthread_mutex_unlock(&pthread_pool_lock);
161 
162 	if (pthread_num >= CONFIG_MAX_PTHREAD_COUNT) {
163 		return EAGAIN;
164 	}
165 
166 	prio = posix_to_zephyr_priority(attr->priority, attr->schedpolicy);
167 
168 	thread = &posix_thread_pool[pthread_num];
169 	/*
170 	 * Ignore return value, as we know that Zephyr implementation
171 	 * cannot fail.
172 	 */
173 	(void)pthread_mutex_init(&thread->state_lock, NULL);
174 	(void)pthread_mutex_init(&thread->cancel_lock, NULL);
175 
176 	pthread_mutex_lock(&thread->cancel_lock);
177 	thread->cancel_state = (1 << _PTHREAD_CANCEL_POS) & attr->flags;
178 	thread->cancel_pending = 0;
179 	pthread_mutex_unlock(&thread->cancel_lock);
180 
181 	pthread_mutex_lock(&thread->state_lock);
182 	thread->state = attr->detachstate;
183 	pthread_mutex_unlock(&thread->state_lock);
184 
185 	pthread_cond_init(&thread->state_cond, &cond_attr);
186 	sys_slist_init(&thread->key_list);
187 
188 	*newthread = (pthread_t) k_thread_create(&thread->thread, attr->stack,
189 						 attr->stacksize,
190 						 (k_thread_entry_t)
191 						 zephyr_thread_wrapper,
192 						 (void *)arg, NULL,
193 						 threadroutine, prio,
194 						 (~K_ESSENTIAL & attr->flags),
195 						 K_MSEC(attr->delayedstart));
196 	return 0;
197 }
198 
199 
200 /**
201  * @brief Set cancelability State.
202  *
203  * See IEEE 1003.1
204  */
pthread_setcancelstate(int state,int * oldstate)205 int pthread_setcancelstate(int state, int *oldstate)
206 {
207 	struct posix_thread *pthread = (struct posix_thread *) pthread_self();
208 
209 	if (state != PTHREAD_CANCEL_ENABLE &&
210 	    state != PTHREAD_CANCEL_DISABLE) {
211 		return EINVAL;
212 	}
213 
214 	*oldstate = pthread->cancel_state;
215 
216 	pthread_mutex_lock(&pthread->cancel_lock);
217 	pthread->cancel_state = state;
218 	pthread_mutex_unlock(&pthread->cancel_lock);
219 
220 	if (state == PTHREAD_CANCEL_ENABLE && pthread->cancel_pending) {
221 		pthread_exit((void *)PTHREAD_CANCELED);
222 	}
223 
224 	return 0;
225 }
226 
227 /**
228  * @brief Cancel execution of a thread.
229  *
230  * See IEEE 1003.1
231  */
pthread_cancel(pthread_t pthread)232 int pthread_cancel(pthread_t pthread)
233 {
234 	struct posix_thread *thread = (struct posix_thread *) pthread;
235 	int cancel_state;
236 
237 	if ((thread == NULL) || (thread->state == PTHREAD_TERMINATED)) {
238 		return ESRCH;
239 	}
240 
241 	pthread_mutex_lock(&thread->cancel_lock);
242 	thread->cancel_pending = 1;
243 	cancel_state = thread->cancel_state;
244 	pthread_mutex_unlock(&thread->cancel_lock);
245 
246 	if (cancel_state == PTHREAD_CANCEL_ENABLE) {
247 		pthread_mutex_lock(&thread->state_lock);
248 		if (thread->state == PTHREAD_DETACHED) {
249 			thread->state = PTHREAD_TERMINATED;
250 		} else {
251 			thread->retval = PTHREAD_CANCELED;
252 			thread->state = PTHREAD_EXITED;
253 			pthread_cond_broadcast(&thread->state_cond);
254 		}
255 		pthread_mutex_unlock(&thread->state_lock);
256 
257 		k_thread_abort((k_tid_t) thread);
258 	}
259 
260 	return 0;
261 }
262 
263 /**
264  * @brief Set thread scheduling policy and parameters.
265  *
266  * See IEEE 1003.1
267  */
pthread_setschedparam(pthread_t pthread,int policy,const struct sched_param * param)268 int pthread_setschedparam(pthread_t pthread, int policy,
269 			  const struct sched_param *param)
270 {
271 	k_tid_t thread = (k_tid_t)pthread;
272 	int new_prio;
273 
274 	if (thread == NULL) {
275 		return ESRCH;
276 	}
277 
278 	if (policy != SCHED_RR && policy != SCHED_FIFO) {
279 		return EINVAL;
280 	}
281 
282 	if (is_posix_prio_valid(param->sched_priority, policy) == false) {
283 		return EINVAL;
284 	}
285 
286 	new_prio = posix_to_zephyr_priority(param->sched_priority, policy);
287 
288 	k_thread_priority_set(thread, new_prio);
289 	return 0;
290 }
291 
292 /**
293  * @brief Initialise threads attribute object
294  *
295  * See IEEE 1003.1
296  */
pthread_attr_init(pthread_attr_t * attr)297 int pthread_attr_init(pthread_attr_t *attr)
298 {
299 
300 	if (attr == NULL) {
301 		return ENOMEM;
302 	}
303 
304 	(void)memcpy(attr, &init_pthread_attrs, sizeof(pthread_attr_t));
305 
306 	return 0;
307 }
308 
309 /**
310  * @brief Get thread scheduling policy and parameters
311  *
312  * See IEEE 1003.1
313  */
pthread_getschedparam(pthread_t pthread,int * policy,struct sched_param * param)314 int pthread_getschedparam(pthread_t pthread, int *policy,
315 			  struct sched_param *param)
316 {
317 	struct posix_thread *thread = (struct posix_thread *) pthread;
318 	uint32_t priority;
319 
320 	if ((thread == NULL) || (thread->state == PTHREAD_TERMINATED)) {
321 		return ESRCH;
322 	}
323 
324 	priority = k_thread_priority_get((k_tid_t) thread);
325 
326 	param->sched_priority = zephyr_to_posix_priority(priority, policy);
327 	return 0;
328 }
329 
330 /**
331  * @brief Dynamic package initialization
332  *
333  * See IEEE 1003.1
334  */
pthread_once(pthread_once_t * once,void (* init_func)(void))335 int pthread_once(pthread_once_t *once, void (*init_func)(void))
336 {
337 	pthread_mutex_lock(&pthread_key_lock);
338 
339 	if (*once == PTHREAD_ONCE_INIT) {
340 		pthread_mutex_unlock(&pthread_key_lock);
341 		return 0;
342 	}
343 
344 	init_func();
345 	*once = PTHREAD_ONCE_INIT;
346 
347 	pthread_mutex_unlock(&pthread_key_lock);
348 
349 	return 0;
350 }
351 
352 /**
353  * @brief Terminate calling thread.
354  *
355  * See IEEE 1003.1
356  */
pthread_exit(void * retval)357 void pthread_exit(void *retval)
358 {
359 	struct posix_thread *self = (struct posix_thread *)pthread_self();
360 	pthread_key_obj *key_obj;
361 	pthread_thread_data *thread_spec_data;
362 	sys_snode_t *node_l;
363 
364 	/* Make a thread as cancelable before exiting */
365 	pthread_mutex_lock(&self->cancel_lock);
366 	if (self->cancel_state == PTHREAD_CANCEL_DISABLE) {
367 		self->cancel_state = PTHREAD_CANCEL_ENABLE;
368 	}
369 
370 	pthread_mutex_unlock(&self->cancel_lock);
371 
372 	pthread_mutex_lock(&self->state_lock);
373 	if (self->state == PTHREAD_JOINABLE) {
374 		self->retval = retval;
375 		self->state = PTHREAD_EXITED;
376 		self->retval = retval;
377 		pthread_cond_broadcast(&self->state_cond);
378 	} else {
379 		self->state = PTHREAD_TERMINATED;
380 	}
381 
382 	SYS_SLIST_FOR_EACH_NODE(&self->key_list, node_l) {
383 		thread_spec_data = (pthread_thread_data *)node_l;
384 		if (thread_spec_data != NULL) {
385 			key_obj = thread_spec_data->key;
386 			if (key_obj->destructor != NULL) {
387 				(key_obj->destructor)(thread_spec_data->spec_data);
388 			}
389 		}
390 	}
391 
392 	pthread_mutex_unlock(&self->state_lock);
393 	k_thread_abort((k_tid_t)self);
394 }
395 
396 /**
397  * @brief Wait for a thread termination.
398  *
399  * See IEEE 1003.1
400  */
pthread_join(pthread_t thread,void ** status)401 int pthread_join(pthread_t thread, void **status)
402 {
403 	struct posix_thread *pthread = (struct posix_thread *) thread;
404 	int ret = 0;
405 
406 	if (pthread == NULL) {
407 		return ESRCH;
408 	}
409 
410 	if (pthread == pthread_self()) {
411 		return EDEADLK;
412 	}
413 
414 	pthread_mutex_lock(&pthread->state_lock);
415 
416 	if (pthread->state == PTHREAD_JOINABLE) {
417 		pthread_cond_wait(&pthread->state_cond, &pthread->state_lock);
418 	}
419 
420 	if (pthread->state == PTHREAD_EXITED) {
421 		if (status != NULL) {
422 			*status = pthread->retval;
423 		}
424 	} else if (pthread->state == PTHREAD_DETACHED) {
425 		ret = EINVAL;
426 	} else {
427 		ret = ESRCH;
428 	}
429 
430 	pthread_mutex_unlock(&pthread->state_lock);
431 	return ret;
432 }
433 
434 /**
435  * @brief Detach a thread.
436  *
437  * See IEEE 1003.1
438  */
pthread_detach(pthread_t thread)439 int pthread_detach(pthread_t thread)
440 {
441 	struct posix_thread *pthread = (struct posix_thread *) thread;
442 	int ret = 0;
443 
444 	if (pthread == NULL) {
445 		return ESRCH;
446 	}
447 
448 	pthread_mutex_lock(&pthread->state_lock);
449 
450 	switch (pthread->state) {
451 	case PTHREAD_JOINABLE:
452 		pthread->state = PTHREAD_DETACHED;
453 		/* Broadcast the condition.
454 		 * This will make threads waiting to join this thread continue.
455 		 */
456 		pthread_cond_broadcast(&pthread->state_cond);
457 		break;
458 	case PTHREAD_EXITED:
459 		pthread->state = PTHREAD_TERMINATED;
460 		/* THREAD has already exited.
461 		 * Pthread remained to provide exit status.
462 		 */
463 		break;
464 	case PTHREAD_TERMINATED:
465 		ret = ESRCH;
466 		break;
467 	default:
468 		ret = EINVAL;
469 		break;
470 	}
471 
472 	pthread_mutex_unlock(&pthread->state_lock);
473 	return ret;
474 }
475 
476 /**
477  * @brief Get detach state attribute in thread attributes object.
478  *
479  * See IEEE 1003.1
480  */
pthread_attr_getdetachstate(const pthread_attr_t * attr,int * detachstate)481 int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
482 {
483 	if ((attr == NULL) || (attr->initialized == 0U)) {
484 		return EINVAL;
485 	}
486 
487 	*detachstate = attr->detachstate;
488 	return 0;
489 }
490 
491 /**
492  * @brief Set detach state attribute in thread attributes object.
493  *
494  * See IEEE 1003.1
495  */
pthread_attr_setdetachstate(pthread_attr_t * attr,int detachstate)496 int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
497 {
498 	if ((attr == NULL) || (attr->initialized == 0U) ||
499 	    (detachstate != PTHREAD_CREATE_DETACHED &&
500 	     detachstate != PTHREAD_CREATE_JOINABLE)) {
501 		return EINVAL;
502 	}
503 
504 	attr->detachstate = detachstate;
505 	return 0;
506 }
507 
508 
509 /**
510  * @brief Get scheduling policy attribute in Thread attributes.
511  *
512  * See IEEE 1003.1
513  */
pthread_attr_getschedpolicy(const pthread_attr_t * attr,int * policy)514 int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
515 {
516 	if ((attr == NULL) || (attr->initialized == 0U)) {
517 		return EINVAL;
518 	}
519 
520 	*policy = attr->schedpolicy;
521 	return 0;
522 }
523 
524 
525 /**
526  * @brief Set scheduling policy attribute in Thread attributes object.
527  *
528  * See IEEE 1003.1
529  */
pthread_attr_setschedpolicy(pthread_attr_t * attr,int policy)530 int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
531 {
532 	if ((attr == NULL) || (attr->initialized == 0U) ||
533 	    (policy != SCHED_RR && policy != SCHED_FIFO)) {
534 		return EINVAL;
535 	}
536 
537 	attr->schedpolicy = policy;
538 	return 0;
539 }
540 
541 /**
542  * @brief Get stack size attribute in thread attributes object.
543  *
544  * See IEEE 1003.1
545  */
pthread_attr_getstacksize(const pthread_attr_t * attr,size_t * stacksize)546 int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
547 {
548 	if ((attr == NULL) || (attr->initialized == 0U)) {
549 		return EINVAL;
550 	}
551 
552 	*stacksize = attr->stacksize;
553 	return 0;
554 
555 }
556 
557 /**
558  * @brief Get stack attributes in thread attributes object.
559  *
560  * See IEEE 1003.1
561  */
pthread_attr_getstack(const pthread_attr_t * attr,void ** stackaddr,size_t * stacksize)562 int pthread_attr_getstack(const pthread_attr_t *attr,
563 				 void **stackaddr, size_t *stacksize)
564 {
565 	if ((attr == NULL) || (attr->initialized == 0U)) {
566 		return EINVAL;
567 	}
568 
569 	*stackaddr = attr->stack;
570 	*stacksize = attr->stacksize;
571 	return 0;
572 }
573 
574 /**
575  * @brief Get thread attributes object scheduling parameters.
576  *
577  * See IEEE 1003.1
578  */
pthread_attr_getschedparam(const pthread_attr_t * attr,struct sched_param * schedparam)579 int pthread_attr_getschedparam(const pthread_attr_t *attr,
580 			       struct sched_param *schedparam)
581 {
582 	if ((attr == NULL) || (attr->initialized == 0U)) {
583 		return EINVAL;
584 	}
585 
586 	schedparam->sched_priority = attr->priority;
587 	return 0;
588 }
589 
590 /**
591  * @brief Destroy thread attributes object.
592  *
593  * See IEEE 1003.1
594  */
pthread_attr_destroy(pthread_attr_t * attr)595 int pthread_attr_destroy(pthread_attr_t *attr)
596 {
597 	if ((attr != NULL) && (attr->initialized != 0U)) {
598 		attr->initialized = false;
599 		return 0;
600 	}
601 
602 	return EINVAL;
603 }
604 
pthread_setname_np(pthread_t thread,const char * name)605 int pthread_setname_np(pthread_t thread, const char *name)
606 {
607 #ifdef CONFIG_THREAD_NAME
608 	k_tid_t kthread = (k_tid_t)thread;
609 
610 	if (kthread == NULL) {
611 		return ESRCH;
612 	}
613 
614 	if (name == NULL) {
615 		return EINVAL;
616 	}
617 
618 	return k_thread_name_set(kthread, name);
619 #else
620 	ARG_UNUSED(thread);
621 	ARG_UNUSED(name);
622 	return 0;
623 #endif
624 }
625 
pthread_getname_np(pthread_t thread,char * name,size_t len)626 int pthread_getname_np(pthread_t thread, char *name, size_t len)
627 {
628 #ifdef CONFIG_THREAD_NAME
629 	k_tid_t kthread = (k_tid_t)thread;
630 
631 	if (kthread == NULL) {
632 		return ESRCH;
633 	}
634 
635 	if (name == NULL) {
636 		return EINVAL;
637 	}
638 
639 	memset(name, '\0', len);
640 	return k_thread_name_copy(kthread, name, len-1);
641 #else
642 	ARG_UNUSED(thread);
643 	ARG_UNUSED(name);
644 	ARG_UNUSED(len);
645 	return 0;
646 #endif
647 }
648