mirror of
https://github.com/opentx/opentx.git
synced 2025-07-19 14:25:11 +03:00
Prevent Lua from allocating all heap memory (Horus) (#4440)
* Fixes #4284: Prevent Lua from allocating all heap memory (Horus) Lua bitmap functions cleanup and docs update Added x or y < 0 check to drawBitmap() * Proper float constant
This commit is contained in:
parent
be61e07939
commit
e80c4c858e
8 changed files with 94 additions and 31 deletions
|
@ -255,7 +255,7 @@ class BitmapBuffer: public BitmapBufferBase<uint16_t>
|
|||
template<class T>
|
||||
void drawBitmap(coord_t x, coord_t y, const T * bmp, coord_t srcx=0, coord_t srcy=0, coord_t w=0, coord_t h=0, float scale=0)
|
||||
{
|
||||
if (!data || !bmp || x >= width || y >= height)
|
||||
if (!data || !bmp || x < 0 || x >= width || y < 0 || y >= height)
|
||||
return;
|
||||
|
||||
coord_t srcw = bmp->getWidth();
|
||||
|
|
|
@ -325,10 +325,19 @@ static int luaLcdDrawSource(lua_State *L)
|
|||
/*luadoc
|
||||
@function Bitmap.open(name)
|
||||
|
||||
Loads a bitmap in memory, for later use with lcd.drawBitmap()
|
||||
Loads a bitmap in memory, for later use with lcd.drawBitmap(). Bitmaps should be loaded only
|
||||
once, returned object should be stored and used for drawing. If loading fails for whatever
|
||||
reason the resulting bitmap object will have width and height set to zero.
|
||||
|
||||
Bitmap loading can fail if:
|
||||
* File is not found or contains invalid image
|
||||
* System is low on memory
|
||||
* Combined memory usage of all Lua script bitmaps exceeds certain value
|
||||
|
||||
@param name (string) full path to the bitmap on SD card (i.e. “/IMAGES/test.bmp”)
|
||||
|
||||
@retval bitmap (object) a bitmap object that can be used with other bitmap functions
|
||||
|
||||
@notice Only available on Horus
|
||||
|
||||
@status current Introduced in 2.2.0
|
||||
|
@ -337,18 +346,25 @@ static int luaOpenBitmap(lua_State * L)
|
|||
{
|
||||
const char * filename = luaL_checkstring(L, 1);
|
||||
|
||||
BitmapBuffer ** ptr = (BitmapBuffer **)lua_newuserdata(L, sizeof(BitmapBuffer *));
|
||||
*ptr = BitmapBuffer::load(filename);
|
||||
BitmapBuffer ** b = (BitmapBuffer **)lua_newuserdata(L, sizeof(BitmapBuffer *));
|
||||
|
||||
if (*ptr == NULL && G(L)->gcrunning) {
|
||||
if (luaExtraMemoryUsage > LUA_MEM_EXTRA_MAX) {
|
||||
// already allocated more than max allowed, fail
|
||||
TRACE("luaOpenBitmap: Error, using too much memory %u/%u", luaExtraMemoryUsage, LUA_MEM_EXTRA_MAX);
|
||||
*b = 0;
|
||||
}
|
||||
else {
|
||||
*b = BitmapBuffer::load(filename);
|
||||
if (*b == NULL && G(L)->gcrunning) {
|
||||
luaC_fullgc(L, 1); /* try to free some memory... */
|
||||
*ptr = BitmapBuffer::load(filename); /* try again */
|
||||
*b = BitmapBuffer::load(filename); /* try again */
|
||||
}
|
||||
}
|
||||
|
||||
if (*ptr) {
|
||||
uint32_t size = (*ptr)->getDataSize();
|
||||
if (*b) {
|
||||
uint32_t size = (*b)->getDataSize();
|
||||
luaExtraMemoryUsage += size;
|
||||
TRACE("luaOpenBitmap: %p (%u)", *ptr, size);
|
||||
TRACE("luaOpenBitmap: %p (%u)", *b, size);
|
||||
}
|
||||
|
||||
luaL_getmetatable(L, LUA_BITMAPHANDLE);
|
||||
|
@ -364,13 +380,16 @@ static BitmapBuffer * checkBitmap(lua_State * L, int index)
|
|||
return *b;
|
||||
}
|
||||
|
||||
|
||||
/*luadoc
|
||||
@function Bitmap.getSize(name)
|
||||
|
||||
Return width, heigh of a bitmap in memory
|
||||
Return width, height of a bitmap object
|
||||
|
||||
@param bitmap (pointer) point to a bitmap previously opened with Bipmap.open()
|
||||
@param bitmap (pointer) point to a bitmap previously opened with Bitmap.open()
|
||||
|
||||
@retval multiple returns 2 values:
|
||||
* (number) width in pixels
|
||||
* (number) height in pixels
|
||||
|
||||
@notice Only available on Horus
|
||||
|
||||
|
@ -378,7 +397,7 @@ Return width, heigh of a bitmap in memory
|
|||
*/
|
||||
static int luaGetBitmapSize(lua_State * L)
|
||||
{
|
||||
BitmapBuffer * b = checkBitmap(L, 1);
|
||||
const BitmapBuffer * b = checkBitmap(L, 1);
|
||||
if (b) {
|
||||
lua_pushinteger(L, b->getWidth());
|
||||
lua_pushinteger(L, b->getHeight());
|
||||
|
@ -392,11 +411,18 @@ static int luaGetBitmapSize(lua_State * L)
|
|||
|
||||
static int luaDestroyBitmap(lua_State * L)
|
||||
{
|
||||
BitmapBuffer * ptr = checkBitmap(L, 1);
|
||||
uint32_t size = ptr->getDataSize();
|
||||
TRACE("luaDestroyBitmap: %p (%u)", ptr, size);
|
||||
if (luaExtraMemoryUsage > size) luaExtraMemoryUsage -= size;
|
||||
delete ptr;
|
||||
BitmapBuffer * b = checkBitmap(L, 1);
|
||||
if (b) {
|
||||
uint32_t size = b->getDataSize();
|
||||
TRACE("luaDestroyBitmap: %p (%u)", b, size);
|
||||
if (luaExtraMemoryUsage >= size) {
|
||||
luaExtraMemoryUsage -= size;
|
||||
}
|
||||
else {
|
||||
luaExtraMemoryUsage = 0;
|
||||
}
|
||||
delete b;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -421,11 +447,12 @@ void registerBitmapClass(lua_State * L)
|
|||
|
||||
Displays a bitmap at (x,y)
|
||||
|
||||
@param bitmap (pointer) point to a bitmap previously opened with Bipmap.open()
|
||||
@param bitmap (pointer) point to a bitmap previously opened with Bitmap.open()
|
||||
|
||||
@param x,y (positive numbers) starting coordinates
|
||||
|
||||
@param scale (positive numbers) scale in %, 50 divides size by two, 100 is unchanged, 200 doubles size
|
||||
@param scale (positive numbers) scale in %, 50 divides size by two, 100 is unchanged, 200 doubles size.
|
||||
Omitting scale draws image in 1:1 scale and is faster than specifying 100 for scale.
|
||||
|
||||
@notice Only available on Horus
|
||||
|
||||
|
@ -434,15 +461,19 @@ Displays a bitmap at (x,y)
|
|||
static int luaLcdDrawBitmap(lua_State *L)
|
||||
{
|
||||
if (!luaLcdAllowed) return 0;
|
||||
const BitmapBuffer * bitmap = checkBitmap(L, 1);
|
||||
int x = luaL_checkinteger(L, 2);
|
||||
int y = luaL_checkinteger(L, 3);
|
||||
unsigned scale = luaL_optunsigned(L, 4, 0);
|
||||
const BitmapBuffer * b = checkBitmap(L, 1);
|
||||
|
||||
if (bitmap) {
|
||||
lcd->drawBitmap(x, y, bitmap, 0, 0, 0, 0, (float) scale/100);
|
||||
if (b) {
|
||||
unsigned int x = luaL_checkunsigned(L, 2);
|
||||
unsigned int y = luaL_checkunsigned(L, 3);
|
||||
unsigned int scale = luaL_optunsigned(L, 4, 0);
|
||||
if (scale) {
|
||||
lcd->drawBitmap(x, y, b, 0, 0, 0, 0, scale/100.0f);
|
||||
}
|
||||
else {
|
||||
lcd->drawBitmap(x, y, b);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#elif LCD_DEPTH > 1
|
||||
|
|
|
@ -165,7 +165,7 @@ void luaClose(lua_State ** L)
|
|||
}
|
||||
else {
|
||||
// we can only disable Lua for the rest of the session
|
||||
luaDisable();
|
||||
if (*L == lsScripts) luaDisable();
|
||||
}
|
||||
UNPROTECT_LUA();
|
||||
*L = NULL;
|
||||
|
@ -954,6 +954,27 @@ bool luaTask(event_t evt, uint8_t scriptType, bool allowLcdUsage)
|
|||
return scriptWasRun;
|
||||
}
|
||||
|
||||
void checkLuaMemoryUsage()
|
||||
{
|
||||
#if (LUA_MEM_MAX > 0)
|
||||
uint32_t totalMemUsed = luaGetMemUsed(lsScripts);
|
||||
#if defined(COLORLCD)
|
||||
totalMemUsed += luaGetMemUsed(lsWidgets);
|
||||
totalMemUsed += luaExtraMemoryUsage;
|
||||
#endif
|
||||
if (totalMemUsed > LUA_MEM_MAX) {
|
||||
TRACE("checkLuaMemoryUsage(): max limit reached (%u), killing Lua", totalMemUsed);
|
||||
// disable Lua scripts
|
||||
luaClose(&lsScripts);
|
||||
luaDisable();
|
||||
#if defined(COLORLCD)
|
||||
// disable widgets
|
||||
luaClose(&lsWidgets);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t luaGetMemUsed(lua_State * L)
|
||||
{
|
||||
return L ? (lua_gc(L, LUA_GCCOUNT, 0) << 10) + lua_gc(L, LUA_GCCOUNTB, 0) : 0;
|
||||
|
|
|
@ -118,6 +118,7 @@ extern ScriptInternalData scriptInternalData[MAX_SCRIPTS];
|
|||
extern ScriptInputsOutputs scriptInputsOutputs[MAX_SCRIPTS];
|
||||
void luaClose(lua_State ** L);
|
||||
bool luaTask(event_t evt, uint8_t scriptType, bool allowLcdUsage);
|
||||
void checkLuaMemoryUsage();
|
||||
void luaExec(const char * filename);
|
||||
void luaDoGc(lua_State * L, bool full);
|
||||
void luaError(lua_State * L, uint8_t error, bool acknowledge=true);
|
||||
|
|
|
@ -519,6 +519,7 @@ void luaInitThemesAndWidgets()
|
|||
// if we got panic during registration
|
||||
// we disable Lua for this session
|
||||
// luaDisable();
|
||||
luaClose(&lsWidgets);
|
||||
lsWidgets = 0;
|
||||
}
|
||||
UNPROTECT_LUA();
|
||||
|
|
|
@ -138,6 +138,9 @@ void periodicTick_1s()
|
|||
void periodicTick_10s()
|
||||
{
|
||||
checkBatteryAlarms();
|
||||
#if defined(LUA)
|
||||
checkLuaMemoryUsage();
|
||||
#endif
|
||||
}
|
||||
|
||||
void periodicTick()
|
||||
|
|
|
@ -83,6 +83,10 @@ extern "C" {
|
|||
#define BOOTLOADER_SIZE 0x8000
|
||||
#define FIRMWARE_ADDRESS 0x08000000
|
||||
|
||||
#define MB *1024*1024
|
||||
#define LUA_MEM_EXTRA_MAX (2 MB) // max allowed memory usage for Lua bitmaps (in bytes)
|
||||
#define LUA_MEM_MAX (6 MB) // max allowed memory usage for complete Lua (in bytes), 0 means unlimited
|
||||
|
||||
// HSI is at 168Mhz (over-drive is not enabled!)
|
||||
#define PERI1_FREQUENCY 42000000
|
||||
#define PERI2_FREQUENCY 84000000
|
||||
|
|
|
@ -91,6 +91,8 @@ extern "C" {
|
|||
#define BOOTLOADER_SIZE 0x8000
|
||||
#define FIRMWARE_ADDRESS 0x08000000
|
||||
|
||||
#define LUA_MEM_MAX (0) // max allowed memory usage for complete Lua (in bytes), 0 means unlimited
|
||||
|
||||
#if defined(PCBX9E)
|
||||
#define PERI1_FREQUENCY 42000000
|
||||
#define PERI2_FREQUENCY 84000000
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue