1 /*
2  * Copyright © 2021, Keith Packard <keithp@keithp.com>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "picolibc-hooks.h"
8 
9 #ifdef CONFIG_MULTITHREADING
10 #define _LOCK_T void *
11 K_MUTEX_DEFINE(__lock___libc_recursive_mutex);
12 
13 #ifdef CONFIG_USERSPACE
14 /* Grant public access to picolibc lock after boot */
picolibc_locks_prepare(void)15 static int picolibc_locks_prepare(void)
16 {
17 
18 	/* Initialise recursive locks */
19 	k_object_access_all_grant(&__lock___libc_recursive_mutex);
20 
21 	return 0;
22 }
23 
24 SYS_INIT(picolibc_locks_prepare, POST_KERNEL,
25 	 CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
26 #endif /* CONFIG_USERSPACE */
27 
28 /* Create a new dynamic recursive lock */
__retarget_lock_init_recursive(_LOCK_T * lock)29 void __retarget_lock_init_recursive(_LOCK_T *lock)
30 {
31 	__ASSERT_NO_MSG(lock != NULL);
32 
33 	/* Allocate mutex object */
34 #ifndef CONFIG_USERSPACE
35 	*lock = malloc(sizeof(struct k_mutex));
36 #else
37 	*lock = k_object_alloc(K_OBJ_MUTEX);
38 #endif /* !CONFIG_USERSPACE */
39 	__ASSERT(*lock != NULL, "recursive lock allocation failed");
40 
41 	k_mutex_init((struct k_mutex *)*lock);
42 }
43 
44 /* Create a new dynamic non-recursive lock */
__retarget_lock_init(_LOCK_T * lock)45 void __retarget_lock_init(_LOCK_T *lock)
46 {
47 	__retarget_lock_init_recursive(lock);
48 }
49 
50 /* Close dynamic recursive lock */
__retarget_lock_close_recursive(_LOCK_T lock)51 void __retarget_lock_close_recursive(_LOCK_T lock)
52 {
53 	__ASSERT_NO_MSG(lock != NULL);
54 #ifndef CONFIG_USERSPACE
55 	free(lock);
56 #else
57 	k_object_release(lock);
58 #endif /* !CONFIG_USERSPACE */
59 }
60 
61 /* Close dynamic non-recursive lock */
__retarget_lock_close(_LOCK_T lock)62 void __retarget_lock_close(_LOCK_T lock)
63 {
64 	__retarget_lock_close_recursive(lock);
65 }
66 
67 /* Acquiure recursive lock */
__retarget_lock_acquire_recursive(_LOCK_T lock)68 void __retarget_lock_acquire_recursive(_LOCK_T lock)
69 {
70 	__ASSERT_NO_MSG(lock != NULL);
71 	k_mutex_lock((struct k_mutex *)lock, K_FOREVER);
72 }
73 
74 /* Acquiure non-recursive lock */
__retarget_lock_acquire(_LOCK_T lock)75 void __retarget_lock_acquire(_LOCK_T lock)
76 {
77 	__retarget_lock_acquire_recursive(lock);
78 }
79 
80 /* Try acquiring recursive lock */
__retarget_lock_try_acquire_recursive(_LOCK_T lock)81 int __retarget_lock_try_acquire_recursive(_LOCK_T lock)
82 {
83 	__ASSERT_NO_MSG(lock != NULL);
84 	return !k_mutex_lock((struct k_mutex *)lock, K_NO_WAIT);
85 }
86 
87 /* Try acquiring non-recursive lock */
__retarget_lock_try_acquire(_LOCK_T lock)88 int __retarget_lock_try_acquire(_LOCK_T lock)
89 {
90 	return __retarget_lock_try_acquire_recursive(lock);
91 }
92 
93 /* Release recursive lock */
__retarget_lock_release_recursive(_LOCK_T lock)94 void __retarget_lock_release_recursive(_LOCK_T lock)
95 {
96 	__ASSERT_NO_MSG(lock != NULL);
97 	k_mutex_unlock((struct k_mutex *)lock);
98 }
99 
100 /* Release non-recursive lock */
__retarget_lock_release(_LOCK_T lock)101 void __retarget_lock_release(_LOCK_T lock)
102 {
103 	__retarget_lock_release_recursive(lock);
104 }
105 
106 #endif /* CONFIG_MULTITHREADING */
107