Index: third_party/mojo/src/mojo/public/go/system/handle.go |
diff --git a/third_party/mojo/src/mojo/public/go/system/handle.go b/third_party/mojo/src/mojo/public/go/system/handle.go |
index 189c8dd15c030f3ec287cd9e331052135a61713b..d8d66dba4b30c2f34557c4b6c70486ff4f7ebc49 100644 |
--- a/third_party/mojo/src/mojo/public/go/system/handle.go |
+++ b/third_party/mojo/src/mojo/public/go/system/handle.go |
@@ -4,9 +4,10 @@ |
package system |
-//#include "c_allocators.h" |
-//#include "mojo/public/c/system/core.h" |
-import "C" |
+import ( |
+ "log" |
+ "runtime" |
+) |
// Handle is a generic handle for mojo objects. |
type Handle interface { |
@@ -60,6 +61,30 @@ type UntypedHandle interface { |
ToSharedBufferHandle() SharedBufferHandle |
} |
+// finalizeHandle closes handles that becomes unreachable in runtime. |
+// We want to make sure that every mojo handle is closed, so we set this |
+// finalizer function on every handle object we create. If a handle object |
+// becomes invalidated (because the handle was closed or the underlying mojo |
+// handle has been passed to another handle object), we remove the finalizer. |
+// |
+// The finalizing mechanism works tricky: runtime.SetFinalizer can be called on |
+// an object allocated by calling new or by taking the address of a composite |
+// literal, so we can't set a finalizer on an embedded struct if the embedded |
+// struct has a non-zero offset related to the outmost struct. |
+// |
+// Type structure of handles is the following: there is a struct baseHandle, |
+// which serves as a "base class" for all the typed handles (i.e. sharedBuffer, |
+// untypedHandleImpl, dataPipeProducer, dataPipeConsumer and messagePipe). We |
+// express it by struct embedding. When we operate with handles, we create typed |
+// handles and set finalizers on them, while to invalidate a handle and remove |
+// finalizer we call methods on the embedded baseHandle struct. So in order for |
+// finalizers to work correct we need to make sure that baseHandle is the first |
+// component of typed handles. |
+func finalizeHandle(h Handle) { |
+ log.Println("Handle was not closed.") |
+ h.Close() |
+} |
+ |
type baseHandle struct { |
core *coreImpl |
mojoHandle MojoHandle |
@@ -67,15 +92,16 @@ type baseHandle struct { |
func (h *baseHandle) invalidate() { |
h.mojoHandle = MOJO_HANDLE_INVALID |
+ runtime.SetFinalizer(h, nil) |
} |
func (h *baseHandle) Close() MojoResult { |
- h.core.mu.Lock() |
- defer h.core.mu.Unlock() |
- |
mojoHandle := h.mojoHandle |
h.invalidate() |
- return MojoResult(C.MojoClose(mojoHandle.cValue())) |
+ h.core.mu.Lock() |
+ r := sysImpl.Close(uint32(mojoHandle)) |
+ h.core.mu.Unlock() |
+ return MojoResult(r) |
} |
func (h *baseHandle) IsValid() bool { |
@@ -94,42 +120,50 @@ func (h *baseHandle) ReleaseNativeHandle() MojoHandle { |
func (h *baseHandle) ToUntypedHandle() UntypedHandle { |
handle := &untypedHandleImpl{*h} |
+ runtime.SetFinalizer(handle, finalizeHandle) |
h.invalidate() |
return handle |
} |
func (h *baseHandle) Wait(signals MojoHandleSignals, deadline MojoDeadline) (MojoResult, MojoHandleSignalsState) { |
- cParams := C.MallocWaitParams() |
- defer C.FreeWaitParams(cParams) |
- *cParams.state = C.struct_MojoHandleSignalsState{} |
- result := C.MojoWait(h.mojoHandle.cValue(), signals.cValue(), deadline.cValue(), cParams.state) |
- return MojoResult(result), cParams.state.goValue() |
+ r, satisfiedSignals, satisfiableSignals := sysImpl.Wait(uint32(h.mojoHandle), uint32(signals), uint64(deadline)) |
+ state := MojoHandleSignalsState{ |
+ SatisfiedSignals: MojoHandleSignals(satisfiedSignals), |
+ SatisfiableSignals: MojoHandleSignals(satisfiableSignals), |
+ } |
+ return MojoResult(r), state |
} |
type untypedHandleImpl struct { |
+ // baseHandle should always be the first component of this struct, |
+ // see |finalizeHandle()| for more details. |
baseHandle |
} |
func (h *untypedHandleImpl) ToConsumerHandle() ConsumerHandle { |
handle := &dataPipeConsumer{h.baseHandle} |
+ runtime.SetFinalizer(handle, finalizeHandle) |
h.invalidate() |
return handle |
} |
func (h *untypedHandleImpl) ToProducerHandle() ProducerHandle { |
handle := &dataPipeProducer{h.baseHandle} |
+ runtime.SetFinalizer(handle, finalizeHandle) |
h.invalidate() |
return handle |
} |
func (h *untypedHandleImpl) ToMessagePipeHandle() MessagePipeHandle { |
handle := &messagePipe{h.baseHandle} |
+ runtime.SetFinalizer(handle, finalizeHandle) |
h.invalidate() |
return handle |
} |
func (h *untypedHandleImpl) ToSharedBufferHandle() SharedBufferHandle { |
handle := &sharedBuffer{h.baseHandle} |
+ runtime.SetFinalizer(handle, finalizeHandle) |
h.invalidate() |
return handle |
} |