system-controller: mark masks DYNAMIC, add funcbridge gettop/settop wrappers.
authorKrisztian Litkey <kli@iki.fi>
Wed, 22 Oct 2014 17:08:36 +0000 (20:08 +0300)
committerKrisztian Litkey <krisztian.litkey@intel.com>
Thu, 8 Jan 2015 16:37:18 +0000 (18:37 +0200)
commit3354ba1e55cad6f66aeaf891cecced653724a624
tree60abdac557656ed8386417d3f2cff41684698e09
parentb2222172f0fa30cda0417da6b5e52da55ea22307
system-controller: mark masks DYNAMIC, add funcbridge gettop/settop wrappers.

Mark Lua *_mask classes (window_mask, layer_mask, input_mask,
output_mask, code_mask) as dynamic.

Finally (I think) I understood where the mysterious and seemingly
quasi-randomly occuring dynamic object leaks were stemming from.
It is caused by functionbridge invocations from a peculiar type
of context (see below). Sadly, in its current form, there is no
easy automatic way to mitigate the problem, or at least I haven't
managed to come up with one yet, to protect people from shooting
themselves in the foot with other instances of this bug. For the
time being folks will need to make sure they do the right things,
which inherently and eventually tends to be error prone...

Anyway, to make a long story short, the leaks were stemming from
calls to mrp_func{bridge,array}_call_from_c from contexts which
were not triggered, directly or indirectly, from Lua from a control
flow perspective. IOW, if there was a call to one of the *from_c
bridge-invoking and on the return path we never ended up returning
to the Lua interpreter (which would have then had been the one
having made the call out to C/us) then all the objects that were
pushed on the Lua stack before the call to the *from_c function
were simply left on the Lua stack forever.

These were not genuine leaks in the sense that the object still
were reachable on the Lua stack, it was just that there was never
a return to Lua or to anybode else to clean up the stack for us
so the object were never ever reclaimed.

The fix for now is to make sure that all invocations to bridges
strictly follow the pattern below, which makes sure that the Lua
stack top is saved before anything is pushed there and restored
before returning from the function:

  ...
  int top;

  error checks and potential bailout();

  top = lua_gettop(L);

  /* from here on no direct bailout, only return via 'goto out;' */
  preparation argument gathering and creation();

  fill funcbridge argument array();
  invoke funcbridge with one of the call_from_c calls();
  free returned values if needed();

  out;
  lua_settop(L, top);

  return status;

Now there are a couple of ways how this could be made safer / less
error prone, but AFAICT all of those require slight changes to the
funcbridge implementation and/or signature.

One, and a rather trivial, way would be to let people pass in the
stack top to be restored to the *_call_from_c functions and let
these make sure that the stack is restored properly before they
return. This would still require the caller to correctly determine
the right stack top, but it would save him from the trouble of
having to remember to correctly restore the stack on all return
pathes.

Another alternative would be to change the funcbridge signature
and allow the called to indicate there how many items were pushed
to the stack just for the funcbridge call (eg. the last item being
the number of items to clean up), or to have separate signature
markers for items that have been specifically allocated for the
funcbridge call. So for instance O would indicate a Lua object
while D would indicate a Lua object that needs to be cleaned from
the stack before returning. Neither of these would be fully fail-
safe though as the caller still needs to provide the right info
one way or another...

Change-Id: If002c8bb4936bbc8e2677dfb9cdc4a0a640c78d6
src/plugins/system-controller/plugin-system-controller.c
src/plugins/system-controller/resource-manager/scripting-resource-manager.c
src/plugins/system-controller/wayland/scripting-code.c
src/plugins/system-controller/wayland/scripting-input-manager.c
src/plugins/system-controller/wayland/scripting-input.c
src/plugins/system-controller/wayland/scripting-layer.c
src/plugins/system-controller/wayland/scripting-output.c
src/plugins/system-controller/wayland/scripting-window-manager.c
src/plugins/system-controller/wayland/scripting-window.c