xref: /kernel/liteos_m/kernel/src/los_mux.c (revision 3d8536b4)
1/*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 *    conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 *    of conditions and the following disclaimer in the documentation and/or other materials
13 *    provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 *    to endorse or promote products derived from this software without specific prior written
17 *    permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "los_mux.h"
33#include "los_config.h"
34#include "los_debug.h"
35#include "los_hook.h"
36#include "los_interrupt.h"
37#include "los_memory.h"
38#include "los_sched.h"
39
40#if (LOSCFG_BASE_IPC_MUX == 1)
41
42LITE_OS_SEC_BSS       LosMuxCB*   g_allMux = NULL;
43LITE_OS_SEC_DATA_INIT LOS_DL_LIST g_unusedMuxList;
44
45/*****************************************************************************
46 Function      : OsMuxInit
47 Description  : Initializes the mutex
48 Input        : None
49 Output       : None
50 Return       : LOS_OK on success, or error code on failure
51 *****************************************************************************/
52LITE_OS_SEC_TEXT_INIT UINT32 OsMuxInit(VOID)
53{
54    LosMuxCB *muxNode = NULL;
55    UINT32 index;
56
57    LOS_ListInit(&g_unusedMuxList);
58
59    if (LOSCFG_BASE_IPC_MUX_LIMIT == 0) {
60        return LOS_ERRNO_MUX_MAXNUM_ZERO;
61    }
62
63    g_allMux = (LosMuxCB *)LOS_MemAlloc(m_aucSysMem0, (LOSCFG_BASE_IPC_MUX_LIMIT * sizeof(LosMuxCB)));
64    if (g_allMux == NULL) {
65        return LOS_ERRNO_MUX_NO_MEMORY;
66    }
67
68    for (index = 0; index < LOSCFG_BASE_IPC_MUX_LIMIT; index++) {
69        muxNode = ((LosMuxCB *)g_allMux) + index;
70        muxNode->muxID = index;
71        muxNode->owner = (LosTaskCB *)NULL;
72        muxNode->muxStat = OS_MUX_UNUSED;
73#if (LOSCFG_MUTEX_CREATE_TRACE == 1)
74        muxNode->createInfo = 0;
75#endif
76        LOS_ListTailInsert(&g_unusedMuxList, &muxNode->muxList);
77    }
78    return LOS_OK;
79}
80
81/*****************************************************************************
82 Function     : LOS_MuxCreate
83 Description  : Create a mutex
84 Input        : None
85 Output       : muxHandle ------ Mutex operation handle
86 Return       : LOS_OK on success, or error code on failure
87 *****************************************************************************/
88LITE_OS_SEC_TEXT_INIT UINT32 LOS_MuxCreate(UINT32 *muxHandle)
89{
90    UINT32 intSave;
91    LosMuxCB *muxCreated = NULL;
92    LOS_DL_LIST *unusedMux = NULL;
93    UINT32 errNo;
94    UINT32 errLine;
95
96    if (muxHandle == NULL) {
97        return LOS_ERRNO_MUX_PTR_NULL;
98    }
99
100    intSave = LOS_IntLock();
101    if (LOS_ListEmpty(&g_unusedMuxList)) {
102        LOS_IntRestore(intSave);
103        OS_GOTO_ERR_HANDLER(LOS_ERRNO_MUX_ALL_BUSY);
104    }
105
106    unusedMux = LOS_DL_LIST_FIRST(&(g_unusedMuxList));
107    LOS_ListDelete(unusedMux);
108    muxCreated = (GET_MUX_LIST(unusedMux));
109    muxCreated->muxCount = 0;
110    muxCreated->muxStat = OS_MUX_USED;
111    muxCreated->priority = 0;
112    muxCreated->owner = (LosTaskCB *)NULL;
113    LOS_ListInit(&muxCreated->muxList);
114    *muxHandle = (UINT32)muxCreated->muxID;
115    LOS_IntRestore(intSave);
116    OsHookCall(LOS_HOOK_TYPE_MUX_CREATE, muxCreated);
117    return LOS_OK;
118ERR_HANDLER:
119    OS_RETURN_ERROR_P2(errLine, errNo);
120}
121
122/*****************************************************************************
123 Function     : LOS_MuxDelete
124 Description  : Delete a mutex
125 Input        : muxHandle ------Mutex operation handle
126 Output       : None
127 Return       : LOS_OK on success, or error code on failure
128 *****************************************************************************/
129LITE_OS_SEC_TEXT_INIT UINT32 LOS_MuxDelete(UINT32 muxHandle)
130{
131    UINT32 intSave;
132    LosMuxCB *muxDeleted = NULL;
133    UINT32 errNo;
134    UINT32 errLine;
135
136    if (muxHandle >= (UINT32)LOSCFG_BASE_IPC_MUX_LIMIT) {
137        OS_GOTO_ERR_HANDLER(LOS_ERRNO_MUX_INVALID);
138    }
139
140    muxDeleted = GET_MUX(muxHandle);
141    intSave = LOS_IntLock();
142    if (muxDeleted->muxStat == OS_MUX_UNUSED) {
143        LOS_IntRestore(intSave);
144        OS_GOTO_ERR_HANDLER(LOS_ERRNO_MUX_INVALID);
145    }
146
147    if ((!LOS_ListEmpty(&muxDeleted->muxList)) || muxDeleted->muxCount) {
148        LOS_IntRestore(intSave);
149        OS_GOTO_ERR_HANDLER(LOS_ERRNO_MUX_PENDED);
150    }
151
152    LOS_ListAdd(&g_unusedMuxList, &muxDeleted->muxList);
153    muxDeleted->muxStat = OS_MUX_UNUSED;
154#if (LOSCFG_MUTEX_CREATE_TRACE == 1)
155    muxDeleted->createInfo = 0;
156#endif
157    LOS_IntRestore(intSave);
158
159    OsHookCall(LOS_HOOK_TYPE_MUX_DELETE, muxDeleted);
160    return LOS_OK;
161ERR_HANDLER:
162    OS_RETURN_ERROR_P2(errLine, errNo);
163}
164
165STATIC_INLINE UINT32 OsMuxValidCheck(LosMuxCB *muxPended)
166{
167    if (muxPended->muxStat == OS_MUX_UNUSED) {
168        return LOS_ERRNO_MUX_INVALID;
169    }
170
171    if (OS_INT_ACTIVE) {
172        return LOS_ERRNO_MUX_IN_INTERR;
173    }
174
175    if (g_losTaskLock) {
176        PRINT_ERR("!!!LOS_ERRNO_MUX_PEND_IN_LOCK!!!\n");
177        return LOS_ERRNO_MUX_PEND_IN_LOCK;
178    }
179
180    if (g_losTask.runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {
181        return LOS_ERRNO_MUX_PEND_IN_SYSTEM_TASK;
182    }
183
184    return LOS_OK;
185}
186
187/*****************************************************************************
188 Function     : LOS_MuxPend
189 Description  : Specify the mutex P operation
190 Input        : muxHandle ------ Mutex operation handleone
191              : timeOut   ------- waiting time
192 Output       : None
193 Return       : LOS_OK on success, or error code on failure
194 *****************************************************************************/
195LITE_OS_SEC_TEXT UINT32 LOS_MuxPend(UINT32 muxHandle, UINT32 timeout)
196{
197    UINT32 intSave;
198    LosMuxCB *muxPended = NULL;
199    UINT32 retErr;
200    LosTaskCB *runningTask = NULL;
201
202    if (muxHandle >= (UINT32)LOSCFG_BASE_IPC_MUX_LIMIT) {
203        OS_RETURN_ERROR(LOS_ERRNO_MUX_INVALID);
204    }
205
206    muxPended = GET_MUX(muxHandle);
207    intSave = LOS_IntLock();
208    retErr = OsMuxValidCheck(muxPended);
209    if (retErr) {
210        goto ERROR_MUX_PEND;
211    }
212
213    runningTask = (LosTaskCB *)g_losTask.runTask;
214    if (muxPended->muxCount == 0) {
215        muxPended->muxCount++;
216        muxPended->owner = runningTask;
217        muxPended->priority = runningTask->priority;
218        LOS_IntRestore(intSave);
219        goto HOOK;
220    }
221
222    if (muxPended->owner == runningTask) {
223        muxPended->muxCount++;
224        LOS_IntRestore(intSave);
225        goto HOOK;
226    }
227
228    if (!timeout) {
229        retErr = LOS_ERRNO_MUX_UNAVAILABLE;
230        goto ERROR_MUX_PEND;
231    }
232
233    runningTask->taskMux = (VOID *)muxPended;
234
235    if (muxPended->owner->priority > runningTask->priority) {
236        (VOID)OsSchedModifyTaskSchedParam(muxPended->owner, runningTask->priority);
237    }
238
239    OsSchedTaskWait(&muxPended->muxList, timeout);
240
241    LOS_IntRestore(intSave);
242    OsHookCall(LOS_HOOK_TYPE_MUX_PEND, muxPended, timeout);
243    LOS_Schedule();
244
245    intSave = LOS_IntLock();
246    if (runningTask->taskStatus & OS_TASK_STATUS_TIMEOUT) {
247        runningTask->taskStatus &= (~OS_TASK_STATUS_TIMEOUT);
248        retErr = LOS_ERRNO_MUX_TIMEOUT;
249        goto ERROR_MUX_PEND;
250    }
251
252    LOS_IntRestore(intSave);
253    return LOS_OK;
254
255HOOK:
256    OsHookCall(LOS_HOOK_TYPE_MUX_PEND, muxPended, timeout);
257    return LOS_OK;
258
259ERROR_MUX_PEND:
260    LOS_IntRestore(intSave);
261    OS_RETURN_ERROR(retErr);
262}
263
264/*****************************************************************************
265 Function     : LOS_MuxPost
266 Description  : Specify the mutex V operation,
267 Input        : muxHandle ------ Mutex operation handle
268 Output       : None
269 Return       : LOS_OK on success, or error code on failure
270 *****************************************************************************/
271LITE_OS_SEC_TEXT UINT32 LOS_MuxPost(UINT32 muxHandle)
272{
273    UINT32 intSave;
274    LosMuxCB *muxPosted = GET_MUX(muxHandle);
275    LosTaskCB *resumedTask = NULL;
276    LosTaskCB *runningTask = NULL;
277
278    intSave = LOS_IntLock();
279
280    if ((muxHandle >= (UINT32)LOSCFG_BASE_IPC_MUX_LIMIT) ||
281        (muxPosted->muxStat == OS_MUX_UNUSED)) {
282        LOS_IntRestore(intSave);
283        OS_RETURN_ERROR(LOS_ERRNO_MUX_INVALID);
284    }
285
286    if (OS_INT_ACTIVE) {
287        LOS_IntRestore(intSave);
288        OS_RETURN_ERROR(LOS_ERRNO_MUX_IN_INTERR);
289    }
290
291    runningTask = (LosTaskCB *)g_losTask.runTask;
292    if ((muxPosted->muxCount == 0) || (muxPosted->owner != runningTask)) {
293        LOS_IntRestore(intSave);
294        OS_RETURN_ERROR(LOS_ERRNO_MUX_INVALID);
295    }
296
297    if (--(muxPosted->muxCount) != 0) {
298        LOS_IntRestore(intSave);
299        OsHookCall(LOS_HOOK_TYPE_MUX_POST, muxPosted);
300        return LOS_OK;
301    }
302
303    if ((muxPosted->owner->priority) != muxPosted->priority) {
304        (VOID)OsSchedModifyTaskSchedParam(muxPosted->owner, muxPosted->priority);
305    }
306
307    if (!LOS_ListEmpty(&muxPosted->muxList)) {
308        resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(muxPosted->muxList)));
309
310        muxPosted->muxCount = 1;
311        muxPosted->owner = resumedTask;
312        muxPosted->priority = resumedTask->priority;
313        resumedTask->taskMux = NULL;
314
315        OsSchedTaskWake(resumedTask);
316
317        LOS_IntRestore(intSave);
318        OsHookCall(LOS_HOOK_TYPE_MUX_POST, muxPosted);
319        LOS_Schedule();
320    } else {
321        muxPosted->owner = NULL;
322        LOS_IntRestore(intSave);
323    }
324
325    return LOS_OK;
326}
327
328#endif /* (LOSCFG_BASE_IPC_MUX == 1) */
329