Friday, August 19, 2011

Brainstorm: ScopedObject and Pinned

ScopedObject and Pinned are two features of Tart which are on my long-term TODO list.

ScopedObject is an interface that is used in conjunction with the 'with' statement. It has two methods: enterScope() and exitScope(). You'd use it like this:

with mutex.locked() {
  // Mutex is locked while in this block, will be unlocked on exit.
}

with file = FileReader.open("foo.txt") {
  // File will be automatically closed on exit.
}

tart.gc.Pinned is a helper class for creating 'pinned' objects - that is, objects that are fixed at a given address and cannot be moved around by the garbage collector. Pinned objects aren't something that normal users of Tart would ever deal with - they are mainly useful for people who are implementing i/o libraries.

Here's a typical example of how pinning would be used:

def writeData(data:ubyte[]) -> int {
  with pinnedData = GC.pin(buffer) {
    with GC.unlocked() {
      return lowLevelStream.writeData(pinnedData.get());
    }
  }
}

Here's what this is doing: GC.pin() takes an object reference and returns a 'pinned' version of that object. Depending on what memory region the object lives in, the return value may be the original object with the 'pinned' bit set in the object header, or it may be a shallow clone of the object. Cloning generally will occur if the original object lives in a compacting collection space - the clone will be put into a different space where object addresses are stable.

Note that the writeData() function will throw an exception if the buffer isn't pinned.

At the end of the outer with statement, the pinned object is disposed. In some cases, the data in the pinned object may get copied back to the original buffer. (Probably 'pin' will take some flags indicating whether the clone will be read/write or just read only.)

The inner 'with' statement handles interactions between the garbage collector and blocking i/o. The 'unlocked' method tells the garbage collector that it's OK for collections to take place while we are waiting for the i/o to finish. At the end of the block, the garbage collector is locked again (meaning that collections can only take place when we tell it that it is safe to do so.) Within the 'unlocked' state, objects may move around in memory - which is why we had to make sure that the input buffer was pinned.

No comments:

Post a Comment