In process of converting LuaSnap to use eris, not finished
This commit is contained in:
@@ -1,172 +1,72 @@
|
|||||||
|
|
||||||
#include "luasnap.hpp"
|
#include "luasnap.hpp"
|
||||||
|
#include "luastack.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
struct BlockHeader {
|
|
||||||
BlockHeader *prev_;
|
|
||||||
BlockHeader *next_;
|
|
||||||
int32_t sanity_; // 0x12345678 only when linked.
|
|
||||||
size_t size_;
|
|
||||||
bool in_use_;
|
|
||||||
void *snapshot_;
|
|
||||||
};
|
|
||||||
|
|
||||||
size_t blocksize(size_t base) {
|
|
||||||
return base + sizeof(BlockHeader);
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockHeader *pointer_to_header(void *ptr) {
|
|
||||||
return (BlockHeader*)(((char *)ptr) - sizeof(BlockHeader));
|
|
||||||
}
|
|
||||||
|
|
||||||
void *header_to_pointer(BlockHeader *blk) {
|
|
||||||
return (void *)(((char *)blk) + sizeof(BlockHeader));
|
|
||||||
}
|
|
||||||
|
|
||||||
class LuaSnapData {
|
|
||||||
public:
|
|
||||||
lua_State *state_;
|
|
||||||
bool have_snapshot_;
|
|
||||||
BlockHeader sentinel_;
|
|
||||||
|
|
||||||
LuaSnapData();
|
|
||||||
~LuaSnapData();
|
|
||||||
lua_State *state() const { return state_; }
|
|
||||||
bool have_snapshot() const { return have_snapshot_; }
|
|
||||||
void snapshot();
|
|
||||||
void rollback();
|
|
||||||
void link(BlockHeader *blk);
|
|
||||||
void unlink(BlockHeader *blk);
|
|
||||||
void *allocf(void *ptr, size_t osize, size_t nsize);
|
|
||||||
};
|
|
||||||
|
|
||||||
void *lsd_alloc_f(void *lsd, void *ptr, size_t osize, size_t nsize) {
|
|
||||||
return ((LuaSnapData*)lsd)->allocf(ptr, osize, nsize);
|
|
||||||
}
|
|
||||||
|
|
||||||
LuaSnapData::LuaSnapData() {
|
|
||||||
sentinel_.prev_ = &sentinel_;
|
|
||||||
sentinel_.next_ = &sentinel_;
|
|
||||||
sentinel_.size_ = 0;
|
|
||||||
sentinel_.in_use_ = false;
|
|
||||||
sentinel_.snapshot_ = 0;
|
|
||||||
have_snapshot_ = false;
|
|
||||||
state_ = lua_newstate(lsd_alloc_f, (void*)this);
|
|
||||||
}
|
|
||||||
|
|
||||||
LuaSnapData::~LuaSnapData() {
|
|
||||||
std::cerr << "LuaSnapData destructor not implemented." << std::endl;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LuaSnapData::snapshot() {
|
|
||||||
assert(!have_snapshot_);
|
|
||||||
for (BlockHeader *blk = sentinel_.next_; blk != &sentinel_; blk = blk->next_) {
|
|
||||||
assert(blk->in_use_);
|
|
||||||
blk->snapshot_ = malloc(blk->size_);
|
|
||||||
memcpy(blk->snapshot_, header_to_pointer(blk), blk->size_);
|
|
||||||
}
|
|
||||||
have_snapshot_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LuaSnapData::rollback() {
|
|
||||||
assert(have_snapshot_);
|
|
||||||
for (BlockHeader *blk = sentinel_.next_; blk != &sentinel_; ) {
|
|
||||||
BlockHeader *next = blk->next_;
|
|
||||||
if (blk->snapshot_) {
|
|
||||||
memcpy(header_to_pointer(blk), blk->snapshot_, blk->size_);
|
|
||||||
free(blk->snapshot_);
|
|
||||||
blk->snapshot_ = nullptr;
|
|
||||||
blk->in_use_ = true;
|
|
||||||
} else {
|
|
||||||
assert(blk->in_use_);
|
|
||||||
unlink(blk);
|
|
||||||
free(blk);
|
|
||||||
}
|
|
||||||
blk = next;
|
|
||||||
}
|
|
||||||
have_snapshot_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LuaSnapData::link(BlockHeader *blk) {
|
|
||||||
blk->prev_ = sentinel_.prev_;
|
|
||||||
blk->next_ = &sentinel_;
|
|
||||||
blk->prev_->next_ = blk;
|
|
||||||
blk->next_->prev_ = blk;
|
|
||||||
blk->sanity_ = 0x12345678;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LuaSnapData::unlink(BlockHeader *blk) {
|
|
||||||
blk->prev_->next_ = blk->next_;
|
|
||||||
blk->next_->prev_ = blk->prev_;
|
|
||||||
blk->prev_ = nullptr;
|
|
||||||
blk->next_ = nullptr;
|
|
||||||
blk->sanity_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *LuaSnapData::allocf(void *ptr, size_t osize, size_t nsize) {
|
|
||||||
if (nsize == 0) {
|
|
||||||
if (ptr == 0) return nullptr;
|
|
||||||
BlockHeader *blk = pointer_to_header(ptr);
|
|
||||||
assert(blk->sanity_ = 0x12345678);
|
|
||||||
assert(blk->in_use_);
|
|
||||||
if (blk->snapshot_ == nullptr) {
|
|
||||||
unlink(blk);
|
|
||||||
free(blk);
|
|
||||||
} else {
|
|
||||||
blk->in_use_ = false;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
} else if (ptr == NULL) {
|
|
||||||
BlockHeader *blk = (BlockHeader*)malloc(blocksize(nsize));
|
|
||||||
link(blk);
|
|
||||||
blk->size_ = nsize;
|
|
||||||
blk->in_use_ = true;
|
|
||||||
blk->snapshot_ = nullptr;
|
|
||||||
return header_to_pointer(blk);
|
|
||||||
} else {
|
|
||||||
BlockHeader *blk = pointer_to_header(ptr);
|
|
||||||
assert(blk->sanity_ = 0x12345678);
|
|
||||||
assert(blk->in_use_);
|
|
||||||
if (blk->snapshot_ == nullptr) {
|
|
||||||
unlink(blk);
|
|
||||||
blk = (BlockHeader*)realloc(blk, blocksize(nsize));
|
|
||||||
blk->size_ = nsize;
|
|
||||||
link(blk);
|
|
||||||
return header_to_pointer(blk);
|
|
||||||
} else {
|
|
||||||
BlockHeader *nblk = (BlockHeader*)malloc(blocksize(nsize));
|
|
||||||
memcpy(nblk, blk, (blk->size_ < nsize) ? blk->size_ : nsize);
|
|
||||||
blk->in_use_ = false;
|
|
||||||
link(nblk);
|
|
||||||
nblk->size_ = nsize;
|
|
||||||
nblk->in_use_ = true;
|
|
||||||
nblk->snapshot_ = nullptr;
|
|
||||||
return header_to_pointer(nblk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LuaSnap::LuaSnap() {
|
LuaSnap::LuaSnap() {
|
||||||
data_ = new LuaSnapData;
|
state_ = luaL_newstate();
|
||||||
state_ = data_->state();
|
LuaStack LS(state_);
|
||||||
|
LS.rawset(LuaRegistry, "persist", LuaNewTable);
|
||||||
|
LS.rawset(LuaRegistry, "unpersist", LuaNewTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaSnap::~LuaSnap() {
|
LuaSnap::~LuaSnap() {
|
||||||
delete data_;
|
std::cerr << "LuaSnap destructor not implemented yet" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LuaSnap::have_snapshot() const {
|
bool LuaSnap::have_snapshot() const {
|
||||||
return data_->have_snapshot();
|
return !snapshot_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void oss_writer(lua_State *L, const void *p, size_t sz, void *ud) {
|
||||||
|
std::ostringstream *oss = (std::ostringstream *)ud;
|
||||||
|
oss->write((const char *)p, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaSnap::snapshot() {
|
void LuaSnap::snapshot() {
|
||||||
data_->snapshot();
|
// Snapshot and the lua stack should both be empty.
|
||||||
|
assert(snapshot_.empty());
|
||||||
|
assert(lua_gettop(state_) == 0);
|
||||||
|
|
||||||
|
// lua variables that we'll need.
|
||||||
|
LuaVar key, value;
|
||||||
|
LuaRet permstable, regcopy;
|
||||||
|
LuaStack LS(state_, permstable, regcopy, key, value);
|
||||||
|
|
||||||
|
// Construct a copy of the registry table.
|
||||||
|
LS.set(regcopy, LuaNewTable);
|
||||||
|
LS.set(key, LuaNil);
|
||||||
|
while (LS.next(LuaRegistry, key, value) != 0) {
|
||||||
|
LS.rawset(regcopy, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove certain things from the copy.
|
||||||
|
LS.rawset(regcopy, LUA_RIDX_MAINTHREAD, LuaNil);
|
||||||
|
LS.rawset(regcopy, "persist", LuaNil);
|
||||||
|
LS.rawset(regcopy, "unpersist", LuaNil);
|
||||||
|
LS.rawset(regcopy, "world", LuaNil);
|
||||||
|
LS.rawset(regcopy, "gui", LuaNil);
|
||||||
|
LS.result();
|
||||||
|
|
||||||
|
// Get the permanents table from the registry.
|
||||||
|
LS.rawget(permstable, LuaRegistry, "persist");
|
||||||
|
|
||||||
|
// When we call 'LS.result', this should leave the
|
||||||
|
// permstable and the regcopy on the stack.
|
||||||
|
LS.result();
|
||||||
|
assert(lua_gettop(state_) == 2);
|
||||||
|
|
||||||
|
// Call eris to dump the state to an ostringstream,
|
||||||
|
// then save the result.
|
||||||
|
std::ostringstream oss;
|
||||||
|
eris_dump(state_, oss_writer, (void *)&oss);
|
||||||
|
snapshot_ = oss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaSnap::rollback() {
|
void LuaSnap::rollback() {
|
||||||
data_->rollback();
|
assert(!snapshot_.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,11 +25,10 @@
|
|||||||
|
|
||||||
#include "luastack.hpp"
|
#include "luastack.hpp"
|
||||||
|
|
||||||
class LuaSnapData;
|
|
||||||
class LuaSnap {
|
class LuaSnap {
|
||||||
private:
|
private:
|
||||||
lua_State *state_;
|
lua_State *state_;
|
||||||
LuaSnapData *data_;
|
std::string snapshot_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LuaSnap();
|
LuaSnap();
|
||||||
|
|||||||
@@ -369,6 +369,7 @@ public:
|
|||||||
bool isfunction(LuaSlot s) const { return lua_type(L_, s) == LUA_TFUNCTION; }
|
bool isfunction(LuaSlot s) const { return lua_type(L_, s) == LUA_TFUNCTION; }
|
||||||
bool isboolean(LuaSlot s) const { return lua_type(L_, s) == LUA_TBOOLEAN; }
|
bool isboolean(LuaSlot s) const { return lua_type(L_, s) == LUA_TBOOLEAN; }
|
||||||
bool isnil(LuaSlot s) const { return lua_type(L_, s) == LUA_TNIL; }
|
bool isnil(LuaSlot s) const { return lua_type(L_, s) == LUA_TNIL; }
|
||||||
|
bool iscfunction(LuaSlot s) const { return lua_iscfunction(L_, s) != 0; }
|
||||||
|
|
||||||
void checktable(LuaSlot index) const { checktype(index, LUA_TTABLE); }
|
void checktable(LuaSlot index) const { checktype(index, LUA_TTABLE); }
|
||||||
void checkstring(LuaSlot index) const { checktype(index, LUA_TSTRING); }
|
void checkstring(LuaSlot index) const { checktype(index, LUA_TSTRING); }
|
||||||
|
|||||||
@@ -320,3 +320,35 @@ void SourceDB::run_unittests() {
|
|||||||
LS.result();
|
LS.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SourceDB::init(lua_State *L) {
|
||||||
|
lua_state_ = L;
|
||||||
|
LuaVar globtab, persist, unpersist, classname, classtab, funcname, funcp, rawfunc;
|
||||||
|
LuaStack LS(L, globtab, persist, unpersist, classname, classtab, funcname, funcp, rawfunc);
|
||||||
|
|
||||||
|
// We need to register all C functions with the eris permanents tables.
|
||||||
|
source_clear_globals(L);
|
||||||
|
source_install_builtins(L);
|
||||||
|
source_load_cfunctions(L);
|
||||||
|
LS.getglobaltable(globtab);
|
||||||
|
LS.rawget(persist, LuaRegistry, "persist");
|
||||||
|
LS.rawget(unpersist, LuaRegistry, "unpersist");
|
||||||
|
LS.set(classname, LuaNil);
|
||||||
|
while (LS.next(globtab, classname, classtab) != 0) {
|
||||||
|
if (LS.isstring(classname) && LS.istable(classtab)) {
|
||||||
|
LS.set(funcname, LuaNil);
|
||||||
|
while (LS.next(classtab, funcname, funcp) != 0) {
|
||||||
|
if (LS.isstring(funcname) && LS.iscfunction(funcp)) {
|
||||||
|
std::string full = "cfunc:";
|
||||||
|
full += LS.ckstring(classname);
|
||||||
|
full += ".";
|
||||||
|
full += LS.ckstring(funcname);
|
||||||
|
lua_pushcfunction(L, lua_tocfunction(L, funcp.index()));
|
||||||
|
lua_replace(L, rawfunc.index());
|
||||||
|
LS.rawset(persist, rawfunc, full);
|
||||||
|
LS.rawset(unpersist, full, rawfunc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ private:
|
|||||||
lua_State *lua_state_;
|
lua_State *lua_state_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void init(lua_State *L) { lua_state_ = L; }
|
void init(lua_State *L);
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
//
|
//
|
||||||
|
|||||||
Reference in New Issue
Block a user