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 
11 #include <sys/lock.h>
12 
13 /* Define the picolibc lock type */
14 struct __lock {
15 	struct k_mutex m;
16 };
17 
18 STRUCT_SECTION_ITERABLE_ALTERNATE(k_mutex, __lock,
19 				  __lock___libc_recursive_mutex) = {
20 	.m = Z_MUTEX_INITIALIZER(__lock___libc_recursive_mutex.m),
21 };
22 
23 #ifdef CONFIG_USERSPACE
24 /* Grant public access to picolibc lock after boot */
picolibc_locks_prepare(void)25 static int picolibc_locks_prepare(void)
26 {
27 
28 	/* Initialise recursive locks */
29 	k_object_access_all_grant(&__lock___libc_recursive_mutex);
30 
31 	return 0;
32 }
33 
34 SYS_INIT(picolibc_locks_prepare, POST_KERNEL,
35 	 CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
36 #endif /* CONFIG_USERSPACE */
37 
38 /* Create a new dynamic recursive lock */
__retarget_lock_init_recursive(_LOCK_T * lock)39 void __retarget_lock_init_recursive(_LOCK_T *lock)
40 {
41 	__ASSERT_NO_MSG(lock != NULL);
42 
43 	/* Allocate mutex object */
44 #ifndef CONFIG_USERSPACE
45 	*lock = malloc(sizeof(struct __lock));
46 #else
47 	*lock = k_object_alloc(K_OBJ_MUTEX);
48 #endif /* !CONFIG_USERSPACE */
49 	__ASSERT(*lock != NULL, "recursive lock allocation failed");
50 
51 	k_mutex_init(&(*lock)->m);
52 }
53 
54 /* Create a new dynamic non-recursive lock */
__retarget_lock_init(_LOCK_T * lock)55 void __retarget_lock_init(_LOCK_T *lock)
56 {
57 	__retarget_lock_init_recursive(lock);
58 }
59 
60 /* Close dynamic recursive lock */
__retarget_lock_close_recursive(_LOCK_T lock)61 void __retarget_lock_close_recursive(_LOCK_T lock)
62 {
63 	__ASSERT_NO_MSG(lock != NULL);
64 #ifndef CONFIG_USERSPACE
65 	free(lock);
66 #else
67 	k_object_release(lock);
68 #endif /* !CONFIG_USERSPACE */
69 }
70 
71 /* Close dynamic non-recursive lock */
__retarget_lock_close(_LOCK_T lock)72 void __retarget_lock_close(_LOCK_T lock)
73 {
74 	__retarget_lock_close_recursive(lock);
75 }
76 
77 /* Acquiure recursive lock */
__retarget_lock_acquire_recursive(_LOCK_T lock)78 void __retarget_lock_acquire_recursive(_LOCK_T lock)
79 {
80 	__ASSERT_NO_MSG(lock != NULL);
81 	k_mutex_lock(&lock->m, K_FOREVER);
82 }
83 
84 /* Acquiure non-recursive lock */
__retarget_lock_acquire(_LOCK_T lock)85 void __retarget_lock_acquire(_LOCK_T lock)
86 {
87 	__retarget_lock_acquire_recursive(lock);
88 }
89 
90 /* Try acquiring recursive lock */
__retarget_lock_try_acquire_recursive(_LOCK_T lock)91 int __retarget_lock_try_acquire_recursive(_LOCK_T lock)
92 {
93 	__ASSERT_NO_MSG(lock != NULL);
94 	return !k_mutex_lock(&lock->m, K_NO_WAIT);
95 }
96 
97 /* Try acquiring non-recursive lock */
__retarget_lock_try_acquire(_LOCK_T lock)98 int __retarget_lock_try_acquire(_LOCK_T lock)
99 {
100 	return __retarget_lock_try_acquire_recursive(lock);
101 }
102 
103 /* Release recursive lock */
__retarget_lock_release_recursive(_LOCK_T lock)104 void __retarget_lock_release_recursive(_LOCK_T lock)
105 {
106 	__ASSERT_NO_MSG(lock != NULL);
107 	k_mutex_unlock(&lock->m);
108 }
109 
110 /* Release non-recursive lock */
__retarget_lock_release(_LOCK_T lock)111 void __retarget_lock_release(_LOCK_T lock)
112 {
113 	__retarget_lock_release_recursive(lock);
114 }
115 
116 #endif /* CONFIG_MULTITHREADING */
117