1 /*
2 * Copyright (c) 2022-2022 Huawei Device Co., Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific prior written
16 * permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifdef LOSCFG_KERNEL_MEM_PLIMIT
32 #include <stdlib.h>
33 #include <securec.h>
34 #include "los_config.h"
35 #include "los_hook.h"
36 #include "los_process_pri.h"
37 #include "los_plimits.h"
38
39 STATIC ProcMemLimiter *g_procMemLimiter = NULL;
40
OsMemLimiterInit(UINTPTR limite)41 VOID OsMemLimiterInit(UINTPTR limite)
42 {
43 ProcMemLimiter *procMemLimiter = (ProcMemLimiter *)limite;
44 procMemLimiter->limit = OS_NULL_INT;
45 g_procMemLimiter = procMemLimiter;
46 }
47
OsMemLimitSetLimit(UINT32 limit)48 VOID OsMemLimitSetLimit(UINT32 limit)
49 {
50 g_procMemLimiter->limit = limit;
51 }
52
OsMemLimiterAlloc(VOID)53 VOID *OsMemLimiterAlloc(VOID)
54 {
55 ProcMemLimiter *plimite = (ProcMemLimiter *)LOS_MemAlloc(m_aucSysMem1, sizeof(ProcMemLimiter));
56 if (plimite == NULL) {
57 return NULL;
58 }
59 (VOID)memset_s(plimite, sizeof(ProcMemLimiter), 0, sizeof(ProcMemLimiter));
60 return (VOID *)plimite;
61 }
62
OsMemLimiterFree(UINTPTR limite)63 VOID OsMemLimiterFree(UINTPTR limite)
64 {
65 ProcMemLimiter *plimite = (ProcMemLimiter *)limite;
66 if (plimite == NULL) {
67 return;
68 }
69
70 (VOID)LOS_MemFree(m_aucSysMem1, (VOID *)limite);
71 }
72
OsMemLimiterCopy(UINTPTR dest,UINTPTR src)73 VOID OsMemLimiterCopy(UINTPTR dest, UINTPTR src)
74 {
75 ProcMemLimiter *plimiteDest = (ProcMemLimiter *)dest;
76 ProcMemLimiter *plimiteSrc = (ProcMemLimiter *)src;
77 plimiteDest->limit = plimiteSrc->limit;
78 return;
79 }
80
MemLimiteMigrateCheck(UINTPTR curr,UINTPTR parent)81 BOOL MemLimiteMigrateCheck(UINTPTR curr, UINTPTR parent)
82 {
83 ProcMemLimiter *currMemLimit = (ProcMemLimiter *)curr;
84 ProcMemLimiter *parentMemLimit = (ProcMemLimiter *)parent;
85 if ((currMemLimit->usage + parentMemLimit->usage) >= parentMemLimit->limit) {
86 return FALSE;
87 }
88 return TRUE;
89 }
90
OsMemLimiterMigrate(UINTPTR currLimit,UINTPTR parentLimit,UINTPTR process)91 VOID OsMemLimiterMigrate(UINTPTR currLimit, UINTPTR parentLimit, UINTPTR process)
92 {
93 ProcMemLimiter *currMemLimit = (ProcMemLimiter *)currLimit;
94 ProcMemLimiter *parentMemLimit = (ProcMemLimiter *)parentLimit;
95 LosProcessCB *pcb = (LosProcessCB *)process;
96
97 if (pcb == NULL) {
98 parentMemLimit->usage += currMemLimit->usage;
99 parentMemLimit->failcnt += currMemLimit->failcnt;
100 if (parentMemLimit->peak < parentMemLimit->usage) {
101 parentMemLimit->peak = parentMemLimit->usage;
102 }
103 return;
104 }
105
106 parentMemLimit->usage -= pcb->limitStat.memUsed;
107 currMemLimit->usage += pcb->limitStat.memUsed;
108 }
109
OsMemLimitAddProcessCheck(UINTPTR limit,UINTPTR process)110 BOOL OsMemLimitAddProcessCheck(UINTPTR limit, UINTPTR process)
111 {
112 ProcMemLimiter *memLimit = (ProcMemLimiter *)limit;
113 LosProcessCB *pcb = (LosProcessCB *)process;
114 if ((memLimit->usage + pcb->limitStat.memUsed) > memLimit->limit) {
115 return FALSE;
116 }
117 return TRUE;
118 }
119
OsMemLimitAddProcess(UINTPTR limit,UINTPTR process)120 VOID OsMemLimitAddProcess(UINTPTR limit, UINTPTR process)
121 {
122 LosProcessCB *pcb = (LosProcessCB *)process;
123 ProcMemLimiter *plimits = (ProcMemLimiter *)limit;
124 plimits->usage += pcb->limitStat.memUsed;
125 if (plimits->peak < plimits->usage) {
126 plimits->peak = plimits->usage;
127 }
128 return;
129 }
130
OsMemLimitDelProcess(UINTPTR limit,UINTPTR process)131 VOID OsMemLimitDelProcess(UINTPTR limit, UINTPTR process)
132 {
133 LosProcessCB *pcb = (LosProcessCB *)process;
134 ProcMemLimiter *plimits = (ProcMemLimiter *)limit;
135
136 plimits->usage -= pcb->limitStat.memUsed;
137 return;
138 }
139
OsMemLimitSetMemLimit(ProcMemLimiter * memLimit,UINT64 value)140 UINT32 OsMemLimitSetMemLimit(ProcMemLimiter *memLimit, UINT64 value)
141 {
142 UINT32 intSave;
143 if ((memLimit == NULL) || (value == 0)) {
144 return EINVAL;
145 }
146
147 if (memLimit == g_procMemLimiter) {
148 return EPERM;
149 }
150
151 SCHEDULER_LOCK(intSave);
152 if (value < memLimit->usage) {
153 SCHEDULER_UNLOCK(intSave);
154 return EINVAL;
155 }
156
157 memLimit->limit = value;
158 SCHEDULER_UNLOCK(intSave);
159 return LOS_OK;
160 }
161
162 #define MEM_LIMIT_LOCK(state, locked) do { \
163 if (SCHEDULER_HELD()) { \
164 locked = TRUE; \
165 } else { \
166 SCHEDULER_LOCK(state); \
167 } \
168 } while (0)
169
170 #define MEM_LIMIT_UNLOCK(state, locked) do { \
171 if (!locked) { \
172 SCHEDULER_UNLOCK(state); \
173 } \
174 } while (0)
175
OsMemLimitCheckAndMemAdd(UINT32 size)176 UINT32 OsMemLimitCheckAndMemAdd(UINT32 size)
177 {
178 UINT32 intSave;
179 BOOL locked = FALSE;
180 MEM_LIMIT_LOCK(intSave, locked);
181 LosProcessCB *run = OsCurrProcessGet();
182 UINT32 currProcessID = run->processID;
183 if ((run == NULL) || (run->plimits == NULL)) {
184 MEM_LIMIT_UNLOCK(intSave, locked);
185 return LOS_OK;
186 }
187
188 ProcMemLimiter *memLimit = (ProcMemLimiter *)run->plimits->limitsList[PROCESS_LIMITER_ID_MEM];
189 if ((memLimit->usage + size) > memLimit->limit) {
190 memLimit->failcnt++;
191 MEM_LIMIT_UNLOCK(intSave, locked);
192 PRINT_ERR("plimits: process %u adjust the memory limit of Plimits group\n", currProcessID);
193 return ENOMEM;
194 }
195
196 memLimit->usage += size;
197 run->limitStat.memUsed += size;
198 if (memLimit->peak < memLimit->usage) {
199 memLimit->peak = memLimit->usage;
200 }
201 MEM_LIMIT_UNLOCK(intSave, locked);
202 return LOS_OK;
203 }
204
OsMemLimitMemFree(UINT32 size)205 VOID OsMemLimitMemFree(UINT32 size)
206 {
207 UINT32 intSave;
208 BOOL locked = FALSE;
209 MEM_LIMIT_LOCK(intSave, locked);
210 LosProcessCB *run = OsCurrProcessGet();
211 if ((run == NULL) || (run->plimits == NULL)) {
212 MEM_LIMIT_UNLOCK(intSave, locked);
213 return;
214 }
215
216 ProcMemLimiter *memLimit = (ProcMemLimiter *)run->plimits->limitsList[PROCESS_LIMITER_ID_MEM];
217 if (run->limitStat.memUsed > size) {
218 run->limitStat.memUsed -= size;
219 memLimit->usage -= size;
220 }
221 MEM_LIMIT_UNLOCK(intSave, locked);
222 }
223 #endif
224