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 #define DBG_TAG "lwp.internal"
13 #define DBG_LVL DBG_INFO
14 #include <rtdbg.h>
15 
16 #include <stdlib.h>
17 #include "lwp_internal.h"
18 
_mutex_take_safe(rt_mutex_t mtx,rt_int32_t timeout,int flags)19 static rt_err_t _mutex_take_safe(rt_mutex_t mtx, rt_int32_t timeout, int flags)
20 {
21     LWP_DEF_RETURN_CODE(rc);
22     int retry;
23     rt_int32_t effect_timeout;
24 
25 #ifdef LWP_DEBUG
26     rt_thread_t thread = rt_thread_self();
27 #endif
28 
29     if (mtx)
30     {
31         effect_timeout = timeout;
32 #if DBG_LVL == DBG_LOG && defined(LWP_DEBUG)
33         int exception;
34         rt_list_t *node = RT_NULL;
35         struct rt_mutex *tak_obj = RT_NULL;
36         if (!rt_list_isempty(&(thread->taken_object_list)) && timeout == RT_WAITING_FOREVER)
37         {
38             exception = 1;
39             effect_timeout = 0;
40         }
41         else
42         {
43             exception = 0;
44         }
45 #endif /* DBG_LOG && defined(LWP_DEBUG) */
46 
47         do {
48             retry = 0;
49             if (flags & LWP_MTX_FLAGS_INTR)
50                 rc = rt_mutex_take_interruptible(mtx, effect_timeout);
51             else
52                 rc = rt_mutex_take_killable(mtx, effect_timeout);
53 
54 #ifdef LWP_DEBUG
55             if (rc == RT_EOK)
56             {
57                 if (!(flags & LWP_MTX_FALGS_NESTED) && rt_mutex_get_hold(mtx) > 1)
58                 {
59                     LOG_W("Already hold the lock");
60                     rt_backtrace();
61                 }
62             }
63             else if (rc == -RT_ETIMEOUT)
64             {
65 #if DBG_LVL == DBG_LOG
66                 if (exception)
67                 {
68                     rt_list_for_each(node, &(thread->taken_object_list))
69                     {
70                         tak_obj = rt_list_entry(node, struct rt_mutex, taken_list);
71                         if (rt_mutex_get_owner(tak_obj)->stat & RT_THREAD_SUSPEND_MASK)
72                             LOG_D("Potential dead lock - Taken: %s, Try take: %s",
73                                 tak_obj->parent.parent.name, mtx->parent.parent.name);
74                     }
75                     rt_backtrace();
76                     retry = 1;
77                     exception = 0;
78                 }
79 #endif
80             }
81             else if (rc != -RT_EINTR)
82             {
83                 char tname[RT_NAME_MAX];
84                 rt_thread_get_name(thread, tname, sizeof(tname));
85                 LOG_W("Possible kernel corruption detected on thread %s with errno %ld", tname, rc);
86             }
87 #endif /* LWP_DEBUG */
88         } while (retry);
89     }
90     else
91     {
92         rc = -RT_ERROR;
93         LOG_W("%s: mtx should not be NULL", __func__);
94         RT_ASSERT(0);
95     }
96 
97     LWP_RETURN(rc);
98 }
99 
lwp_mutex_take_safe(rt_mutex_t mtx,rt_int32_t timeout,int flags)100 rt_err_t lwp_mutex_take_safe(rt_mutex_t mtx, rt_int32_t timeout, int flags)
101 {
102     LWP_DEF_RETURN_CODE(rc);
103     rc = _mutex_take_safe(mtx, timeout, flags);
104     LWP_RETURN(rc);
105 }
106 
lwp_mutex_release_safe(rt_mutex_t mtx)107 rt_err_t lwp_mutex_release_safe(rt_mutex_t mtx)
108 {
109     LWP_DEF_RETURN_CODE(rc);
110 
111     rc = rt_mutex_release(mtx);
112     if (rc)
113     {
114         LOG_I("%s: release failed with code %ld", __func__, rc);
115         rt_backtrace();
116     }
117 
118     LWP_RETURN(rc);
119 }
120 
lwp_critical_enter(struct rt_lwp * lwp,int flags)121 rt_err_t lwp_critical_enter(struct rt_lwp *lwp, int flags)
122 {
123     rt_err_t rc;
124     do {
125         rc = lwp_mutex_take_safe(&lwp->lwp_lock, RT_WAITING_FOREVER, flags);
126     } while (rc != RT_EOK && !(flags & LWP_MTX_FLAGS_INTR) && rc == -RT_EINTR);
127 
128     /* if current process is force killed */
129     if (rc != RT_EOK && rc != -RT_EINTR)
130     {
131         LOG_I("%s: unexpected return code = %ld", __func__, rc);
132     }
133 
134     return rc;
135 }
136 
lwp_critical_exit(struct rt_lwp * lwp)137 rt_err_t lwp_critical_exit(struct rt_lwp *lwp)
138 {
139     return lwp_mutex_release_safe(&lwp->lwp_lock);
140 }
141 
lwp_pgrp_critical_enter(struct rt_processgroup * pgrp,int flags)142 rt_err_t lwp_pgrp_critical_enter(struct rt_processgroup *pgrp, int flags)
143 {
144     rt_err_t rc;
145     do {
146         rc = lwp_mutex_take_safe(&pgrp->mutex, RT_WAITING_FOREVER, flags);
147     } while (rc != RT_EOK && !(flags & LWP_MTX_FLAGS_INTR) && rc == -RT_EINTR);
148 
149     /* if current process is force killed */
150     if (rc != RT_EOK && rc != -RT_EINTR)
151     {
152         LOG_I("%s: unexpected return code = %ld", __func__, rc);
153     }
154 
155     return rc;
156 }
157 
lwp_pgrp_critical_exit(struct rt_processgroup * pgrp)158 rt_err_t lwp_pgrp_critical_exit(struct rt_processgroup *pgrp)
159 {
160     return lwp_mutex_release_safe(&pgrp->mutex);
161 }
162 
lwp_sess_critical_enter(struct rt_session * sess,int flags)163 rt_err_t lwp_sess_critical_enter(struct rt_session *sess, int flags)
164 {
165     rt_err_t rc;
166     do {
167         rc = lwp_mutex_take_safe(&sess->mutex, RT_WAITING_FOREVER, flags);
168     } while (rc != RT_EOK && !(flags & LWP_MTX_FLAGS_INTR) && rc == -RT_EINTR);
169 
170     /* if current process is force killed */
171     if (rc != RT_EOK && rc != -RT_EINTR)
172     {
173         LOG_I("%s: unexpected return code = %ld", __func__, rc);
174     }
175 
176     return rc;
177 }
178 
lwp_sess_critical_exit(struct rt_session * sess)179 rt_err_t lwp_sess_critical_exit(struct rt_session *sess)
180 {
181     return lwp_mutex_release_safe(&sess->mutex);
182 }
183