mirror of
https://github.com/opentx/opentx.git
synced 2025-07-21 15:25:17 +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>
|
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)
|
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;
|
return;
|
||||||
|
|
||||||
coord_t srcw = bmp->getWidth();
|
coord_t srcw = bmp->getWidth();
|
||||||
|
|
|
@ -325,10 +325,19 @@ static int luaLcdDrawSource(lua_State *L)
|
||||||
/*luadoc
|
/*luadoc
|
||||||
@function Bitmap.open(name)
|
@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”)
|
@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
|
@notice Only available on Horus
|
||||||
|
|
||||||
@status current Introduced in 2.2.0
|
@status current Introduced in 2.2.0
|
||||||
|
@ -337,18 +346,25 @@ static int luaOpenBitmap(lua_State * L)
|
||||||
{
|
{
|
||||||
const char * filename = luaL_checkstring(L, 1);
|
const char * filename = luaL_checkstring(L, 1);
|
||||||
|
|
||||||
BitmapBuffer ** ptr = (BitmapBuffer **)lua_newuserdata(L, sizeof(BitmapBuffer *));
|
BitmapBuffer ** b = (BitmapBuffer **)lua_newuserdata(L, sizeof(BitmapBuffer *));
|
||||||
*ptr = BitmapBuffer::load(filename);
|
|
||||||
|
|
||||||
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... */
|
luaC_fullgc(L, 1); /* try to free some memory... */
|
||||||
*ptr = BitmapBuffer::load(filename); /* try again */
|
*b = BitmapBuffer::load(filename); /* try again */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*ptr) {
|
if (*b) {
|
||||||
uint32_t size = (*ptr)->getDataSize();
|
uint32_t size = (*b)->getDataSize();
|
||||||
luaExtraMemoryUsage += size;
|
luaExtraMemoryUsage += size;
|
||||||
TRACE("luaOpenBitmap: %p (%u)", *ptr, size);
|
TRACE("luaOpenBitmap: %p (%u)", *b, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
luaL_getmetatable(L, LUA_BITMAPHANDLE);
|
luaL_getmetatable(L, LUA_BITMAPHANDLE);
|
||||||
|
@ -364,13 +380,16 @@ static BitmapBuffer * checkBitmap(lua_State * L, int index)
|
||||||
return *b;
|
return *b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*luadoc
|
/*luadoc
|
||||||
@function Bitmap.getSize(name)
|
@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
|
@notice Only available on Horus
|
||||||
|
|
||||||
|
@ -378,7 +397,7 @@ Return width, heigh of a bitmap in memory
|
||||||
*/
|
*/
|
||||||
static int luaGetBitmapSize(lua_State * L)
|
static int luaGetBitmapSize(lua_State * L)
|
||||||
{
|
{
|
||||||
BitmapBuffer * b = checkBitmap(L, 1);
|
const BitmapBuffer * b = checkBitmap(L, 1);
|
||||||
if (b) {
|
if (b) {
|
||||||
lua_pushinteger(L, b->getWidth());
|
lua_pushinteger(L, b->getWidth());
|
||||||
lua_pushinteger(L, b->getHeight());
|
lua_pushinteger(L, b->getHeight());
|
||||||
|
@ -392,11 +411,18 @@ static int luaGetBitmapSize(lua_State * L)
|
||||||
|
|
||||||
static int luaDestroyBitmap(lua_State * L)
|
static int luaDestroyBitmap(lua_State * L)
|
||||||
{
|
{
|
||||||
BitmapBuffer * ptr = checkBitmap(L, 1);
|
BitmapBuffer * b = checkBitmap(L, 1);
|
||||||
uint32_t size = ptr->getDataSize();
|
if (b) {
|
||||||
TRACE("luaDestroyBitmap: %p (%u)", ptr, size);
|
uint32_t size = b->getDataSize();
|
||||||
if (luaExtraMemoryUsage > size) luaExtraMemoryUsage -= size;
|
TRACE("luaDestroyBitmap: %p (%u)", b, size);
|
||||||
delete ptr;
|
if (luaExtraMemoryUsage >= size) {
|
||||||
|
luaExtraMemoryUsage -= size;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
luaExtraMemoryUsage = 0;
|
||||||
|
}
|
||||||
|
delete b;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,11 +447,12 @@ void registerBitmapClass(lua_State * L)
|
||||||
|
|
||||||
Displays a bitmap at (x,y)
|
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 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
|
@notice Only available on Horus
|
||||||
|
|
||||||
|
@ -434,15 +461,19 @@ Displays a bitmap at (x,y)
|
||||||
static int luaLcdDrawBitmap(lua_State *L)
|
static int luaLcdDrawBitmap(lua_State *L)
|
||||||
{
|
{
|
||||||
if (!luaLcdAllowed) return 0;
|
if (!luaLcdAllowed) return 0;
|
||||||
const BitmapBuffer * bitmap = checkBitmap(L, 1);
|
const BitmapBuffer * b = checkBitmap(L, 1);
|
||||||
int x = luaL_checkinteger(L, 2);
|
|
||||||
int y = luaL_checkinteger(L, 3);
|
|
||||||
unsigned scale = luaL_optunsigned(L, 4, 0);
|
|
||||||
|
|
||||||
if (bitmap) {
|
if (b) {
|
||||||
lcd->drawBitmap(x, y, bitmap, 0, 0, 0, 0, (float) scale/100);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
#elif LCD_DEPTH > 1
|
#elif LCD_DEPTH > 1
|
||||||
|
|
|
@ -165,7 +165,7 @@ void luaClose(lua_State ** L)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// we can only disable Lua for the rest of the session
|
// we can only disable Lua for the rest of the session
|
||||||
luaDisable();
|
if (*L == lsScripts) luaDisable();
|
||||||
}
|
}
|
||||||
UNPROTECT_LUA();
|
UNPROTECT_LUA();
|
||||||
*L = NULL;
|
*L = NULL;
|
||||||
|
@ -954,6 +954,27 @@ bool luaTask(event_t evt, uint8_t scriptType, bool allowLcdUsage)
|
||||||
return scriptWasRun;
|
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)
|
uint32_t luaGetMemUsed(lua_State * L)
|
||||||
{
|
{
|
||||||
return L ? (lua_gc(L, LUA_GCCOUNT, 0) << 10) + lua_gc(L, LUA_GCCOUNTB, 0) : 0;
|
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];
|
extern ScriptInputsOutputs scriptInputsOutputs[MAX_SCRIPTS];
|
||||||
void luaClose(lua_State ** L);
|
void luaClose(lua_State ** L);
|
||||||
bool luaTask(event_t evt, uint8_t scriptType, bool allowLcdUsage);
|
bool luaTask(event_t evt, uint8_t scriptType, bool allowLcdUsage);
|
||||||
|
void checkLuaMemoryUsage();
|
||||||
void luaExec(const char * filename);
|
void luaExec(const char * filename);
|
||||||
void luaDoGc(lua_State * L, bool full);
|
void luaDoGc(lua_State * L, bool full);
|
||||||
void luaError(lua_State * L, uint8_t error, bool acknowledge=true);
|
void luaError(lua_State * L, uint8_t error, bool acknowledge=true);
|
||||||
|
|
|
@ -519,6 +519,7 @@ void luaInitThemesAndWidgets()
|
||||||
// if we got panic during registration
|
// if we got panic during registration
|
||||||
// we disable Lua for this session
|
// we disable Lua for this session
|
||||||
// luaDisable();
|
// luaDisable();
|
||||||
|
luaClose(&lsWidgets);
|
||||||
lsWidgets = 0;
|
lsWidgets = 0;
|
||||||
}
|
}
|
||||||
UNPROTECT_LUA();
|
UNPROTECT_LUA();
|
||||||
|
|
|
@ -138,6 +138,9 @@ void periodicTick_1s()
|
||||||
void periodicTick_10s()
|
void periodicTick_10s()
|
||||||
{
|
{
|
||||||
checkBatteryAlarms();
|
checkBatteryAlarms();
|
||||||
|
#if defined(LUA)
|
||||||
|
checkLuaMemoryUsage();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void periodicTick()
|
void periodicTick()
|
||||||
|
|
|
@ -83,6 +83,10 @@ extern "C" {
|
||||||
#define BOOTLOADER_SIZE 0x8000
|
#define BOOTLOADER_SIZE 0x8000
|
||||||
#define FIRMWARE_ADDRESS 0x08000000
|
#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!)
|
// HSI is at 168Mhz (over-drive is not enabled!)
|
||||||
#define PERI1_FREQUENCY 42000000
|
#define PERI1_FREQUENCY 42000000
|
||||||
#define PERI2_FREQUENCY 84000000
|
#define PERI2_FREQUENCY 84000000
|
||||||
|
|
|
@ -91,6 +91,8 @@ extern "C" {
|
||||||
#define BOOTLOADER_SIZE 0x8000
|
#define BOOTLOADER_SIZE 0x8000
|
||||||
#define FIRMWARE_ADDRESS 0x08000000
|
#define FIRMWARE_ADDRESS 0x08000000
|
||||||
|
|
||||||
|
#define LUA_MEM_MAX (0) // max allowed memory usage for complete Lua (in bytes), 0 means unlimited
|
||||||
|
|
||||||
#if defined(PCBX9E)
|
#if defined(PCBX9E)
|
||||||
#define PERI1_FREQUENCY 42000000
|
#define PERI1_FREQUENCY 42000000
|
||||||
#define PERI2_FREQUENCY 84000000
|
#define PERI2_FREQUENCY 84000000
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue