node-capnp icon indicating copy to clipboard operation
node-capnp copied to clipboard

close() on pipeline capability does not cause remote object to be immediately dropped

Open dwrensha opened this issue 7 years ago • 1 comments

Similar to #4.

# test.capnp
@0x8314444a113b636e;

interface Grault {}

interface Foo {
  bar @0 () -> ();
  baz @1 () -> (grault : Grault);
}
// test-server.c++
#include "test.capnp.h"
#include <capnp/ez-rpc.h>
#include <iostream>

class GraultImpl final: public Grault::Server {
public:
  ~GraultImpl() {
    std::cout << "Destroying a GraultImpl\n";
  }
};

class FooImpl final: public Foo::Server {
public:
  kj::Promise<void> baz(BazContext context) override {
    std::cout << "inside of baz\n";
    auto results = context.getResults();
    results.setGrault(kj::heap<GraultImpl>());
    return kj::READY_NOW;
  }
};

int main(int argc, const char* argv[]) {
  capnp::EzRpcServer server(kj::heap<FooImpl>(), "127.0.0.1:1234");

  auto& waitScope = server.getWaitScope();
  kj::NEVER_DONE.wait(waitScope);
}
// test.js
Capnp = require('capnp');
Foo = Capnp.import('test.capnp').Foo;

const conn = Capnp.connect("127.0.0.1:1234");
const cap = conn.restore(null, Foo);

const grault =  cap.baz().grault;
grault.close();
console.log("called close()");

If I run test-server in one terminal and node test.js in another, I expect to immediately see "Destroying a GraultImpl` in the first terminal output. Instead, that does not get printed until I ctrl-c the javascript program.

The problem is observable in Sandstorm's proxy.js, which keeps a pipeline cap of newSession().session and calls close() on it when the proxy closes. @mrdomino noticed that this does not actually cause the websession object in the grain to be dropped immediately.

dwrensha avatar Sep 01 '16 16:09 dwrensha

It does appear, however, that the remote object does eventually get dropped due to garbage collection. If I run the following client (with node --expose-gc), then the GraultImpl does get dropped right away:

Capnp = require('capnp');
Foo = Capnp.import('test.capnp').Foo;

const conn = Capnp.connect("127.0.0.1:1234");
{
  const cap = conn.restore(null, Foo);
  const grault =  cap.baz().grault;
  grault.close();
  console.log("closed");
}

setTimeout(() => {
  const conn1 = conn; // prevent segfault
  console.log("garbage collecting...");
  global.gc();
  console.log("gc'ed");
}, 200);

dwrensha avatar Sep 01 '16 16:09 dwrensha