Fix crash with bitmaps and resetting Lua VM

Kill requests depending on bitmaps and palettes going away, to avoid
having the emulator crash if there is a request using those bitmaps
and palettes in flight while Lua VM is reset.

Noticed by FatRatKnight.
This commit is contained in:
Ilari Liusvaara 2013-02-28 04:03:01 +02:00
parent 615d525fa6
commit 80c9dcee2d
6 changed files with 77 additions and 5 deletions

View file

@ -101,5 +101,9 @@ void take_screenshot(const std::string& file) throw(std::bad_alloc, std::runtime
* Get scale factors.
*/
std::pair<uint32_t, uint32_t> get_scale_factors(uint32_t width, uint32_t height);
/**
* Kill pending requests associated with object.
*/
void render_kill_request(void* obj);
#endif

View file

@ -355,7 +355,10 @@ struct render_object
* Destructor.
*/
virtual ~render_object() throw();
/**
* Kill object function. If it returns true, kill the request. Default is to return false.
*/
virtual bool kill_request(void* obj) throw();
/**
* Draw the object.
*
@ -537,7 +540,10 @@ struct render_queue
* Frees all objects in the queue without applying them.
*/
void clear() throw();
/**
* Call kill_request on all objects in queue.
*/
void kill_request(void* obj) throw();
/**
* Get memory from internal allocator.
*/
@ -561,7 +567,7 @@ struct render_queue
~render_queue() throw();
private:
void add(struct render_object& obj) throw(std::bad_alloc);
struct node { struct render_object* obj; struct node* next; };
struct node { struct render_object* obj; struct node* next; bool killed; };
struct page { char content[RENDER_PAGE_SIZE]; };
struct node* queue_head;
struct node* queue_tail;

View file

@ -10,6 +10,7 @@
struct lua_bitmap
{
lua_bitmap(uint32_t w, uint32_t h);
~lua_bitmap();
size_t width;
size_t height;
std::vector<uint16_t> pixels;
@ -18,6 +19,7 @@ struct lua_bitmap
struct lua_dbitmap
{
lua_dbitmap(uint32_t w, uint32_t h);
~lua_dbitmap();
size_t width;
size_t height;
std::vector<premultiplied_color> pixels;

View file

@ -326,3 +326,10 @@ void triplebuffer_logic::end_read() throw()
mutex::holder h(*mut);
read_active--;
}
void render_kill_request(void* obj)
{
buffer1.rq.kill_request(obj);
buffer2.rq.kill_request(obj);
buffer3.rq.kill_request(obj);
}

View file

@ -501,6 +501,7 @@ void render_queue::add(struct render_object& obj) throw(std::bad_alloc)
struct node* n = reinterpret_cast<struct node*>(alloc(sizeof(node)));
n->obj = &obj;
n->next = NULL;
n->killed = false;
if(queue_tail)
queue_tail = queue_tail->next = n;
else
@ -512,7 +513,8 @@ template<bool X> void render_queue::run(struct framebuffer<X>& scr) throw()
struct node* tmp = queue_head;
while(tmp) {
try {
(*(tmp->obj))(scr);
if(!tmp->killed)
(*(tmp->obj))(scr);
tmp = tmp->next;
} catch(...) {
}
@ -522,7 +524,8 @@ template<bool X> void render_queue::run(struct framebuffer<X>& scr) throw()
void render_queue::clear() throw()
{
while(queue_head) {
queue_head->obj->~render_object();
if(!queue_head->killed)
queue_head->obj->~render_object();
queue_head = queue_head->next;
}
//Release all memory for reuse.
@ -545,6 +548,22 @@ void* render_queue::alloc(size_t block) throw(std::bad_alloc)
return mem;
}
void render_queue::kill_request(void* obj) throw()
{
struct node* tmp = queue_head;
while(tmp) {
try {
if(!tmp->killed && tmp->obj->kill_request(obj)) {
//Kill this request.
tmp->killed = true;
tmp->obj->~render_object();
}
tmp = tmp->next;
} catch(...) {
}
}
}
render_queue::render_queue() throw()
{
queue_head = NULL;
@ -562,6 +581,11 @@ render_object::~render_object() throw()
{
}
bool render_object::kill_request(void* obj) throw()
{
return false;
}
bitmap_font::bitmap_font() throw(std::bad_alloc)
{
bad_glyph_data[0] = 0x018001AAU;

View file

@ -1,4 +1,5 @@
#include "lua/internal.hpp"
#include "core/framebuffer.hpp"
#include "library/framebuffer.hpp"
#include "lua/bitmap.hpp"
#include <vector>
@ -11,6 +12,11 @@ lua_bitmap::lua_bitmap(uint32_t w, uint32_t h)
memset(&pixels[0], 0, width * height);
}
lua_bitmap::~lua_bitmap()
{
render_kill_request(this);
}
lua_dbitmap::lua_dbitmap(uint32_t w, uint32_t h)
{
width = w;
@ -18,6 +24,11 @@ lua_dbitmap::lua_dbitmap(uint32_t w, uint32_t h)
pixels.resize(width * height);
}
lua_dbitmap::~lua_dbitmap()
{
render_kill_request(this);
}
lua_palette::lua_palette()
{
palette_mutex = &mutex::aquire();
@ -40,6 +51,7 @@ namespace
b = _bitmap;
b2 = NULL;
p = _palette;
killed = false;
}
render_object_bitmap(int32_t _x, int32_t _y, lua_obj_pin<lua_dbitmap>* _bitmap) throw()
@ -49,15 +61,31 @@ namespace
b = NULL;
b2 = _bitmap;
p = NULL;
killed = false;
}
~render_object_bitmap() throw()
{
if(killed)
return;
delete b;
delete b2;
delete p;
}
bool kill_request(void* obj) throw()
{
if(!obj)
return false; //Can't kill on NULL object.
if(p && p->object() == obj)
return killed = true;
if(b && b->object() == obj)
return killed = true;
if(b2 && b2->object() == obj)
return killed = true;
return false;
}
template<bool T> void composite_op(struct framebuffer<T>& scr) throw()
{
if(p)
@ -111,6 +139,7 @@ namespace
lua_obj_pin<lua_bitmap>* b;
lua_obj_pin<lua_dbitmap>* b2;
lua_obj_pin<lua_palette>* p;
bool killed;
};
function_ptr_luafun gui_bitmap("gui.bitmap_draw", [](lua_State* LS, const std::string& fname) -> int {