| // 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 ( |
| "runtime" |
| "sync" |
| ) |
| |
| // core is an instance of the Mojo system APIs implementation. |
| var core coreImpl |
| |
| // Core is an interface giving access to the base operations. |
| // See |mojo/public/c/include/mojo/system/*.h| for the underlying API. |
| type Core interface { |
| // AcquireNativeHandle acquires a handle from the native side. The handle |
| // will be owned by the returned object and must not be closed outside of |
| // it. |
| AcquireNativeHandle(handle MojoHandle) UntypedHandle |
| |
| // GetTimeTicksNow returns a monotonically increasing platform dependent |
| // tick count representing "right now". Resolution depends on the system |
| // configuration. |
| GetTimeTicksNow() MojoTimeTicks |
| |
| // WaitMany behaves as if Wait were called on each handle/signal pair |
| // simultaneously and completing when the first Wait would complete. |
| // Notes about return values: |
| // |index| can be -1 if the error returned was not caused by a |
| // particular handle. For example, the error MOJO_RESULT_DEADLINE_EXCEEDED |
| // is not related to a particular handle. |
| // |states| can be nil if the signal array could not be returned. This can |
| // happen with errors such as MOJO_RESULT_INVALID_ARGUMENT. |
| WaitMany(handles []Handle, signals []MojoHandleSignals, deadline MojoDeadline) (result MojoResult, index int, states []MojoHandleSignalsState) |
| |
| // CreateDataPipe creates a data pipe which is a unidirectional |
| // communication channel for unframed data. On success, returns a |
| // handle to the producer and consumer of the data pipe. |
| CreateDataPipe(opts *DataPipeOptions) (MojoResult, ProducerHandle, ConsumerHandle) |
| |
| // CreateMessagePipe creates a message pipe which is a bidirectional |
| // communication channel for framed data (i.e., messages). Messages |
| // can contain plain data and/or Mojo handles. On success, it returns |
| // handles to the two endpoints of the message pipe. |
| CreateMessagePipe(opts *MessagePipeOptions) (MojoResult, MessagePipeHandle, MessagePipeHandle) |
| |
| // CreateSharedBuffer creates a buffer of size numBytes that can be |
| // shared between applications. One must call MapBuffer to access |
| // the buffer. |
| CreateSharedBuffer(opts *SharedBufferOptions, numBytes uint64) (MojoResult, SharedBufferHandle) |
| } |
| |
| // coreImpl is an implementation of the Mojo system APIs. |
| type coreImpl struct { |
| // The Go runtime spawns more OS threads (or recycles one from a thread pool) |
| // to serve its goroutines if a call blocks for more than some small fraction |
| // of time. To prevent creating spurrious OS threads, we try to have no more |
| // than one parallel non-blocking mojo system call; blocking calls shouldn't |
| // use this mutex. |
| mu sync.Mutex |
| } |
| |
| // GetCore returns singleton instance of the Mojo system APIs implementation. |
| // |
| // The implementation uses cgo to call native mojo APIs implementation. Each cgo |
| // call uses a separate thread for execution. To limit the number of used |
| // threads all non-blocking system calls (i.e. all system calls except |Wait| |
| // and |WaitMany|) on this implementation and on handles returned by this |
| // implementation are protected by a mutex so that if you make two parallel |
| // system calls one will wait for another to finish before executing. |
| // However, |Wait| and |WaitMany| are not protected by a mutex and each parallel |
| // call will use a separate thread. To reduce number of threads used for |Wait| |
| // calls prefer to use |WaitMany|. |
| func GetCore() Core { |
| return &core |
| } |
| |
| func (impl *coreImpl) AcquireNativeHandle(mojoHandle MojoHandle) UntypedHandle { |
| handle := &untypedHandleImpl{baseHandle{impl, mojoHandle}} |
| runtime.SetFinalizer(handle, finalizeHandle) |
| return handle |
| } |
| |
| func (impl *coreImpl) GetTimeTicksNow() MojoTimeTicks { |
| impl.mu.Lock() |
| r := sysImpl.GetTimeTicksNow() |
| impl.mu.Unlock() |
| return MojoTimeTicks(r) |
| } |
| |
| func (impl *coreImpl) WaitMany(handles []Handle, signals []MojoHandleSignals, deadline MojoDeadline) (MojoResult, int, []MojoHandleSignalsState) { |
| if len(handles) == 0 { |
| r, _, _, _ := sysImpl.WaitMany(nil, nil, uint64(deadline)) |
| return MojoResult(r), -1, nil |
| } |
| rawHandles := make([]uint32, len(handles)) |
| rawSignals := make([]uint32, len(signals)) |
| for i := 0; i < len(handles); i++ { |
| rawHandles[i] = uint32(handles[i].NativeHandle()) |
| rawSignals[i] = uint32(signals[i]) |
| } |
| r, index, rawSatisfiedSignals, rawSatisfiableSignals := sysImpl.WaitMany(rawHandles, rawSignals, uint64(deadline)) |
| if MojoResult(r) == MOJO_RESULT_INVALID_ARGUMENT || MojoResult(r) == MOJO_RESULT_RESOURCE_EXHAUSTED { |
| return MojoResult(r), index, nil |
| } |
| signalsStates := make([]MojoHandleSignalsState, len(handles)) |
| for i := 0; i < len(handles); i++ { |
| signalsStates[i].SatisfiedSignals = MojoHandleSignals(rawSatisfiedSignals[i]) |
| signalsStates[i].SatisfiableSignals = MojoHandleSignals(rawSatisfiableSignals[i]) |
| } |
| return MojoResult(r), index, signalsStates |
| } |
| |
| func (impl *coreImpl) CreateDataPipe(opts *DataPipeOptions) (MojoResult, ProducerHandle, ConsumerHandle) { |
| |
| var r uint32 |
| var p, c uint32 |
| impl.mu.Lock() |
| if opts == nil { |
| r, p, c = sysImpl.CreateDataPipeWithDefaultOptions() |
| } else { |
| r, p, c = sysImpl.CreateDataPipe(uint32(opts.Flags), uint32(opts.ElemSize), uint32(opts.Capacity)) |
| } |
| impl.mu.Unlock() |
| return MojoResult(r), impl.AcquireNativeHandle(MojoHandle(p)).ToProducerHandle(), impl.AcquireNativeHandle(MojoHandle(c)).ToConsumerHandle() |
| } |
| |
| func (impl *coreImpl) CreateMessagePipe(opts *MessagePipeOptions) (MojoResult, MessagePipeHandle, MessagePipeHandle) { |
| |
| var flags uint32 |
| if opts != nil { |
| flags = uint32(opts.Flags) |
| } |
| impl.mu.Lock() |
| r, handle0, handle1 := sysImpl.CreateMessagePipe(flags) |
| impl.mu.Unlock() |
| return MojoResult(r), impl.AcquireNativeHandle(MojoHandle(handle0)).ToMessagePipeHandle(), impl.AcquireNativeHandle(MojoHandle(handle1)).ToMessagePipeHandle() |
| } |
| |
| func (impl *coreImpl) CreateSharedBuffer(opts *SharedBufferOptions, numBytes uint64) (MojoResult, SharedBufferHandle) { |
| var flags uint32 |
| if opts != nil { |
| flags = uint32(opts.Flags) |
| } |
| impl.mu.Lock() |
| r, handle := sysImpl.CreateSharedBuffer(flags, numBytes) |
| impl.mu.Unlock() |
| return MojoResult(r), impl.AcquireNativeHandle(MojoHandle(handle)).ToSharedBufferHandle() |
| } |