lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


I should perhaps have made the implementation a bit clearer: we only use Lua
in a very light sense, and most of the data storage/management is done in C
rather than in Lua. We store the references in a managed array of pending
function calls, limiting them to more than 10 outstanding at once. The
storage code is all properly checked and the data is sensible (since there
are never more than 2 outstanding pending functions at once). 

But the problem isn't occurring at the C level, it is the lua_*ref*
functions that are returning odd data. The grepped output from from my run
looks like:

lua_ref : 3
lua_getref : 3
lua_ref : 3
lua_unref : 3
lua_getref : 3

So at each call to the lua functions I output the reference that was
used/returned. The reference is not -1, so I'm not referencing nil, and
there are no other calls to luaL_ref or luaL_unref (from placing breakpoints
in the lua source). Tracing through the luaL_ref function takes the exact
same path both times, and the calls inside all return the same data both
calls. Could the lua_getref call somehow be unreferencing the data
indirectly?

As the post below shows, I can probably work around it by unreferencing the
first function before calling it, but it is awkward because my unref wrapper
function is seperate from my call wrapper function - i.e. I have to put the
unref code inside the call function so the unref occurs after the getref. At
the moment they are nice and cleanly seperate - I can call several times
without having to unref if I want to.

-----Original Message-----
From: RLake@oxfam.org.pe [mailto:RLake@oxfam.org.pe]
Sent: 23 October 2003 19:26
To: Chris.chapman@visentertainment.com
Subject: RE: Lua on the PlayStation2


Hi, Chris.

> But I'm tracking down a sneaky bug that was introduced with the change. 
We
> implement a 'pending-function' interface to our scripts which allows us 
to
> store a function with some parameters for calling at a later time (after 
the
> script which stored it has finished and returned control to the game
> engine). We implemented this in Lua 4.0.1 by calling lua_ref(L, true) to
> pull a reference to the function and lock it so it doesn't accidentally 
get
> garbage collected. To call the function, the game engine uses the 
reference
> by calling lua_getref, calls the pending function, and then calls 
lua_unref
> to clean up.

Maybe I'm being dense here, but I don't understand the details of your
implementation. Where does the reference get stored? Presumably in some
game engine data structure, or possibly in a per-script data structure?
How does the game engine deal with the case where there is already
a stored pending-reference, and a script tries to install another one?
Perhaps you have some bug there...

In any event, you seem to have the sequence:

  lua_getref(L, pref);
  lua_call(L, 0, 0);  // or pcall with arguments and results, maybe
  lua_unref(L, pref);

However, you could just as well do:

  lua_getref(L, pref);
  lua_unref(L, pref);
  lua_call(L, 0, 0);  // or pcall with arguments and results, maybe

After the call to getref, the function object is on the stack and
will not be garbage collectable until it is popped from the stack,
and that certainly won't happen while the function is being called.
So that might simplify handling of multiple pending-references.

There is nothing magical about the Lua registry. You could store
your pending functions in any Lua table, using any mechanism you
liked. Normally, it is pretty easy to do a queue in Lua, but if
lua_Numbers are single-precision in your implementation, you have
to be careful to not overflow the index.

-- This works fine with doubles; it can handle about 2^52 inserts
-- I'm assuming you won't have a lot of them, so I didn't muck
-- about with metamethods

function Queue(...)
  local low, high = 1, arg.n + 1

  function arg.put(obj)
    arg[high], high = obj, high + 1
    return arg
  end

  function arg.get()
    if low < high then
      local rv
      low, rv, arg[low] = low + 1, arg[low], nil
      return rv
    end
  end

  return arg
end

-- Example: flat traverse of a directory table; assume that
-- the keys are all strings.

-- I wrote it in functional style to demonstrate the use of
-- pending functions.

function dirlist(t, name)
  local done, workq = {}
  local function traverse(prefix, t)
    done[t] = true
    io.write("\n", prefix, ":")
    for k, v in t do
      io.write("\t", k)
      if type(v) == "table" then
        io.write "/"
        if done[v] then
          io.write "*"
         else
          local pfx, vv = prefix.."/"..k, v
          workq.put(function() traverse(pfx, vv) end)
        end
      end
    end
    io.write "\n"
  end
  workq = Queue(function() traverse(name or "", t) end)

  for fn in workq.get do fn() end
end

dirlist(getfenv(), ".")