forked from len0rd/rockbox
Lua Add Emergency Garbage Collector
Derivative of work by RobertGabrielJakabosky http://lua-users.org/wiki/EmergencyGarbageCollector I've only implemented the not enough memory part and expanded this idea to adding a mechanism to signal the OOM condition of the plugin buffer which allows us to only grab the playback buffer after garbage collection fails (SO THE MUSIC KEEPS PLAYING AS LONG AS POSSIBLE) Change-Id: I684fb98b540ffc01f7ba324ab5b761ceb59b9f9b
This commit is contained in:
parent
4beafe16fa
commit
45bd14b392
21 changed files with 266 additions and 68 deletions
|
@ -24,6 +24,7 @@ ltable.c
|
|||
ltablib.c
|
||||
ltm.c
|
||||
lundump.c
|
||||
lua_user.c
|
||||
lvm.c
|
||||
lzio.c
|
||||
rockaux.c
|
||||
|
|
|
@ -547,7 +547,9 @@ LUA_API void lua_getfield (lua_State *L, int idx, const char *k) {
|
|||
lua_lock(L);
|
||||
t = index2adr(L, idx);
|
||||
api_checkvalidindex(L, t);
|
||||
fixedstack(L);
|
||||
setsvalue(L, &key, luaS_new(L, k));
|
||||
unfixedstack(L);
|
||||
luaV_gettable(L, t, &key, L->top);
|
||||
api_incr_top(L);
|
||||
lua_unlock(L);
|
||||
|
@ -656,14 +658,14 @@ LUA_API void lua_settable (lua_State *L, int idx) {
|
|||
|
||||
LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
|
||||
StkId t;
|
||||
TValue key;
|
||||
lua_lock(L);
|
||||
api_checknelems(L, 1);
|
||||
t = index2adr(L, idx);
|
||||
api_checkvalidindex(L, t);
|
||||
setsvalue(L, &key, luaS_new(L, k));
|
||||
luaV_settable(L, t, &key, L->top - 1);
|
||||
L->top--; /* pop value */
|
||||
setsvalue2s(L, L->top, luaS_new(L, k));
|
||||
api_incr_top(L);
|
||||
luaV_settable(L, t, L->top - 1, L->top - 2);
|
||||
L->top -= 2; /* pop key and value */
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
||||
|
@ -674,7 +676,9 @@ LUA_API void lua_rawset (lua_State *L, int idx) {
|
|||
api_checknelems(L, 2);
|
||||
t = index2adr(L, idx);
|
||||
api_check(L, ttistable(t));
|
||||
fixedstack(L);
|
||||
setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1);
|
||||
unfixedstack(L);
|
||||
luaC_barriert(L, hvalue(t), L->top-1);
|
||||
L->top -= 2;
|
||||
lua_unlock(L);
|
||||
|
@ -687,7 +691,9 @@ LUA_API void lua_rawseti (lua_State *L, int idx, int n) {
|
|||
api_checknelems(L, 1);
|
||||
o = index2adr(L, idx);
|
||||
api_check(L, ttistable(o));
|
||||
fixedstack(L);
|
||||
setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1);
|
||||
unfixedstack(L);
|
||||
luaC_barriert(L, hvalue(o), L->top-1);
|
||||
L->top--;
|
||||
lua_unlock(L);
|
||||
|
@ -903,11 +909,11 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
|
|||
g = G(L);
|
||||
switch (what) {
|
||||
case LUA_GCSTOP: {
|
||||
g->GCthreshold = MAX_LUMEM;
|
||||
set_block_gc(L);
|
||||
break;
|
||||
}
|
||||
case LUA_GCRESTART: {
|
||||
g->GCthreshold = g->totalbytes;
|
||||
unset_block_gc(L);
|
||||
break;
|
||||
}
|
||||
case LUA_GCCOLLECT: {
|
||||
|
@ -924,6 +930,10 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
|
|||
break;
|
||||
}
|
||||
case LUA_GCSTEP: {
|
||||
if(is_block_gc(L)) {
|
||||
res = 1; /* gc is block so we need to pretend that the collection cycle finished. */
|
||||
break;
|
||||
}
|
||||
lu_mem a = (cast(lu_mem, data) << 10);
|
||||
if (a <= g->totalbytes)
|
||||
g->GCthreshold = g->totalbytes - a;
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <string.h>
|
||||
#include "lstring.h" /* ROCKLUA ADDED */
|
||||
|
||||
|
||||
/* This file uses only the official API of Lua.
|
||||
** Any function declared here could be written as an application function.
|
||||
** Note ** luaS_newlloc breaks this guarantee ROCKLUA ADDED
|
||||
|
@ -34,7 +33,9 @@
|
|||
#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \
|
||||
lua_gettop(L) + (i) + 1)
|
||||
|
||||
|
||||
#ifndef LUA_OOM
|
||||
#define LUA_OOM(L) {}
|
||||
#endif
|
||||
/*
|
||||
** {======================================================
|
||||
** Error-report functions
|
||||
|
@ -756,14 +757,30 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s) {
|
|||
|
||||
|
||||
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
|
||||
(void)ud;
|
||||
(void)osize;
|
||||
(void) osize;
|
||||
lua_State *L = (lua_State *)ud;
|
||||
void *nptr;
|
||||
|
||||
if (nsize == 0) {
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
return realloc(ptr, nsize);
|
||||
|
||||
nptr = realloc(ptr, nsize);
|
||||
if (nptr == NULL) {
|
||||
if(L != NULL)
|
||||
{
|
||||
luaC_fullgc(L); /* emergency full collection. */
|
||||
nptr = realloc(ptr, nsize); /* try allocation again */
|
||||
}
|
||||
|
||||
if (nptr == NULL) {
|
||||
LUA_OOM(L); /* if defined.. signal OOM condition */
|
||||
nptr = realloc(ptr, nsize); /* try allocation again */
|
||||
}
|
||||
}
|
||||
|
||||
return nptr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -779,6 +796,7 @@ static int panic (lua_State *L) {
|
|||
|
||||
LUALIB_API lua_State *luaL_newstate (void) {
|
||||
lua_State *L = lua_newstate(l_alloc, NULL);
|
||||
lua_setallocf(L, l_alloc, L); /* allocator needs lua_State. */
|
||||
if (L) lua_atpanic(L, &panic);
|
||||
return L;
|
||||
}
|
||||
|
|
|
@ -51,11 +51,13 @@ struct lua_longjmp {
|
|||
void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
|
||||
switch (errcode) {
|
||||
case LUA_ERRMEM: {
|
||||
setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG));
|
||||
ptrdiff_t oldtopr = savestack(L, oldtop);
|
||||
setsvalue2s(L, restorestack(L, oldtopr), luaS_newliteral(L, MEMERRMSG));
|
||||
break;
|
||||
}
|
||||
case LUA_ERRERR: {
|
||||
setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));
|
||||
ptrdiff_t oldtopr = savestack(L, oldtop);
|
||||
setsvalue2s(L, restorestack(L, oldtopr), luaS_newliteral(L, "error in error handling"));
|
||||
break;
|
||||
}
|
||||
case LUA_ERRSYNTAX:
|
||||
|
@ -92,6 +94,8 @@ static void resetstack (lua_State *L, int status) {
|
|||
|
||||
|
||||
void luaD_throw (lua_State *L, int errcode) {
|
||||
unfixedstack(L); /* make sure the fixedstack & block_gc flags get reset. */
|
||||
unset_block_gc(L);
|
||||
if (L->errorJmp) {
|
||||
L->errorJmp->status = errcode;
|
||||
LUAI_THROW(L, L->errorJmp);
|
||||
|
@ -208,7 +212,9 @@ void luaD_callhook (lua_State *L, int event, int line) {
|
|||
static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
|
||||
int i;
|
||||
int nfixargs = p->numparams;
|
||||
#if defined(LUA_COMPAT_VARARG)
|
||||
Table *htab = NULL;
|
||||
#endif
|
||||
StkId base, fixed;
|
||||
for (; actual < nfixargs; ++actual)
|
||||
setnilvalue(L->top++);
|
||||
|
@ -219,10 +225,15 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
|
|||
luaC_checkGC(L);
|
||||
luaD_checkstack(L, p->maxstacksize);
|
||||
htab = luaH_new(L, nvar, 1); /* create `arg' table */
|
||||
sethvalue2s(L, L->top, htab); /* put table on stack */
|
||||
incr_top(L);
|
||||
fixedstack(L);
|
||||
for (i=0; i<nvar; i++) /* put extra arguments into `arg' table */
|
||||
setobj2n(L, luaH_setnum(L, htab, i+1), L->top - nvar + i);
|
||||
setobj2n(L, luaH_setnum(L, htab, i+1), L->top - 1 - nvar + i);
|
||||
unfixedstack(L);
|
||||
/* store counter in field `n' */
|
||||
setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar));
|
||||
L->top--; /* remove table from stack */
|
||||
}
|
||||
#endif
|
||||
/* move fixed parameters to final position */
|
||||
|
@ -232,11 +243,13 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
|
|||
setobjs2s(L, L->top++, fixed+i);
|
||||
setnilvalue(fixed+i);
|
||||
}
|
||||
#if defined(LUA_COMPAT_VARARG)
|
||||
/* add `arg' parameter */
|
||||
if (htab) {
|
||||
sethvalue(L, L->top++, htab);
|
||||
lua_assert(iswhite(obj2gco(htab)));
|
||||
}
|
||||
#endif
|
||||
return base;
|
||||
}
|
||||
|
||||
|
@ -495,6 +508,7 @@ static void f_parser (lua_State *L, void *ud) {
|
|||
struct SParser *p = cast(struct SParser *, ud);
|
||||
int c = luaZ_lookahead(p->z);
|
||||
luaC_checkGC(L);
|
||||
set_block_gc(L); /* stop collector during parsing */
|
||||
tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z,
|
||||
&p->buff, p->name);
|
||||
cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L)));
|
||||
|
@ -503,6 +517,7 @@ static void f_parser (lua_State *L, void *ud) {
|
|||
cl->l.upvals[i] = luaF_newupval(L);
|
||||
setclvalue(L, L->top, cl);
|
||||
incr_top(L);
|
||||
unset_block_gc(L);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -66,7 +66,6 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
|
|||
}
|
||||
uv = luaM_new(L, UpVal); /* not found: create a new one */
|
||||
uv->tt = LUA_TUPVAL;
|
||||
uv->marked = luaC_white(g);
|
||||
uv->v = level; /* current value lives in the stack */
|
||||
uv->next = *pp; /* chain it in the proper position */
|
||||
*pp = obj2gco(uv);
|
||||
|
@ -74,6 +73,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
|
|||
uv->u.l.next = g->uvhead.u.l.next;
|
||||
uv->u.l.next->u.l.prev = uv;
|
||||
g->uvhead.u.l.next = uv;
|
||||
luaC_marknew(L, obj2gco(uv));
|
||||
lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
|
||||
return uv;
|
||||
}
|
||||
|
|
|
@ -58,6 +58,9 @@
|
|||
|
||||
#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause)
|
||||
|
||||
#ifndef yield
|
||||
#define yield() {}
|
||||
#endif
|
||||
|
||||
static void removeentry (Node *n) {
|
||||
lua_assert(ttisnil(gval(n)));
|
||||
|
@ -232,8 +235,10 @@ static void traverseclosure (global_State *g, Closure *cl) {
|
|||
int i;
|
||||
lua_assert(cl->l.nupvalues == cl->l.p->nups);
|
||||
markobject(g, cl->l.p);
|
||||
for (i=0; i<cl->l.nupvalues; i++) /* mark its upvalues */
|
||||
markobject(g, cl->l.upvals[i]);
|
||||
for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */
|
||||
if(cl->l.upvals[i])
|
||||
markobject(g, cl->l.upvals[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,6 +263,7 @@ static void traversestack (global_State *g, lua_State *l) {
|
|||
CallInfo *ci;
|
||||
markvalue(g, gt(l));
|
||||
lim = l->top;
|
||||
if(l->stack == NULL) return; /* no stack to traverse */
|
||||
for (ci = l->base_ci; ci <= l->ci; ci++) {
|
||||
lua_assert(ci->top <= l->stack_last);
|
||||
if (lim < ci->top) lim = ci->top;
|
||||
|
@ -266,7 +272,8 @@ static void traversestack (global_State *g, lua_State *l) {
|
|||
markvalue(g, o);
|
||||
for (; o <= lim; o++)
|
||||
setnilvalue(o);
|
||||
checkstacksizes(l, lim);
|
||||
if (!isfixedstack(l)) /* if stack size is fixed, can't resize it. */
|
||||
checkstacksizes(l, lim);
|
||||
}
|
||||
|
||||
|
||||
|
@ -419,8 +426,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
|
|||
else { /* must erase `curr' */
|
||||
lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT));
|
||||
*p = curr->gch.next;
|
||||
if (curr == g->rootgc) /* is the first element of the list? */
|
||||
g->rootgc = curr->gch.next; /* adjust first */
|
||||
freeobj(L, curr);
|
||||
}
|
||||
}
|
||||
|
@ -434,6 +439,8 @@ static void checkSizes (lua_State *L) {
|
|||
if (g->strt.nuse < cast(lu_int32, g->strt.size/4) &&
|
||||
g->strt.size > MINSTRTABSIZE*2)
|
||||
luaS_resize(L, g->strt.size/2); /* table is too big */
|
||||
/* it is not safe to re-size the buffer if it is in use. */
|
||||
if (luaZ_bufflen(&g->buff) > 0) return;
|
||||
/* check size of buffer */
|
||||
if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */
|
||||
size_t newsize = luaZ_sizebuffer(&g->buff) / 2;
|
||||
|
@ -552,6 +559,15 @@ static void atomic (lua_State *L) {
|
|||
g->estimate = g->totalbytes - udsize; /* first estimate */
|
||||
}
|
||||
|
||||
static void sweepstrstep (global_State *g, lua_State *L) {
|
||||
lu_mem old = g->totalbytes;
|
||||
sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
|
||||
if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */
|
||||
g->gcstate = GCSsweep; /* end sweep-string phase */
|
||||
lua_assert(old >= g->totalbytes);
|
||||
g->estimate -= old - g->totalbytes;
|
||||
}
|
||||
|
||||
|
||||
static l_mem singlestep (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
|
@ -570,12 +586,7 @@ static l_mem singlestep (lua_State *L) {
|
|||
}
|
||||
}
|
||||
case GCSsweepstring: {
|
||||
lu_mem old = g->totalbytes;
|
||||
sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
|
||||
if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */
|
||||
g->gcstate = GCSsweep; /* end sweep-string phase */
|
||||
lua_assert(old >= g->totalbytes);
|
||||
g->estimate -= old - g->totalbytes;
|
||||
sweepstrstep(g, L);
|
||||
return GCSWEEPCOST;
|
||||
}
|
||||
case GCSsweep: {
|
||||
|
@ -609,10 +620,14 @@ static l_mem singlestep (lua_State *L) {
|
|||
|
||||
void luaC_step (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
if(is_block_gc(L)) return;
|
||||
set_block_gc(L);
|
||||
l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul;
|
||||
if (lim == 0)
|
||||
lim = (MAX_LUMEM-1)/2; /* no limit */
|
||||
g->gcdept += g->totalbytes - g->GCthreshold;
|
||||
if (g->estimate > g->totalbytes)
|
||||
g->estimate = g->totalbytes;
|
||||
do {
|
||||
lim -= singlestep(L);
|
||||
if (g->gcstate == GCSpause)
|
||||
|
@ -629,11 +644,23 @@ void luaC_step (lua_State *L) {
|
|||
else {
|
||||
setthreshold(g);
|
||||
}
|
||||
unset_block_gc(L);
|
||||
}
|
||||
|
||||
|
||||
int luaC_sweepstrgc (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
if (g->gcstate == GCSsweepstring) {
|
||||
sweepstrstep(g, L);
|
||||
return (g->gcstate == GCSsweepstring) ? 1 : 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void luaC_fullgc (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
if(is_block_gc(L)) return;
|
||||
set_block_gc(L);
|
||||
if (g->gcstate <= GCSpropagate) {
|
||||
/* reset sweep marks to sweep all elements (returning them to white) */
|
||||
g->sweepstrgc = 0;
|
||||
|
@ -649,12 +676,15 @@ void luaC_fullgc (lua_State *L) {
|
|||
while (g->gcstate != GCSfinalize) {
|
||||
lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);
|
||||
singlestep(L);
|
||||
yield();
|
||||
}
|
||||
markroot(L);
|
||||
while (g->gcstate != GCSpause) {
|
||||
singlestep(L);
|
||||
yield();
|
||||
}
|
||||
setthreshold(g);
|
||||
unset_block_gc(L);
|
||||
}
|
||||
|
||||
|
||||
|
@ -682,6 +712,14 @@ void luaC_barrierback (lua_State *L, Table *t) {
|
|||
}
|
||||
|
||||
|
||||
void luaC_marknew (lua_State *L, GCObject *o) {
|
||||
global_State *g = G(L);
|
||||
o->gch.marked = luaC_white(g);
|
||||
if (g->gcstate == GCSpropagate)
|
||||
reallymarkobject(g, o); /* mark new objects as gray during propagate state. */
|
||||
}
|
||||
|
||||
|
||||
void luaC_link (lua_State *L, GCObject *o, lu_byte tt) {
|
||||
global_State *g = G(L);
|
||||
o->gch.next = g->rootgc;
|
||||
|
|
|
@ -37,12 +37,30 @@
|
|||
#define test2bits(x,b1,b2) testbits(x, (bit2mask(b1, b2)))
|
||||
|
||||
|
||||
/*
|
||||
** Possible Garbage Collector flags.
|
||||
** Layout for bit use in 'gsflags' field in global_State structure.
|
||||
** bit 0 - Protect GC from recursive calls.
|
||||
** bit 1 - Don't try to shrink string table if EGC was called during a string table resize.
|
||||
*/
|
||||
#define GCFlagsNone 0
|
||||
#define GCBlockGCBit 0
|
||||
#define GCResizingStringsBit 1
|
||||
|
||||
|
||||
#define is_block_gc(L) testbit(G(L)->gcflags, GCBlockGCBit)
|
||||
#define set_block_gc(L) l_setbit(G(L)->gcflags, GCBlockGCBit)
|
||||
#define unset_block_gc(L) resetbit(G(L)->gcflags, GCBlockGCBit)
|
||||
#define is_resizing_strings_gc(L) testbit(G(L)->gcflags, GCResizingStringsBit)
|
||||
#define set_resizing_strings_gc(L) l_setbit(G(L)->gcflags, GCResizingStringsBit)
|
||||
#define unset_resizing_strings_gc(L) resetbit(G(L)->gcflags, GCResizingStringsBit)
|
||||
|
||||
/*
|
||||
** Layout for bit use in `marked' field:
|
||||
** bit 0 - object is white (type 0)
|
||||
** bit 1 - object is white (type 1)
|
||||
** bit 2 - object is black
|
||||
** bit 3 - for thread: Don't resize thread's stack
|
||||
** bit 3 - for userdata: has been finalized
|
||||
** bit 3 - for tables: has weak keys
|
||||
** bit 4 - for tables: has weak values
|
||||
|
@ -54,6 +72,7 @@
|
|||
#define WHITE0BIT 0
|
||||
#define WHITE1BIT 1
|
||||
#define BLACKBIT 2
|
||||
#define FIXEDSTACKBIT 3
|
||||
#define FINALIZEDBIT 3
|
||||
#define KEYWEAKBIT 3
|
||||
#define VALUEWEAKBIT 4
|
||||
|
@ -76,6 +95,9 @@
|
|||
|
||||
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
|
||||
|
||||
#define isfixedstack(x) testbit((x)->marked, FIXEDSTACKBIT)
|
||||
#define fixedstack(x) l_setbit((x)->marked, FIXEDSTACKBIT)
|
||||
#define unfixedstack(x) resetbit((x)->marked, FIXEDSTACKBIT)
|
||||
|
||||
#define luaC_checkGC(L) { \
|
||||
condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \
|
||||
|
@ -101,6 +123,8 @@ LUAI_FUNC void luaC_callGCTM (lua_State *L);
|
|||
LUAI_FUNC void luaC_freeall (lua_State *L);
|
||||
LUAI_FUNC void luaC_step (lua_State *L);
|
||||
LUAI_FUNC void luaC_fullgc (lua_State *L);
|
||||
LUAI_FUNC int luaC_sweepstrgc (lua_State *L);
|
||||
LUAI_FUNC void luaC_marknew (lua_State *L, GCObject *o);
|
||||
LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt);
|
||||
LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv);
|
||||
LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v);
|
||||
|
|
|
@ -117,42 +117,48 @@ typedef struct lua_TValue {
|
|||
#define setnilvalue(obj) ((obj)->tt=LUA_TNIL)
|
||||
|
||||
#define setnvalue(obj,x) \
|
||||
{ TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; }
|
||||
{ lua_Number i_x = (x); TValue *i_o=(obj); i_o->value.n=i_x; i_o->tt=LUA_TNUMBER; }
|
||||
|
||||
#define setpvalue(obj,x) \
|
||||
{ TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; }
|
||||
{ void *i_x = (x); TValue *i_o=(obj); i_o->value.p=i_x; i_o->tt=LUA_TLIGHTUSERDATA; }
|
||||
|
||||
#define setbvalue(obj,x) \
|
||||
{ TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; }
|
||||
{ int i_x = (x); TValue *i_o=(obj); i_o->value.b=i_x; i_o->tt=LUA_TBOOLEAN; }
|
||||
|
||||
#define setsvalue(L,obj,x) \
|
||||
{ TValue *i_o=(obj); \
|
||||
i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \
|
||||
{ GCObject *i_x = cast(GCObject *, (x)); \
|
||||
TValue *i_o=(obj); \
|
||||
i_o->value.gc=i_x; i_o->tt=LUA_TSTRING; \
|
||||
checkliveness(G(L),i_o); }
|
||||
|
||||
#define setuvalue(L,obj,x) \
|
||||
{ TValue *i_o=(obj); \
|
||||
i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \
|
||||
{ GCObject *i_x = cast(GCObject *, (x)); \
|
||||
TValue *i_o=(obj); \
|
||||
i_o->value.gc=i_x; i_o->tt=LUA_TUSERDATA; \
|
||||
checkliveness(G(L),i_o); }
|
||||
|
||||
#define setthvalue(L,obj,x) \
|
||||
{ TValue *i_o=(obj); \
|
||||
i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \
|
||||
{ GCObject *i_x = cast(GCObject *, (x)); \
|
||||
TValue *i_o=(obj); \
|
||||
i_o->value.gc=i_x; i_o->tt=LUA_TTHREAD; \
|
||||
checkliveness(G(L),i_o); }
|
||||
|
||||
#define setclvalue(L,obj,x) \
|
||||
{ TValue *i_o=(obj); \
|
||||
i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \
|
||||
{ GCObject *i_x = cast(GCObject *, (x)); \
|
||||
TValue *i_o=(obj); \
|
||||
i_o->value.gc=i_x; i_o->tt=LUA_TFUNCTION; \
|
||||
checkliveness(G(L),i_o); }
|
||||
|
||||
#define sethvalue(L,obj,x) \
|
||||
{ TValue *i_o=(obj); \
|
||||
i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \
|
||||
{ GCObject *i_x = cast(GCObject *, (x)); \
|
||||
TValue *i_o=(obj); \
|
||||
i_o->value.gc=i_x; i_o->tt=LUA_TTABLE; \
|
||||
checkliveness(G(L),i_o); }
|
||||
|
||||
#define setptvalue(L,obj,x) \
|
||||
{ TValue *i_o=(obj); \
|
||||
i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \
|
||||
{ GCObject *i_x = cast(GCObject *, (x)); \
|
||||
TValue *i_o=(obj); \
|
||||
i_o->value.gc=i_x; i_o->tt=LUA_TPROTO; \
|
||||
checkliveness(G(L),i_o); }
|
||||
|
||||
|
||||
|
|
|
@ -383,14 +383,18 @@ static void close_func (LexState *ls) {
|
|||
Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) {
|
||||
struct LexState lexstate;
|
||||
struct FuncState funcstate;
|
||||
TString *tname = luaS_new(L, name);
|
||||
setsvalue2s(L, L->top, tname); /* protect name */
|
||||
incr_top(L);
|
||||
lexstate.buff = buff;
|
||||
luaX_setinput(L, &lexstate, z, luaS_new(L, name));
|
||||
luaX_setinput(L, &lexstate, z, tname);
|
||||
open_func(&lexstate, &funcstate);
|
||||
funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */
|
||||
luaX_next(&lexstate); /* read first token */
|
||||
chunk(&lexstate);
|
||||
check(&lexstate, TK_EOS);
|
||||
close_func(&lexstate);
|
||||
L->top--; /* remove 'name' from stack */
|
||||
lua_assert(funcstate.prev == NULL);
|
||||
lua_assert(funcstate.f->nups == 0);
|
||||
lua_assert(lexstate.fs == NULL);
|
||||
|
|
|
@ -119,6 +119,8 @@ static void close_state (lua_State *L) {
|
|||
lua_State *luaE_newthread (lua_State *L) {
|
||||
lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State)));
|
||||
luaC_link(L, obj2gco(L1), LUA_TTHREAD);
|
||||
setthvalue(L, L->top, L1); /* put thread on stack */
|
||||
incr_top(L);
|
||||
preinit_state(L1, G(L));
|
||||
stack_init(L1, L); /* init stack */
|
||||
setobj2n(L, gt(L1), gt(L)); /* share table of globals */
|
||||
|
@ -126,7 +128,8 @@ lua_State *luaE_newthread (lua_State *L) {
|
|||
L1->basehookcount = L->basehookcount;
|
||||
L1->hook = L->hook;
|
||||
resethookcount(L1);
|
||||
lua_assert(iswhite(obj2gco(L1)));
|
||||
lua_assert(!isdead(G(L), obj2gco(L1)));
|
||||
L->top--; /* remove thread from stack */
|
||||
return L1;
|
||||
}
|
||||
|
||||
|
@ -160,6 +163,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
|||
g->uvhead.u.l.prev = &g->uvhead;
|
||||
g->uvhead.u.l.next = &g->uvhead;
|
||||
g->GCthreshold = 0; /* mark it as unfinished state */
|
||||
g->estimate = 0;
|
||||
g->strt.size = 0;
|
||||
g->strt.nuse = 0;
|
||||
g->strt.hash = NULL;
|
||||
|
@ -167,6 +171,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
|||
luaZ_initbuffer(L, &g->buff);
|
||||
g->panic = NULL;
|
||||
g->gcstate = GCSpause;
|
||||
g->gcflags = GCFlagsNone;
|
||||
g->rootgc = obj2gco(L);
|
||||
g->sweepstrgc = 0;
|
||||
g->sweepgc = &g->rootgc;
|
||||
|
|
|
@ -71,6 +71,7 @@ typedef struct global_State {
|
|||
void *ud; /* auxiliary data to `frealloc' */
|
||||
lu_byte currentwhite;
|
||||
lu_byte gcstate; /* state of garbage collector */
|
||||
lu_byte gcflags; /* flags for the garbage collector */
|
||||
int sweepstrgc; /* position of sweep in `strt' */
|
||||
GCObject *rootgc; /* list of all collectable objects */
|
||||
GCObject **sweepgc; /* position of sweep in `rootgc' */
|
||||
|
|
|
@ -22,30 +22,34 @@
|
|||
|
||||
|
||||
void luaS_resize (lua_State *L, int newsize) {
|
||||
GCObject **newhash;
|
||||
stringtable *tb;
|
||||
int i;
|
||||
if (G(L)->gcstate == GCSsweepstring)
|
||||
return; /* cannot resize during GC traverse */
|
||||
newhash = luaM_newvector(L, newsize, GCObject *);
|
||||
tb = &G(L)->strt;
|
||||
for (i=0; i<newsize; i++) newhash[i] = NULL;
|
||||
if (luaC_sweepstrgc(L) || newsize == tb->size || is_resizing_strings_gc(L))
|
||||
return; /* cannot resize during GC traverse or doesn't need to be resized */
|
||||
set_resizing_strings_gc(L);
|
||||
if (newsize > tb->size) {
|
||||
luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *);
|
||||
for (i=tb->size; i<newsize; i++) tb->hash[i] = NULL;
|
||||
}
|
||||
/* rehash */
|
||||
for (i=0; i<tb->size; i++) {
|
||||
GCObject *p = tb->hash[i];
|
||||
tb->hash[i] = NULL;
|
||||
while (p) { /* for each node in the list */
|
||||
GCObject *next = p->gch.next; /* save next */
|
||||
unsigned int h = gco2ts(p)->hash;
|
||||
int h1 = lmod(h, newsize); /* new position */
|
||||
lua_assert(cast_int(h%newsize) == lmod(h, newsize));
|
||||
p->gch.next = newhash[h1]; /* chain it */
|
||||
newhash[h1] = p;
|
||||
p->gch.next = tb->hash[h1]; /* chain it */
|
||||
tb->hash[h1] = p;
|
||||
p = next;
|
||||
}
|
||||
}
|
||||
luaM_freearray(L, tb->hash, tb->size, TString *);
|
||||
if (newsize < tb->size)
|
||||
luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *);
|
||||
tb->size = newsize;
|
||||
tb->hash = newhash;
|
||||
unset_resizing_strings_gc(L);
|
||||
}
|
||||
|
||||
|
||||
|
@ -55,6 +59,9 @@ static TString *newlstr (lua_State *L, const char *str, size_t l,
|
|||
stringtable *tb;
|
||||
if (l > ((MAX_SIZET - sizeof(TString))/sizeof(char)) - sizeof(""))
|
||||
luaM_toobig(L);
|
||||
tb = &G(L)->strt;
|
||||
if ((tb->nuse + 1) > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
|
||||
luaS_resize(L, tb->size*2); /* too crowded */
|
||||
ts = cast(TString *, luaM_malloc(L, sizetstring(type, l)));
|
||||
ts->tsv.len = l;
|
||||
ts->tsv.hash = h;
|
||||
|
@ -70,13 +77,10 @@ static TString *newlstr (lua_State *L, const char *str, size_t l,
|
|||
memcpy(ts+1, str, l*sizeof(char));
|
||||
((char *)(ts+1))[l] = '\0'; /* ending 0 */
|
||||
}
|
||||
tb = &G(L)->strt;
|
||||
h = lmod(h, tb->size);
|
||||
ts->tsv.next = tb->hash[h]; /* chain new entry */
|
||||
tb->hash[h] = obj2gco(ts);
|
||||
tb->nuse++;
|
||||
if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
|
||||
luaS_resize(L, tb->size*2); /* too crowded */
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
|
|
@ -358,6 +358,8 @@ static void rehash (lua_State *L, Table *t, const TValue *ek) {
|
|||
Table *luaH_new (lua_State *L, int narray, int nhash) {
|
||||
Table *t = luaM_new(L, Table);
|
||||
luaC_link(L, obj2gco(t), LUA_TTABLE);
|
||||
sethvalue2s(L, L->top, t); /* put table on stack */
|
||||
incr_top(L);
|
||||
t->metatable = NULL;
|
||||
t->flags = cast_byte(~0);
|
||||
/* temporary values (kept only if some malloc fails) */
|
||||
|
@ -367,6 +369,7 @@ Table *luaH_new (lua_State *L, int narray, int nhash) {
|
|||
t->node = cast(Node *, dummynode);
|
||||
setarrayvector(L, t, narray);
|
||||
setnodevector(L, t, nhash);
|
||||
L->top--; /* remove table from stack */
|
||||
return t;
|
||||
}
|
||||
|
||||
|
|
18
apps/plugins/lua/lua_user.c
Normal file
18
apps/plugins/lua/lua_user.c
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include "plugin.h"
|
||||
#include "lstate.h"
|
||||
#include LUA_USER_H
|
||||
|
||||
/* lua Out Of Memory */
|
||||
static struct lua_OOM l_oom = {NULL, 0};
|
||||
|
||||
int set_lua_OOM(lua_State * L)
|
||||
{
|
||||
l_oom.L = L;
|
||||
l_oom.count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct lua_OOM *get_lua_OOM(void)
|
||||
{
|
||||
return &l_oom;
|
||||
}
|
14
apps/plugins/lua/lua_user.h
Normal file
14
apps/plugins/lua/lua_user.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef _LUA_USER_H_
|
||||
#define _LUA_USER_H_
|
||||
|
||||
#define LUA_OOM(L) set_lua_OOM(L)
|
||||
|
||||
struct lua_OOM {
|
||||
lua_State * L;
|
||||
int count;
|
||||
};
|
||||
|
||||
int set_lua_OOM(lua_State * L);
|
||||
|
||||
struct lua_OOM* get_lua_OOM(void);
|
||||
#endif
|
|
@ -810,7 +810,13 @@ extern long rb_pow(long, long);
|
|||
/*Rocklua functions*/
|
||||
#include "rockconf.h"
|
||||
|
||||
/* heap */
|
||||
#undef LUAI_GCPAUSE /*200*/
|
||||
#define LUAI_GCPAUSE 125
|
||||
#define MINSTRTABSIZE 512 /*32*/
|
||||
|
||||
/*else*/
|
||||
#define LUA_USER_H "lua_user.h"
|
||||
#define LUA_DISABLE_BYTECODE
|
||||
|
||||
#endif
|
||||
|
|
|
@ -49,9 +49,10 @@ int luaV_tostring (lua_State *L, StkId obj) {
|
|||
return 0;
|
||||
else {
|
||||
char s[LUAI_MAXNUMBER2STR];
|
||||
ptrdiff_t objr = savestack(L, obj);
|
||||
lua_Number n = nvalue(obj);
|
||||
lua_number2str(s, n);
|
||||
setsvalue2s(L, obj, luaS_new(L, s));
|
||||
setsvalue2s(L, restorestack(L, objr), luaS_new(L, s));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -134,6 +135,9 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
|
|||
void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
|
||||
int loop;
|
||||
TValue temp;
|
||||
setnilvalue(L->top);
|
||||
L->top++;
|
||||
fixedstack(L);
|
||||
for (loop = 0; loop < MAXTAGLOOP; loop++) {
|
||||
const TValue *tm;
|
||||
if (ttistable(t)) { /* `t' is a table? */
|
||||
|
@ -141,6 +145,8 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
|
|||
TValue *oldval = luaH_set(L, h, key); /* do a primitive set */
|
||||
if (!ttisnil(oldval) || /* result is no nil? */
|
||||
(tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */
|
||||
L->top--;
|
||||
unfixedstack(L);
|
||||
setobj2t(L, oldval, val);
|
||||
h->flags = 0;
|
||||
luaC_barriert(L, h, val);
|
||||
|
@ -151,12 +157,15 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
|
|||
else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))
|
||||
luaG_typeerror(L, t, "index");
|
||||
if (ttisfunction(tm)) {
|
||||
L->top--;
|
||||
unfixedstack(L);
|
||||
callTM(L, tm, t, key, val);
|
||||
return;
|
||||
}
|
||||
/* else repeat with `tm' */
|
||||
setobj(L, &temp, tm); /* avoid pointing inside table (may rehash) */
|
||||
t = &temp;
|
||||
setobj2s(L, L->top-1, t); /* need to protect value from EGC. */
|
||||
}
|
||||
luaG_runerror(L, "loop in settable");
|
||||
}
|
||||
|
@ -284,8 +293,11 @@ void luaV_concat (lua_State *L, int total, int last) {
|
|||
StkId top = L->base + last + 1;
|
||||
int n = 2; /* number of elements handled in this pass (at least 2) */
|
||||
if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) {
|
||||
if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT))
|
||||
if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) {
|
||||
/* restore 'top' pointer, since stack might have been reallocted */
|
||||
top = L->base + last + 1;
|
||||
luaG_concaterror(L, top-2, top-1);
|
||||
}
|
||||
} else if (tsvalue(top-1)->len == 0) /* second op is empty? */
|
||||
(void)tostring(L, top - 2); /* result is first op (as string) */
|
||||
else {
|
||||
|
@ -293,12 +305,14 @@ void luaV_concat (lua_State *L, int total, int last) {
|
|||
size_t tl = tsvalue(top-1)->len;
|
||||
char *buffer;
|
||||
int i;
|
||||
fixedstack(L);
|
||||
/* collect total length */
|
||||
for (n = 1; n < total && tostring(L, top-n-1); n++) {
|
||||
size_t l = tsvalue(top-n-1)->len;
|
||||
if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow");
|
||||
tl += l;
|
||||
}
|
||||
G(L)->buff.n = tl;
|
||||
buffer = luaZ_openspace(L, &G(L)->buff, tl);
|
||||
tl = 0;
|
||||
for (i=n; i>0; i--) { /* concat all strings */
|
||||
|
@ -307,6 +321,8 @@ void luaV_concat (lua_State *L, int total, int last) {
|
|||
tl += l;
|
||||
}
|
||||
setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl));
|
||||
luaZ_resetbuffer(&G(L)->buff);
|
||||
unfixedstack(L);
|
||||
}
|
||||
total -= n-1; /* got `n' strings to create 1 new */
|
||||
last -= n-1;
|
||||
|
@ -332,8 +348,13 @@ static void Arith (lua_State *L, StkId ra, const TValue *rb,
|
|||
default: lua_assert(0); break;
|
||||
}
|
||||
}
|
||||
else if (!call_binTM(L, rb, rc, ra, op))
|
||||
luaG_aritherror(L, rb, rc);
|
||||
else {
|
||||
ptrdiff_t br = savestack(L, rb);
|
||||
ptrdiff_t cr = savestack(L, rc);
|
||||
if (!call_binTM(L, rb, rc, ra, op)) {
|
||||
luaG_aritherror(L, restorestack(L, br), restorestack(L, cr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -461,7 +482,9 @@ void luaV_execute (lua_State *L, int nexeccalls) {
|
|||
case OP_NEWTABLE: {
|
||||
int b = GETARG_B(i);
|
||||
int c = GETARG_C(i);
|
||||
sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c)));
|
||||
Table *h;
|
||||
Protect(h = luaH_new(L, luaO_fb2int(b), luaO_fb2int(c)));
|
||||
sethvalue(L, RA(i), h);
|
||||
Protect(luaC_checkGC(L));
|
||||
continue;
|
||||
}
|
||||
|
@ -547,9 +570,10 @@ void luaV_execute (lua_State *L, int nexeccalls) {
|
|||
break;
|
||||
}
|
||||
default: { /* try metamethod */
|
||||
ptrdiff_t br = savestack(L, rb);
|
||||
Protect(
|
||||
if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN))
|
||||
luaG_typeerror(L, rb, "get length of");
|
||||
luaG_typeerror(L, restorestack(L, br), "get length of");
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -723,6 +747,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
|
|||
int c = GETARG_C(i);
|
||||
int last;
|
||||
Table *h;
|
||||
fixedstack(L);
|
||||
if (n == 0) {
|
||||
n = cast_int(L->top - ra) - 1;
|
||||
L->top = L->ci->top;
|
||||
|
@ -738,6 +763,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
|
|||
setobj2t(L, luaH_setnum(L, h, last--), val);
|
||||
luaC_barriert(L, h, val);
|
||||
}
|
||||
unfixedstack(L);
|
||||
continue;
|
||||
}
|
||||
case OP_CLOSE: {
|
||||
|
@ -750,7 +776,9 @@ void luaV_execute (lua_State *L, int nexeccalls) {
|
|||
int nup, j;
|
||||
p = cl->p->p[GETARG_Bx(i)];
|
||||
nup = p->nups;
|
||||
fixedstack(L);
|
||||
ncl = luaF_newLclosure(L, nup, cl->env);
|
||||
setclvalue(L, ra, ncl);
|
||||
ncl->l.p = p;
|
||||
for (j=0; j<nup; j++, pc++) {
|
||||
if (GET_OPCODE(*pc) == OP_GETUPVAL)
|
||||
|
@ -760,7 +788,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
|
|||
ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc));
|
||||
}
|
||||
}
|
||||
setclvalue(L, ra, ncl);
|
||||
unfixedstack(L);
|
||||
Protect(luaC_checkGC(L));
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ typedef struct Mbuffer {
|
|||
size_t buffsize;
|
||||
} Mbuffer;
|
||||
|
||||
#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0)
|
||||
#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->n = 0, (buff)->buffsize = 0)
|
||||
|
||||
#define luaZ_buffer(buff) ((buff)->buffer)
|
||||
#define luaZ_sizebuffer(buff) ((buff)->buffsize)
|
||||
|
|
|
@ -63,6 +63,7 @@ long lpow(long x, long y);
|
|||
#define strcmp rb->strcmp
|
||||
#define strcpy rb->strcpy
|
||||
#define strlen rb->strlen
|
||||
#define yield() rb->yield()
|
||||
|
||||
#endif /* _ROCKCONF_H_ */
|
||||
|
||||
|
|
|
@ -304,7 +304,7 @@ RB_WRAP(playlist)
|
|||
break;
|
||||
}
|
||||
|
||||
rb->yield();
|
||||
yield();
|
||||
lua_pushinteger(L, result);
|
||||
return 1;
|
||||
}
|
||||
|
@ -382,7 +382,7 @@ RB_WRAP(audio)
|
|||
return 1;
|
||||
}
|
||||
|
||||
rb->yield();
|
||||
yield();
|
||||
lua_pushinteger(L, status); /* return previous (or current) audio status */
|
||||
return 1;
|
||||
}
|
||||
|
@ -502,7 +502,7 @@ RB_WRAP(pcm)
|
|||
break;
|
||||
}
|
||||
|
||||
rb->yield();
|
||||
yield();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "plugin.h"
|
||||
#include <tlsf.h>
|
||||
#include "lua.h"
|
||||
|
||||
void *get_new_area(size_t *size)
|
||||
{
|
||||
|
@ -36,7 +37,8 @@ void *get_new_area(size_t *size)
|
|||
return pluginbuf_ptr;
|
||||
}
|
||||
|
||||
if (audiobuf_ptr == NULL)
|
||||
/* only grab the next area if lua already tried + failed to garbage collect*/
|
||||
if (audiobuf_ptr == NULL && (get_lua_OOM())->count > 0)
|
||||
{
|
||||
/* grab audiobuffer */
|
||||
audiobuf_ptr = rb->plugin_get_audio_buffer(size);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue