1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2023-07-25 Shell first version
9 * 2023-11-25 Shell Add pgrp, session lock API
10 */
11
12 #ifndef __LWP_INTERNAL_H__
13 #define __LWP_INTERNAL_H__
14
15 #include "lwp.h"
16 #include "lwp_arch.h"
17 #include "lwp_user_mm.h"
18 #include "lwp_mm.h"
19
20 #include <rtthread.h>
21 #include "libc_musl.h"
22
23 struct rt_lwp;
24
25 #define LWP_MTX_FLAGS_INTR 0x1 /* interruptible waiting */
26 #define LWP_MTX_FALGS_NESTED 0x2 /* allow nested */
27 rt_err_t lwp_mutex_take_safe(rt_mutex_t mtx, rt_int32_t timeout, int flags);
28 rt_err_t lwp_mutex_release_safe(rt_mutex_t mtx);
29
lwp_in_user_space(const char * addr)30 rt_inline rt_bool_t lwp_in_user_space(const char *addr)
31 {
32 return (addr >= (char *)USER_VADDR_START && addr < (char *)USER_VADDR_TOP);
33 }
34
35 #ifdef RT_USING_SMP
36 #define LOCAL_IRQ_MASK() rt_hw_local_irq_disable()
37 #define LOCAL_IRQ_UNMASK(level) rt_hw_local_irq_enable(level)
38 #else
39 #define LOCAL_IRQ_MASK() rt_hw_interrupt_disable()
40 #define LOCAL_IRQ_UNMASK(level) rt_hw_interrupt_enable(level)
41 #endif
42
43 #ifndef LWP_USING_CPUS_LOCK
44 rt_err_t lwp_sess_critical_enter(struct rt_session *sess, int flags);
45 rt_err_t lwp_sess_critical_exit(struct rt_session *sess);
46 rt_err_t lwp_pgrp_critical_enter(struct rt_processgroup *pgrp, int flags);
47 rt_err_t lwp_pgrp_critical_exit(struct rt_processgroup *pgrp);
48 rt_err_t lwp_critical_enter(struct rt_lwp *lwp, int flags);
49 rt_err_t lwp_critical_exit(struct rt_lwp *lwp);
50
51 #define LWP_ASSERT_LOCKED(proc) RT_ASSERT(rt_mutex_get_owner(&(proc)->lwp_lock) == rt_thread_self())
52 #define PGRP_ASSERT_LOCKED(pgrp) RT_ASSERT(rt_mutex_get_owner(&(pgrp)->mutex) == rt_thread_self())
53
54 #define LWP_LOCK(lwp) \
55 do \
56 { \
57 RT_DEBUG_SCHEDULER_AVAILABLE(1); \
58 if (lwp_critical_enter(lwp, 0) != RT_EOK) \
59 { \
60 RT_ASSERT(0); \
61 } \
62 } while (0)
63
64 #define LWP_LOCK_NESTED(lwp) \
65 do \
66 { \
67 RT_DEBUG_SCHEDULER_AVAILABLE(1); \
68 if (lwp_critical_enter(lwp, LWP_MTX_FALGS_NESTED) != RT_EOK) \
69 { \
70 RT_ASSERT(0); \
71 } \
72 } while (0)
73
74 #define LWP_UNLOCK(lwp) \
75 do { \
76 if (lwp_critical_exit(lwp) != RT_EOK) \
77 { \
78 RT_ASSERT(0); \
79 } \
80 } while (0)
81
82 #define PGRP_LOCK(pgrp) \
83 do \
84 { \
85 RT_DEBUG_SCHEDULER_AVAILABLE(1); \
86 if (lwp_pgrp_critical_enter(pgrp, 0) != RT_EOK) \
87 { \
88 RT_ASSERT(0); \
89 } \
90 } while (0)
91
92 #define PGRP_LOCK_NESTED(pgrp) \
93 do \
94 { \
95 RT_DEBUG_SCHEDULER_AVAILABLE(1); \
96 if (lwp_pgrp_critical_enter(pgrp, LWP_MTX_FALGS_NESTED) != RT_EOK) \
97 { \
98 RT_ASSERT(0); \
99 } \
100 } while (0)
101
102 #define PGRP_UNLOCK(pgrp) \
103 do \
104 { \
105 if (lwp_pgrp_critical_exit(pgrp) != RT_EOK) \
106 { \
107 RT_ASSERT(0); \
108 } \
109 } while (0)
110
111 #define SESS_LOCK(sess) \
112 do \
113 { \
114 RT_DEBUG_SCHEDULER_AVAILABLE(1); \
115 if (lwp_sess_critical_enter(sess, 0) != RT_EOK) \
116 { \
117 RT_ASSERT(0); \
118 } \
119 } while (0)
120
121 #define SESS_LOCK_NESTED(sess) \
122 do \
123 { \
124 RT_DEBUG_SCHEDULER_AVAILABLE(1); \
125 if (lwp_sess_critical_enter(sess, LWP_MTX_FALGS_NESTED) != RT_EOK) \
126 { \
127 RT_ASSERT(0); \
128 } \
129 } while (0)
130
131 #define SESS_UNLOCK(sess) \
132 do \
133 { \
134 if (lwp_sess_critical_exit(sess) != RT_EOK) \
135 { \
136 RT_ASSERT(0); \
137 } \
138 } while (0)
139
140 #else
141
142 #define LWP_LOCK(lwp) rt_base_t level = rt_hw_interrupt_disable()
143 #define LWP_UNLOCK(lwp) rt_hw_interrupt_enable(level)
144 #define PGRP_LOCK(pgrp) rt_base_t level = rt_hw_interrupt_disable()
145 #define PGRP_UNLOCK(pgrp) rt_hw_interrupt_enable(level)
146 #define SESS_LOCK(sess) rt_base_t level = rt_hw_interrupt_disable()
147 #define SESS_UNLOCK(sess) rt_hw_interrupt_enable(level)
148
149 #endif /* LWP_USING_CPUS_LOCK */
150
151 /* cpus lock */
152 #ifdef LWP_OVERRIDE_CPUS_LOCK
153 #undef rt_hw_interrupt_disable
154 #undef rt_hw_interrupt_enable
155
156 #define rt_hw_interrupt_disable() ({ \
157 rt_base_t irq = rt_hw_interrupt_is_disabled(); \
158 if (irq) \
159 { \
160 LOG_W("Nested interrupt disable"); \
161 rt_backtrace(); \
162 irq = 0xabadcafe; \
163 } else { \
164 irq = rt_cpus_lock(); \
165 } \
166 irq; \
167 })
168
169 #define rt_hw_interrupt_enable(level) do { \
170 if (level != 0xabadcafe) \
171 rt_cpus_unlock(level); \
172 } while (0)
173 #endif /* LWP_OVERRIDE_CPUS_LOCK */
174
175 /**
176 * Brief: Return code with safety check
177 * There tend to be chances where a return value is returned without correctly init
178 */
179 #ifndef LWP_DEBUG
180 #define LWP_DEF_RETURN_CODE(name) rt_err_t name;RT_UNUSED(name)
181 #define LWP_RETURN(name) return name
182
183 #else
184 #define _LWP_UNINITIALIZED_RC 0xbeefcafe
185 #define LWP_DEF_RETURN_CODE(name) rt_err_t name = _LWP_UNINITIALIZED_RC
186 #define LWP_RETURN(name) {RT_ASSERT(name != _LWP_UNINITIALIZED_RC);return name;}
187 #endif /* LWP_DEBUG */
188
189 #endif /* __LWP_INTERNAL_H__ */
190