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