blob: d8d66dba4b30c2f34557c4b6c70486ff4f7ebc49 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package system
import (
"log"
"runtime"
)
// Handle is a generic handle for mojo objects.
type Handle interface {
// Close closes the given handle.
Close() MojoResult
// IsValid returns whether the handle is valid. A handle is valid until it
// has been explicitly closed or sent through a message pipe.
IsValid() bool
// NativeHandle returns the native handle backed by this handle.
//
// Note: try to avoid using this method as you lose ownership tracking.
NativeHandle() MojoHandle
// ReleaseNativeHandle releases the native handle backed by this handle.
// The caller owns the handle and must close it.
ReleaseNativeHandle() MojoHandle
// ToUntypedHandle converts this handle into an UntypedHandle, invalidating
// this handle.
ToUntypedHandle() UntypedHandle
// Wait waits on the handle until a signal indicated by signals is satisfied
// or it becomes known that no signal indicated by signals will ever be
// satisified or until deadline has passed.
Wait(signals MojoHandleSignals, deadline MojoDeadline) (MojoResult, MojoHandleSignalsState)
}
// UntypedHandle is a a mojo handle of unknown type. This handle can be typed by
// using one of its methods, which will return a handle of the requested type
// and invalidate this object. No validation is made when the conversion
// operation is called.
type UntypedHandle interface {
Handle
// ToConsumerHandle returns the underlying handle as a ConsumerHandle
// and invalidates this UntypedHandle representation.
ToConsumerHandle() ConsumerHandle
// ToProducerHandle returns the underlying handle as a ProducerHandle
// and invalidates this UntypedHandle representation.
ToProducerHandle() ProducerHandle
// ToMessagePipeHandle returns the underlying handle as a MessagePipeHandle
// and invalidates this UntypedHandle representation.
ToMessagePipeHandle() MessagePipeHandle
// ToSharedBufferHandle returns the underlying handle as a
// SharedBufferHandle and invalidates this UntypedHandle representation.
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
}
func (h *baseHandle) invalidate() {
h.mojoHandle = MOJO_HANDLE_INVALID
runtime.SetFinalizer(h, nil)
}
func (h *baseHandle) Close() MojoResult {
mojoHandle := h.mojoHandle
h.invalidate()
h.core.mu.Lock()
r := sysImpl.Close(uint32(mojoHandle))
h.core.mu.Unlock()
return MojoResult(r)
}
func (h *baseHandle) IsValid() bool {
return h.mojoHandle != MOJO_HANDLE_INVALID
}
func (h *baseHandle) NativeHandle() MojoHandle {
return h.mojoHandle
}
func (h *baseHandle) ReleaseNativeHandle() MojoHandle {
mojoHandle := h.mojoHandle
h.invalidate()
return 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) {
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
}