• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_oom.h"
33 #include "los_init.h"
34 #include "los_vm_dump.h"
35 #include "los_vm_lock.h"
36 #include "los_vm_phys.h"
37 #include "los_vm_filemap.h"
38 #include "los_process_pri.h"
39 #ifdef LOSCFG_BASE_CORE_SWTMR_ENABLE
40 #include "los_swtmr_pri.h"
41 #endif
42 
43 #ifdef LOSCFG_FS_VFS
44 #include "console.h"
45 #endif
46 
47 
48 #ifdef LOSCFG_KERNEL_VM
49 
50 LITE_OS_SEC_BSS OomCB *g_oomCB = NULL;
51 static SPIN_LOCK_INIT(g_oomSpinLock);
52 
OomScoreProcess(LosProcessCB * candidateProcess)53 LITE_OS_SEC_TEXT_MINOR STATIC UINT32 OomScoreProcess(LosProcessCB *candidateProcess)
54 {
55     UINT32 actualPm;
56 
57 #ifndef LOSCFG_KERNEL_SMP
58     (VOID)LOS_MuxAcquire(&candidateProcess->vmSpace->regionMux);
59 #endif
60     /* we only consider actual physical memory here. */
61     OsUProcessPmUsage(candidateProcess->vmSpace, NULL, &actualPm);
62 #ifndef LOSCFG_KERNEL_SMP
63     (VOID)LOS_MuxRelease(&candidateProcess->vmSpace->regionMux);
64 #endif
65     return actualPm;
66 }
67 
OomKillProcess(UINTPTR param)68 LITE_OS_SEC_TEXT_MINOR STATIC UINT32 OomKillProcess(UINTPTR param)
69 {
70     /* we will not kill process, and do nothing here */
71     return LOS_OK;
72 }
73 
OomForceShrinkMemory(VOID)74 LITE_OS_SEC_TEXT_MINOR STATIC UINT32 OomForceShrinkMemory(VOID)
75 {
76     UINT32 i;
77     UINT32 reclaimMemPages = 0;
78 
79     /*
80      * TryShrinkMemory maybe reclaim 0 pages in the first time from active list
81      * to inactive list, and in the second time reclaim memory from inactive list.
82      */
83     for (i = 0; i < MAX_SHRINK_PAGECACHE_TRY; i++) {
84         reclaimMemPages += OsTryShrinkMemory(0);
85     }
86 
87     return reclaimMemPages;
88 }
89 
OomReclaimPageCache(VOID)90 LITE_OS_SEC_TEXT_MINOR STATIC BOOL OomReclaimPageCache(VOID)
91 {
92     UINT32 totalPm = 0;
93     UINT32 usedPm = 0;
94     BOOL isReclaimMemory = FALSE;
95     UINT32 reclaimMemPages;
96     UINT32 i;
97 
98     for (i = 0; i < MAX_SHRINK_PAGECACHE_TRY; i++) {
99         OsVmPhysUsedInfoGet(&usedPm, &totalPm);
100         isReclaimMemory = ((totalPm - usedPm) << PAGE_SHIFT) < g_oomCB->reclaimMemThreshold;
101         if (isReclaimMemory) {
102             /*
103              * we do force memory reclaim from page cache here.
104              * if we get memory, we will reclaim pagecache memory again.
105              * if there is no memory to reclaim, we will return.
106              */
107             reclaimMemPages = OomForceShrinkMemory();
108             if (reclaimMemPages > 0) {
109                 continue;
110             }
111         }
112         break;
113     }
114 
115     return isReclaimMemory;
116 }
117 
118 /*
119  * check is low memory or not, if low memory, try to kill process.
120  * return is kill process or not.
121  */
OomCheckProcess(VOID)122 LITE_OS_SEC_TEXT_MINOR BOOL OomCheckProcess(VOID)
123 {
124     UINT32 totalPm;
125     UINT32 usedPm;
126     BOOL isLowMemory = FALSE;
127 
128     /*
129      * spinlock the current core schedule, make sure oom process atomic
130      * spinlock other place entering OomCheckProcess, make sure oom process mutex
131      */
132     LOS_SpinLock(&g_oomSpinLock);
133 
134     /* first we will check if we need to reclaim pagecache memory */
135     if (OomReclaimPageCache() == FALSE) {
136         LOS_SpinUnlock(&g_oomSpinLock);
137         goto NO_VICTIM_PROCESS;
138     }
139 
140     /* get free bytes */
141     OsVmPhysUsedInfoGet(&usedPm, &totalPm);
142     isLowMemory = ((totalPm - usedPm) << PAGE_SHIFT) < g_oomCB->lowMemThreshold;
143 
144     LOS_SpinUnlock(&g_oomSpinLock);
145 
146     if (isLowMemory) {
147         PRINTK("[oom] OS is in low memory state\n"
148                "total physical memory: %#x(byte), used: %#x(byte),"
149                "free: %#x(byte), low memory threshold: %#x(byte)\n",
150                totalPm << PAGE_SHIFT, usedPm << PAGE_SHIFT,
151                (totalPm - usedPm) << PAGE_SHIFT, g_oomCB->lowMemThreshold);
152     }
153 
154 NO_VICTIM_PROCESS:
155     return isLowMemory;
156 }
157 
158 #ifdef LOSCFG_ENABLE_OOM_LOOP_TASK
OomWriteEvent(VOID)159 STATIC VOID OomWriteEvent(VOID)
160 {
161     OsWriteResourceEvent(OS_RESOURCE_EVENT_OOM);
162 }
163 #endif
164 
OomInfodump(VOID)165 LITE_OS_SEC_TEXT_MINOR VOID OomInfodump(VOID)
166 {
167     PRINTK("[oom] oom loop task status: %s\n"
168            "      oom low memory threshold: %#x(byte)\n"
169            "      oom reclaim memory threshold: %#x(byte)\n"
170            "      oom check interval: %d(microsecond)\n",
171            g_oomCB->enabled ? "enabled" : "disabled",
172            g_oomCB->lowMemThreshold, g_oomCB->reclaimMemThreshold,
173            g_oomCB->checkInterval);
174 }
175 
OomSetLowMemThreashold(UINT32 lowMemThreshold)176 LITE_OS_SEC_TEXT_MINOR VOID OomSetLowMemThreashold(UINT32 lowMemThreshold)
177 {
178     if ((lowMemThreshold > OOM_DEFAULT_LOW_MEM_THRESHOLD_MAX)) {
179         PRINTK("[oom] low memory threshold %#x(byte) invalid,"
180                "should be in [%#x, %#x](byte)\n",
181                lowMemThreshold, OOM_DEFAULT_LOW_MEM_THRESHOLD_MIN,
182                OOM_DEFAULT_LOW_MEM_THRESHOLD_MAX);
183     } else {
184         g_oomCB->lowMemThreshold = lowMemThreshold;
185         PRINTK("[oom] set oom low memory threshold %#x(byte) successful\n",
186                g_oomCB->lowMemThreshold);
187     }
188 }
189 
OomSetReclaimMemThreashold(UINT32 reclaimMemThreshold)190 LITE_OS_SEC_TEXT_MINOR VOID OomSetReclaimMemThreashold(UINT32 reclaimMemThreshold)
191 {
192     UINT32 totalPm = 0;
193     UINT32 usedPm = 0;
194 
195     OsVmPhysUsedInfoGet(&usedPm, &totalPm);
196     if ((reclaimMemThreshold >= (totalPm << PAGE_SHIFT)) ||
197         (reclaimMemThreshold < g_oomCB->lowMemThreshold)) {
198         PRINTK("[oom] reclaim memory threshold %#x(byte) invalid,"
199                "should be in [%#x, %#x)(byte)\n",
200                reclaimMemThreshold, g_oomCB->lowMemThreshold, (totalPm << PAGE_SHIFT));
201     } else {
202         g_oomCB->reclaimMemThreshold = reclaimMemThreshold;
203         PRINTK("[oom] set oom reclaim memory threshold %#x(byte) successful\n",
204                g_oomCB->reclaimMemThreshold);
205     }
206 }
207 
OomSetCheckInterval(UINT32 checkInterval)208 LITE_OS_SEC_TEXT_MINOR VOID OomSetCheckInterval(UINT32 checkInterval)
209 {
210     if ((checkInterval >= OOM_CHECK_MIN) && (checkInterval <= OOM_CHECK_MAX)) {
211         g_oomCB->checkInterval = checkInterval;
212         PRINTK("[oom] set oom check interval (%d)ms successful\n",
213                g_oomCB->checkInterval);
214     } else {
215         PRINTK("[oom] set oom check interval (%d)ms failed, should be in [%d, %d]\n",
216                g_oomCB->checkInterval, OOM_CHECK_MIN, OOM_CHECK_MAX);
217     }
218 }
219 
OomTaskInit(VOID)220 LITE_OS_SEC_TEXT_MINOR UINT32 OomTaskInit(VOID)
221 {
222     g_oomCB = (OomCB *)LOS_MemAlloc(m_aucSysMem0, sizeof(OomCB));
223     if (g_oomCB == NULL) {
224         VM_ERR("oom task init failed, malloc OomCB failed.");
225         return LOS_NOK;
226     }
227 
228     g_oomCB->lowMemThreshold     = OOM_DEFAULT_LOW_MEM_THRESHOLD;
229     g_oomCB->reclaimMemThreshold = OOM_DEFAULT_RECLAIM_MEM_THRESHOLD;
230     g_oomCB->checkInterval       = OOM_DEFAULT_CHECK_INTERVAL;
231     g_oomCB->processVictimCB     = (OomFn)OomKillProcess;
232     g_oomCB->scoreCB             = (OomFn)OomScoreProcess;
233     g_oomCB->enabled             = FALSE;
234 
235 #ifdef LOSCFG_ENABLE_OOM_LOOP_TASK
236     g_oomCB->enabled         = TRUE;
237     UINT32 ret = LOS_SwtmrCreate(g_oomCB->checkInterval, LOS_SWTMR_MODE_PERIOD, (SWTMR_PROC_FUNC)OomWriteEvent,
238                                  &g_oomCB->swtmrID, (UINTPTR)g_oomCB);
239     if (ret != LOS_OK) {
240         return ret;
241     }
242 
243     return LOS_SwtmrStart(g_oomCB->swtmrID);
244 #else
245     return LOS_OK;
246 #endif
247 }
248 
249 LOS_MODULE_INIT(OomTaskInit, LOS_INIT_LEVEL_KMOD_TASK);
250 
251 #endif
252 
253