Commit 28e16123 authored by qsr's avatar qsr Committed by Commit bot

Core mojo API for python.

Review URL: https://codereview.chromium.org/377293002

Cr-Commit-Position: refs/heads/master@{#291701}
parent 0aff6f3f
...@@ -13,6 +13,12 @@ group("mojo") { ...@@ -13,6 +13,12 @@ group("mojo") {
"//mojo/services", "//mojo/services",
"//mojo/shell:mojo_shell", "//mojo/shell:mojo_shell",
] ]
if (is_linux) {
deps += [
"//mojo/python",
]
}
} }
group("tests") { group("tests") {
......
...@@ -87,6 +87,13 @@ ...@@ -87,6 +87,13 @@
'mojo_dbus_echo_service', 'mojo_dbus_echo_service',
], ],
}], }],
['component != "shared_library" and OS == "linux"', {
'dependencies': [
'mojo_python_embedder',
'mojo_python_system',
'mojo_python',
],
}],
] ]
}, },
{ {
...@@ -531,5 +538,77 @@ ...@@ -531,5 +538,77 @@
}, },
], ],
}], }],
['component!="shared_library" and OS=="linux"', {
'targets': [
{
'target_name': 'mojo_python_system',
'variables': {
'python_base_module': 'mojo',
'python_cython_module': 'system',
},
'sources': [
'public/python/mojo/c_core.pxd',
'public/python/mojo/system.pyx',
],
'dependencies': [
'mojo_base.gyp:mojo_system',
],
'includes': [ '../third_party/cython/cython_compiler.gypi' ],
},
{
'target_name': 'mojo_python_embedder',
'type': 'loadable_module',
'variables': {
'python_base_module': 'mojo',
'python_cython_module': 'embedder',
},
'sources': [
'python/system/mojo/embedder.pyx',
],
'dependencies': [
'mojo_base.gyp:mojo_system_impl',
],
'includes': [ '../third_party/cython/cython_compiler.gypi' ],
},
{
'target_name': 'mojo_python',
'type': 'none',
'variables': {
'python_base_module': 'mojo',
},
'sources': [
'public/python/mojo/__init__.py',
],
'dependencies': [
'mojo_python_embedder',
'mojo_python_system',
],
'includes': [ '../third_party/cython/python_module.gypi' ],
},
{
'target_name': 'mojo_python_unittests',
'type': 'none',
'actions': [
{
'action_name': 'run_mojo_python_unittests',
'inputs': [
'python/tests/test_core.py',
'<(SHARED_INTERMEDIATE_DIR)/mojo_python_py_module.stamp',
'<(PRODUCT_DIR)/python/mojo/__init__.py',
],
'outputs': [
'none',
],
'action': [
'python', '<@(_inputs)', '<(PRODUCT_DIR)/python',
],
},
],
'dependency': [
'mojo_python',
],
},
],
}],
], ],
} }
...@@ -14,6 +14,12 @@ group("public") { ...@@ -14,6 +14,12 @@ group("public") {
"//mojo/public/js/bindings", "//mojo/public/js/bindings",
] ]
if (is_linux) {
deps += [
"//mojo/public/python",
]
}
if (is_android) { if (is_android) {
deps += [ deps += [
"//mojo/public/java:system", "//mojo/public/java:system",
......
# Copyright 2014 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.
import("//third_party/cython/rules.gni")
group("python") {
deps = [
":base",
":system",
]
}
python_binary_module("system") {
python_base_module = "mojo"
sources = [
"mojo/c_core.pxd",
"mojo/system.pyx",
]
deps = [
"//mojo/public/c/system",
":base",
]
}
copy("base") {
sources = [
"mojo/__init__.py",
]
outputs = [
"$root_out_dir/python/mojo/__init__.py",
]
}
# Copyright 2014 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.
# Copyright 2014 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.
# distutils: language = c++
from cpython.buffer cimport PyBUF_CONTIG
from cpython.buffer cimport PyBUF_CONTIG_RO
from cpython.buffer cimport Py_buffer
from cpython.buffer cimport PyBuffer_FillInfo
from cpython.buffer cimport PyBuffer_Release
from cpython.buffer cimport PyObject_GetBuffer
from cpython.mem cimport PyMem_Malloc, PyMem_Free
from libc.stdint cimport int32_t, int64_t, uint32_t, uint64_t, uintptr_t
cdef extern from "third_party/cython/python_export.h":
pass
cdef extern from "mojo/public/platform/native/system_thunks.h" nogil:
cdef struct MojoSystemThunks:
pass
cdef extern size_t MojoSetSystemThunks(const MojoSystemThunks* system_thunks)
cdef extern from "mojo/public/c/system/core.h" nogil:
# types.h
ctypedef int64_t MojoTimeTicks
ctypedef uint32_t MojoHandle
const MojoHandle MOJO_HANDLE_INVALID
ctypedef int32_t MojoResult
const MojoResult MOJO_RESULT_OK
const MojoResult MOJO_RESULT_CANCELLED
const MojoResult MOJO_RESULT_UNKNOWN
const MojoResult MOJO_RESULT_INVALID_ARGUMENT
const MojoResult MOJO_RESULT_DEADLINE_EXCEEDED
const MojoResult MOJO_RESULT_NOT_FOUND
const MojoResult MOJO_RESULT_ALREADY_EXISTS
const MojoResult MOJO_RESULT_PERMISSION_DENIED
const MojoResult MOJO_RESULT_RESOURCE_EXHAUSTED
const MojoResult MOJO_RESULT_FAILED_PRECONDITION
const MojoResult MOJO_RESULT_ABORTED
const MojoResult MOJO_RESULT_OUT_OF_RANGE
const MojoResult MOJO_RESULT_UNIMPLEMENTED
const MojoResult MOJO_RESULT_INTERNAL
const MojoResult MOJO_RESULT_UNAVAILABLE
const MojoResult MOJO_RESULT_DATA_LOSS
const MojoResult MOJO_RESULT_BUSY
const MojoResult MOJO_RESULT_SHOULD_WAIT
ctypedef uint64_t MojoDeadline
const MojoDeadline MOJO_DEADLINE_INDEFINITE
ctypedef uint32_t MojoHandleSignals
const MojoHandleSignals MOJO_HANDLE_SIGNAL_NONE
const MojoHandleSignals MOJO_HANDLE_SIGNAL_READABLE
const MojoHandleSignals MOJO_HANDLE_SIGNAL_WRITABLE
# functions.h
MojoTimeTicks MojoGetTimeTicksNow()
MojoResult MojoClose(MojoHandle handle)
MojoResult MojoWait(MojoHandle handle,
MojoHandleSignals signals,
MojoDeadline deadline)
MojoResult MojoWaitMany(const MojoHandle* handles,
const MojoHandleSignals* signals,
uint32_t num_handles,
MojoDeadline deadline)
# message_pipe.h
ctypedef uint32_t MojoCreateMessagePipeOptionsFlags
const MojoCreateMessagePipeOptionsFlags MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE
ctypedef uint32_t MojoWriteMessageFlags
const MojoWriteMessageFlags MOJO_WRITE_MESSAGE_FLAG_NONE
ctypedef uint32_t MojoReadMessageFlags
const MojoReadMessageFlags MOJO_READ_MESSAGE_FLAG_NONE
const MojoReadMessageFlags MOJO_READ_MESSAGE_FLAG_MAY_DISCARD
cdef struct MojoCreateMessagePipeOptions:
uint32_t struct_size
MojoCreateMessagePipeOptionsFlags flags
MojoResult MojoCreateMessagePipe(
const MojoCreateMessagePipeOptions* options,
MojoHandle* message_pipe_handle0,
MojoHandle* message_pipe_handle1)
MojoResult MojoWriteMessage(
MojoHandle message_pipe_handle,
const void* bytes,
uint32_t num_bytes,
const MojoHandle* handles,
uint32_t num_handles,
MojoWriteMessageFlags flags)
MojoResult MojoReadMessage(
MojoHandle message_pipe_handle,
void* bytes,
uint32_t* num_bytes,
MojoHandle* handles,
uint32_t* num_handles,
MojoReadMessageFlags flags)
# data_pipe.h
ctypedef uint32_t MojoCreateDataPipeOptionsFlags
const MojoCreateDataPipeOptionsFlags MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE
const MojoCreateDataPipeOptionsFlags MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD
cdef struct MojoCreateDataPipeOptions:
uint32_t struct_size
MojoCreateDataPipeOptionsFlags flags
uint32_t element_num_bytes
uint32_t capacity_num_bytes
ctypedef uint32_t MojoWriteDataFlags
const MojoWriteDataFlags MOJO_WRITE_DATA_FLAG_NONE
const MojoWriteDataFlags MOJO_WRITE_DATA_FLAG_ALL_OR_NONE
ctypedef uint32_t MojoReadDataFlags
const MojoReadDataFlags MOJO_READ_DATA_FLAG_NONE
const MojoReadDataFlags MOJO_READ_DATA_FLAG_ALL_OR_NONE
const MojoReadDataFlags MOJO_READ_DATA_FLAG_DISCARD
const MojoReadDataFlags MOJO_READ_DATA_FLAG_QUERY
MojoResult MojoCreateDataPipe(
const MojoCreateDataPipeOptions* options,
MojoHandle* data_pipe_producer_handle,
MojoHandle* data_pipe_consumer_handle)
MojoResult MojoWriteData(
MojoHandle data_pipe_producer_handle,
const void* elements,
uint32_t* num_bytes,
MojoWriteDataFlags flags)
MojoResult MojoBeginWriteData(
MojoHandle data_pipe_producer_handle,
void** buffer,
uint32_t* buffer_num_bytes,
MojoWriteDataFlags flags)
MojoResult MojoEndWriteData(
MojoHandle data_pipe_producer_handle,
uint32_t num_bytes_written)
MojoResult MojoReadData(
MojoHandle data_pipe_consumer_handle,
void* elements,
uint32_t* num_bytes,
MojoReadDataFlags flags)
MojoResult MojoBeginReadData(
MojoHandle data_pipe_consumer_handle,
const void** buffer,
uint32_t* buffer_num_bytes,
MojoReadDataFlags flags)
MojoResult MojoEndReadData(
MojoHandle data_pipe_consumer_handle,
uint32_t num_bytes_read)
# buffer.h
ctypedef uint32_t MojoCreateSharedBufferOptionsFlags
const MojoCreateSharedBufferOptionsFlags MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE
cdef struct MojoCreateSharedBufferOptions:
uint32_t struct_size
MojoCreateSharedBufferOptionsFlags flags
ctypedef uint32_t MojoDuplicateBufferHandleOptionsFlags
const MojoDuplicateBufferHandleOptionsFlags MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE
cdef struct MojoDuplicateBufferHandleOptions:
uint32_t struct_size
MojoDuplicateBufferHandleOptionsFlags flags
ctypedef uint32_t MojoMapBufferFlags
const MojoMapBufferFlags MOJO_MAP_BUFFER_FLAG_NONE
MojoResult MojoCreateSharedBuffer(
const MojoCreateSharedBufferOptions* options,
uint64_t num_bytes,
MojoHandle* shared_buffer_handle)
MojoResult MojoDuplicateBufferHandle(
MojoHandle buffer_handle,
const MojoDuplicateBufferHandleOptions* options,
MojoHandle* new_buffer_handle)
MojoResult MojoMapBuffer(MojoHandle buffer_handle,
uint64_t offset,
uint64_t num_bytes,
void** buffer,
MojoMapBufferFlags flags)
MojoResult MojoUnmapBuffer(void* buffer)
# Copyright 2014 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.
# distutils language = c++
cimport c_core
from cpython.buffer cimport PyBUF_CONTIG
from cpython.buffer cimport PyBUF_CONTIG_RO
from cpython.buffer cimport Py_buffer
from cpython.buffer cimport PyBuffer_FillInfo
from cpython.buffer cimport PyBuffer_Release
from cpython.buffer cimport PyObject_GetBuffer
from cpython.mem cimport PyMem_Malloc, PyMem_Free
from libc.stdint cimport int32_t, int64_t, uint32_t, uint64_t, uintptr_t
def set_system_thunks(system_thunks_as_object):
"""Bind the basic Mojo Core functions.
This should only be used by the embedder.
"""
cdef const c_core.MojoSystemThunks* system_thunks = (
<const c_core.MojoSystemThunks*><uintptr_t>system_thunks_as_object)
c_core.MojoSetSystemThunks(system_thunks)
HANDLE_INVALID = c_core.MOJO_HANDLE_INVALID
RESULT_OK = c_core.MOJO_RESULT_OK
RESULT_CANCELLED = c_core.MOJO_RESULT_CANCELLED
RESULT_UNKNOWN = c_core.MOJO_RESULT_UNKNOWN
RESULT_INVALID_ARGUMENT = c_core.MOJO_RESULT_INVALID_ARGUMENT
RESULT_DEADLINE_EXCEEDED = c_core.MOJO_RESULT_DEADLINE_EXCEEDED
RESULT_NOT_FOUND = c_core.MOJO_RESULT_NOT_FOUND
RESULT_ALREADY_EXISTS = c_core.MOJO_RESULT_ALREADY_EXISTS
RESULT_PERMISSION_DENIED = c_core.MOJO_RESULT_PERMISSION_DENIED
RESULT_RESOURCE_EXHAUSTED = c_core.MOJO_RESULT_RESOURCE_EXHAUSTED
RESULT_FAILED_PRECONDITION = c_core.MOJO_RESULT_FAILED_PRECONDITION
RESULT_ABORTED = c_core.MOJO_RESULT_ABORTED
RESULT_OUT_OF_RANGE = c_core.MOJO_RESULT_OUT_OF_RANGE
RESULT_UNIMPLEMENTED = c_core.MOJO_RESULT_UNIMPLEMENTED
RESULT_INTERNAL = c_core.MOJO_RESULT_INTERNAL
RESULT_UNAVAILABLE = c_core.MOJO_RESULT_UNAVAILABLE
RESULT_DATA_LOSS = c_core.MOJO_RESULT_DATA_LOSS
RESULT_BUSY = c_core.MOJO_RESULT_BUSY
RESULT_SHOULD_WAIT = c_core.MOJO_RESULT_SHOULD_WAIT
DEADLINE_INDEFINITE = c_core.MOJO_DEADLINE_INDEFINITE
HANDLE_SIGNAL_NONE = c_core.MOJO_HANDLE_SIGNAL_NONE
HANDLE_SIGNAL_READABLE = c_core.MOJO_HANDLE_SIGNAL_READABLE
HANDLE_SIGNAL_WRITABLE = c_core.MOJO_HANDLE_SIGNAL_WRITABLE
WRITE_MESSAGE_FLAG_NONE = c_core.MOJO_WRITE_MESSAGE_FLAG_NONE
READ_MESSAGE_FLAG_NONE = c_core.MOJO_READ_MESSAGE_FLAG_NONE
READ_MESSAGE_FLAG_MAY_DISCARD = c_core.MOJO_READ_MESSAGE_FLAG_MAY_DISCARD
WRITE_DATA_FLAG_NONE = c_core.MOJO_WRITE_DATA_FLAG_NONE
WRITE_DATA_FLAG_ALL_OR_NONE = c_core.MOJO_WRITE_DATA_FLAG_ALL_OR_NONE
READ_DATA_FLAG_NONE = c_core.MOJO_READ_DATA_FLAG_NONE
READ_DATA_FLAG_ALL_OR_NONE = c_core.MOJO_READ_DATA_FLAG_ALL_OR_NONE
READ_DATA_FLAG_DISCARD = c_core.MOJO_READ_DATA_FLAG_DISCARD
READ_DATA_FLAG_QUERY = c_core.MOJO_READ_DATA_FLAG_QUERY
MAP_BUFFER_FLAG_NONE = c_core.MOJO_MAP_BUFFER_FLAG_NONE
def get_time_ticks_now():
"""Monotonically increasing tick count representing "right now."
See mojo/public/c/system/functions.h
"""
return c_core.MojoGetTimeTicksNow()
cdef class _ScopedMemory:
"""Allocate memory at creation, and deallocate it at destruction."""
cdef void* memory
def __init__(self, size):
self.memory = PyMem_Malloc(size)
def __dealloc__(self):
PyMem_Free(self.memory)
cdef class _ScopedBuffer:
"""Retrieve pointer to a buffer a creation, and release it at destruction.
"""
cdef Py_buffer _buf
cdef void* buf
cdef Py_ssize_t len
def __init__(self, obj, flags=PyBUF_CONTIG_RO):
if obj:
if PyObject_GetBuffer(obj, &self._buf, flags) < 0:
raise TypeError('Unable to read buffer.')
self.buf = self._buf.buf
self.len = self._buf.len
else:
self.buf = NULL
self.len = 0
def __dealloc__(self):
if self.buf:
PyBuffer_Release(&self._buf)
def _slice_buffer(buffer, size):
"""Slice the given buffer, reducing it to the given size.
Return None if None is passed in.
"""
if not buffer:
return buffer
return buffer[:size]
cdef class _NativeMemoryView(object):
"""Create a python buffer wrapping the given memory.
Will also retain the given handle until this object is deallocated.
"""
cdef void* _memory
cdef uint32_t _size
cdef char _read_only
cdef char _wrapped
cdef object _handle
def __init__(self, handle):
self._handle = handle
def __cinit__(self):
self._memory = NULL
self._size = 0
self._read_only = True
self._wrapped = False
cdef wrap(self,
const void* memory,
uint32_t size,
read_only=True):
"""Makes this buffer wraps the given memory.
Must be called before using this buffer, and must only be called once.
"""
assert not self._wrapped
self._wrapped = True
self._memory = <void*>memory
self._size = size
self._read_only = read_only
# buffer interface (PEP 3118)
def __getbuffer__(self, Py_buffer *view, int flags):
assert self._wrapped
if view == NULL:
return
PyBuffer_FillInfo(view,
self,
self._memory,
self._size,
self._read_only,
flags)
def __releasebuffer__(self, Py_buffer *view):
assert self._wrapped
pass
# legacy buffer interface
def __getsegcount__(self, Py_ssize_t *sizes):
assert self._wrapped
if sizes != NULL:
sizes[0] = self._size
return 1
def __getreadbuffer__(self, Py_ssize_t index, void **data):
assert self._wrapped
if index != 0:
raise SystemError('Index out of bounds: %d' % index)
data[0] = self._memory
return self._size
def __getwritebuffer__(self, Py_ssize_t index, void **data):
assert self._wrapped
if index != 0:
raise SystemError('Index out of bounds: %d' % index)
if self._read_only:
raise TypeError('Buffer is read-only.')
data[0] = self._memory
return self._size
class MojoException(Exception):
"""Exception wrapping a mojo result error code."""
def __init__(self, mojo_result):
self.mojo_result = mojo_result
def wait_many(handles_and_signals, deadline):
"""Waits on a list of handles.
Args:
handles_and_signals: list of tuples of handle and signal.
See mojo/public/c/system/functions.h
"""
cdef uint32_t length = len(handles_and_signals)
cdef _ScopedMemory handles_alloc = _ScopedMemory(
sizeof(c_core.MojoHandle) * length)
cdef _ScopedMemory signals_alloc = _ScopedMemory(
sizeof(c_core.MojoHandleSignals) * length)
cdef c_core.MojoHandle* handles = <c_core.MojoHandle*>handles_alloc.memory
cdef c_core.MojoHandleSignals* signals = (
<c_core.MojoHandleSignals*>signals_alloc.memory)
cdef int index = 0
for (h, s) in handles_and_signals:
handles[index] = (<Handle?>h)._mojo_handle
signals[index] = s
index += 1
cdef c_core.MojoResult result = c_core.MOJO_RESULT_OK
cdef c_core.MojoDeadline cdeadline = deadline
with nogil:
result = c_core.MojoWaitMany(handles, signals, length, cdeadline)
return result
cdef class DataPipeTwoPhaseBuffer(object):
"""Return value for two phases read and write.
The buffer field contains the python buffer where data can be read or written.
When done with the buffer, the |end| method must be called with the number of
bytes read or written.
"""
cdef object _buffer
cdef Handle _handle
cdef char _read
def __init__(self, handle, buffer, read=True):
self._buffer = buffer
self._handle = handle
self._read = read
def end(self, num_bytes):
self._buffer = None
cdef c_core.MojoResult result
if self._read:
result = c_core.MojoEndReadData(self._handle._mojo_handle, num_bytes)
else:
result = c_core.MojoEndWriteData(self._handle._mojo_handle, num_bytes)
self._handle = None
return result
@property
def buffer(self):
return self._buffer
def __dealloc__(self):
assert not self._buffer
cdef class MappedBuffer(object):
"""Return value for the |map| operation on shared buffer handles.
The buffer field contains the python buffer where data can be read or written.
When done with the buffer, the |unmap| method must be called.
"""
cdef object _buffer
cdef object _handle
cdef object _cleanup
def __init__(self, handle, buffer, cleanup):
self._buffer = buffer
self._handle = handle
self._cleanup = cleanup
def unmap(self):
self._buffer = None
cdef c_core.MojoResult result = self._cleanup()
self._cleanup = None
self._handle = None
return result
@property
def buffer(self):
return self._buffer
def __dealloc__(self):
if self._buffer:
self.unmap()
cdef class Handle(object):
"""A mojo object."""
cdef c_core.MojoHandle _mojo_handle
def __init__(self, mojo_handle=c_core.MOJO_HANDLE_INVALID):
self._mojo_handle = mojo_handle
def _invalidate(self):
"""Invalidate the current handle.
The close operation is not called. It is the responsability of the caller to
ensure that the handle is not leaked.
"""
self._mojo_handle = c_core.MOJO_HANDLE_INVALID
def is_valid(self):
"""Returns whether this handle is valid."""
return self._mojo_handle != c_core.MOJO_HANDLE_INVALID
def close(self):
"""Closes this handle.
See mojo/public/c/system/functions.h
"""
cdef c_core.MojoResult result = c_core.MOJO_RESULT_OK
if self.is_valid():
result = c_core.MojoClose(self._mojo_handle)
self._invalidate()
return result
def __dealloc__(self):
self.close()
def wait(self, signals, deadline):
"""Waits on the given handle.
See mojo/public/c/system/functions.h
"""
cdef c_core.MojoHandle handle = self._mojo_handle
cdef c_core.MojoHandleSignals csignals = signals
cdef c_core.MojoDeadline cdeadline = deadline
cdef c_core.MojoResult result
with nogil:
result = c_core.MojoWait(handle, csignals, cdeadline)
return result
def write_message(self,
buffer=None,
handles=None,
flags=WRITE_MESSAGE_FLAG_NONE):
"""Writes a message to the message pipe.
This method can only be used on a handle obtained from |MessagePipe()|.
See mojo/public/c/system/message_pipe.h
"""
cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer)
cdef uint32_t input_buffer_length = buffer_as_buffer.len
cdef c_core.MojoHandle* input_handles = NULL
cdef uint32_t input_handles_length = 0
cdef _ScopedMemory handles_alloc = None
if handles:
input_handles_length = len(handles)
handles_alloc = _ScopedMemory(sizeof(c_core.MojoHandle) *
input_handles_length)
input_handles = <c_core.MojoHandle*>handles_alloc.memory
for i in xrange(input_handles_length):
input_handles[i] = (<Handle?>handles[i])._mojo_handle
cdef c_core.MojoResult res = c_core.MojoWriteMessage(self._mojo_handle,
buffer_as_buffer.buf,
input_buffer_length,
input_handles,
input_handles_length,
flags)
if res == c_core.MOJO_RESULT_OK and handles:
# Handles have been transferred. Let's invalidate those.
for handle in handles:
handle._invalidate()
return res
def read_message(self,
buffer=None,
max_number_of_handles=0,
flags=READ_MESSAGE_FLAG_NONE):
"""Reads a message from the message pipe.
This method can only be used on a handle obtained from |MessagePipe()|.
This method returns a triplet of value (code, data, sizes):
- if code is RESULT_OK, sizes will be None, and data will be a pair of
(buffer, handles) where buffer is a view of the input buffer with the read
data, and handles is a list of received handles.
- if code is RESULT_RESOURCE_EXHAUSTED, data will be None and sizes will be
a pair of (buffer_size, handles_size) where buffer_size is the size of the
next message data and handles_size is the number of handles in the next
message.
- if code is any other value, data and sizes will be None.
See mojo/public/c/system/message_pipe.h
"""
cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer, PyBUF_CONTIG)
cdef uint32_t input_buffer_length = buffer_as_buffer.len
cdef c_core.MojoHandle* input_handles = NULL
cdef uint32_t input_handles_length = 0
cdef _ScopedMemory handles_alloc = None
if max_number_of_handles > 0:
input_handles_length = max_number_of_handles
handles_alloc = _ScopedMemory(sizeof(c_core.MojoHandle) *
input_handles_length)
input_handles = <c_core.MojoHandle*>handles_alloc.memory
cdef res = c_core.MojoReadMessage(self._mojo_handle,
buffer_as_buffer.buf,
&input_buffer_length,
input_handles,
&input_handles_length,
flags)
if res == c_core.MOJO_RESULT_RESOURCE_EXHAUSTED:
return (res, None, (input_buffer_length, input_handles_length))
if res == c_core.MOJO_RESULT_OK:
returned_handles = [Handle(input_handles[i])
for i in xrange(input_handles_length)]
return (res,
(_slice_buffer(buffer, input_buffer_length), returned_handles),
None)
return (res, None, None)
def write_data(self, buffer=None, flags=WRITE_DATA_FLAG_NONE):
"""
Writes the given data to the data pipe producer.
This method can only be used on a producer handle obtained from
|DataPipe()|.
This method returns a tuple (code, num_bytes).
- If code is RESULT_OK, num_bytes is the number of written bytes.
- Otherwise, num_bytes is None.
See mojo/public/c/system/data_pipe.h
"""
cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer)
cdef uint32_t input_buffer_length = buffer_as_buffer.len
cdef c_core.MojoResult res = c_core.MojoWriteData(self._mojo_handle,
buffer_as_buffer.buf,
&input_buffer_length,
flags)
if res == c_core.MOJO_RESULT_OK:
return (res, input_buffer_length)
return (res, None)
def begin_write_data(self,
min_size=None,
flags=WRITE_DATA_FLAG_NONE):
"""
Begins a two-phase write to the data pipe producer.
This method can only be used on a producer handle obtained from
|DataPipe()|.
This method returns a tuple (code, two_phase_buffer).
- If code is RESULT_OK, two_phase_buffer is a writable
DataPipeTwoPhaseBuffer
- Otherwise, two_phase_buffer is None.
See mojo/public/c/system/data_pipe.h
"""
cdef void* out_buffer
cdef uint32_t out_size = 0
if min_size:
flags |= c_core.MOJO_WRITE_DATA_FLAG_ALL_OR_NONE
out_size = min_size
cdef c_core.MojoResult res = c_core.MojoBeginWriteData(self._mojo_handle,
&out_buffer,
&out_size,
flags)
if res != c_core.MOJO_RESULT_OK:
return (res, None)
cdef _NativeMemoryView view_buffer = _NativeMemoryView(self)
view_buffer.wrap(out_buffer, out_size, read_only=False)
return (res, DataPipeTwoPhaseBuffer(self, memoryview(view_buffer), False))
def read_data(self, buffer=None, flags=READ_DATA_FLAG_NONE):
"""Reads data from the data pipe consumer.
This method can only be used on a consumer handle obtained from
|DataPipe()|.
This method returns a tuple (code, buffer)
- if code is RESULT_OK, buffer will be a view of the input buffer with the
read data.
- otherwise, buffer will be None.
See mojo/public/c/system/data_pipe.h
"""
cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer)
cdef uint32_t input_buffer_length = buffer_as_buffer.len
cdef c_core.MojoResult res = c_core.MojoReadData(self._mojo_handle,
buffer_as_buffer.buf,
&input_buffer_length,
flags)
if res == c_core.MOJO_RESULT_OK:
return (res, _slice_buffer(buffer, input_buffer_length))
return (res, None)
def query_data(self, flags=READ_DATA_FLAG_NONE):
"""Queries the amount of data available on the data pipe consumer.
This method can only be used on a consumer handle obtained from
|DataPipe()|.
This method returns a tuple (code, num_bytes)
- if code is RESULT_OK, num_bytes will be the number of bytes available on
the data pipe consumer.
- otherwise, num_bytes will be None.
See mojo/public/c/system/data_pipe.h
"""
cdef uint32_t num_bytes = 0
cdef c_core.MojoResult res = c_core.MojoReadData(
self._mojo_handle,
NULL,
&num_bytes,
flags|c_core.MOJO_READ_DATA_FLAG_QUERY)
return (res, num_bytes)
def begin_read_data(self, min_size=None, flags=READ_DATA_FLAG_NONE):
"""
Begins a two-phase read to the data pipe consumer.
This method can only be used on a consumer handle obtained from
|DataPipe()|.
This method returns a tuple (code, two_phase_buffer).
- If code is RESULT_OK, two_phase_buffer is a readable
DataPipeTwoPhaseBuffer
- Otherwise, two_phase_buffer is None.
See mojo/public/c/system/data_pipe.h
"""
cdef const void* out_buffer
cdef uint32_t out_size = 0
if min_size:
flags |= c_core.MOJO_READ_DATA_FLAG_ALL_OR_NONE
out_size = min_size
cdef c_core.MojoResult res = c_core.MojoBeginReadData(self._mojo_handle,
&out_buffer,
&out_size,
flags)
if res != c_core.MOJO_RESULT_OK:
return (res, None)
cdef _NativeMemoryView view_buffer = _NativeMemoryView(self)
view_buffer.wrap(out_buffer, out_size, read_only=True)
return (res, DataPipeTwoPhaseBuffer(self, memoryview(view_buffer), True))
def duplicate(self, options=None):
"""Duplicate the shared buffer handle.
This method can only be used on a handle obtained from
|create_shared_buffer()| or |duplicate()|.
See mojo/public/c/system/buffer.h
"""
cdef c_core.MojoDuplicateBufferHandleOptions coptions
cdef c_core.MojoDuplicateBufferHandleOptions* coptions_ptr = NULL
cdef c_core.MojoHandle cnew_handle = c_core.MOJO_HANDLE_INVALID
if options:
coptions.struct_size = sizeof(c_core.MojoDuplicateBufferHandleOptions)
coptions.flags = options.flags
coptions_ptr = &coptions
cdef c_core.MojoResult result = c_core.MojoDuplicateBufferHandle(
self._mojo_handle, coptions_ptr, &cnew_handle)
new_handle = Handle(cnew_handle)
if result != c_core.MOJO_RESULT_OK:
raise MojoException(result)
return new_handle
def map(self, offset, num_bytes, flags=MAP_BUFFER_FLAG_NONE):
"""Maps the part (at offset |offset| of length |num_bytes|) of the buffer.
This method can only be used on a handle obtained from
|create_shared_buffer()| or |duplicate()|.
This method returns a tuple (code, mapped_buffer).
- If code is RESULT_OK, mapped_buffer is a readable/writable
MappedBuffer
- Otherwise, mapped_buffer is None.
See mojo/public/c/system/buffer.h
"""
cdef void* buffer
res = c_core.MojoMapBuffer(self._mojo_handle,
offset,
num_bytes,
&buffer,
flags)
if res != c_core.MOJO_RESULT_OK:
return (res, None)
cdef _NativeMemoryView view_buffer = _NativeMemoryView(self)
view_buffer.wrap(buffer, num_bytes, read_only=False)
return (res, MappedBuffer(self,
memoryview(view_buffer),
lambda: c_core.MojoUnmapBuffer(buffer)))
class CreateMessagePipeOptions(object):
"""Options for creating a message pipe.
See mojo/public/c/system/message_pipe.h
"""
FLAG_NONE = c_core.MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE
def __init__(self):
self.flags = CreateMessagePipeOptions.FLAG_NONE
class MessagePipe(object):
"""Creates a message pipe.
The two ends of the message pipe are accessible with the members handle0 and
handle1.
See mojo/public/c/system/message_pipe.h
"""
def __init__(self, options=None):
cdef c_core.MojoCreateMessagePipeOptions coptions
cdef c_core.MojoCreateMessagePipeOptions* coptions_ptr = NULL
cdef c_core.MojoHandle chandle0 = c_core.MOJO_HANDLE_INVALID
cdef c_core.MojoHandle chandle1 = c_core.MOJO_HANDLE_INVALID
if options:
coptions.struct_size = sizeof(c_core.MojoCreateMessagePipeOptions)
coptions.flags = options.flags
coptions_ptr = &coptions
cdef c_core.MojoResult result = c_core.MojoCreateMessagePipe(coptions_ptr,
&chandle0,
&chandle1)
self.handle0 = Handle(chandle0)
self.handle1 = Handle(chandle1)
if result != c_core.MOJO_RESULT_OK:
raise c_core.MojoException(result)
class CreateDataPipeOptions(object):
"""Options for creating a data pipe.
See mojo/public/c/system/data_pipe.h
"""
FLAG_NONE = c_core.MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE
FLAG_MAY_DISCARD = c_core.MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD
def __init__(self):
self.flags = CreateDataPipeOptions.FLAG_NONE
self.element_num_bytes = 1
self.capacity_num_bytes = 0
class DataPipe(object):
"""Creates a data pipe.
The producer end of the data pipe is accessible with the member
producer_handle and the consumer end of the data pipe is accessible with the
member cconsumer_handle.
See mojo/public/c/system/data_pipe.h
"""
def __init__(self, options=None):
cdef c_core.MojoCreateDataPipeOptions coptions
cdef c_core.MojoCreateDataPipeOptions* coptions_ptr = NULL
cdef c_core.MojoHandle cproducer_handle = c_core.MOJO_HANDLE_INVALID
cdef c_core.MojoHandle cconsumer_handle = c_core.MOJO_HANDLE_INVALID
if options:
coptions.struct_size = sizeof(c_core.MojoCreateDataPipeOptions)
coptions.flags = options.flags
coptions.element_num_bytes = options.element_num_bytes
coptions.capacity_num_bytes = options.capacity_num_bytes
coptions_ptr = &coptions
cdef c_core.MojoResult result = c_core.MojoCreateDataPipe(coptions_ptr,
&cproducer_handle,
&cconsumer_handle)
self.producer_handle = Handle(cproducer_handle)
self.consumer_handle = Handle(cconsumer_handle)
if result != c_core.MOJO_RESULT_OK:
raise MojoException(result)
class CreateSharedBufferOptions(object):
"""Options for creating a shared buffer.
See mojo/public/c/system/buffer.h
"""
FLAG_NONE = c_core.MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE
def __init__(self):
self.flags = CreateSharedBufferOptions.FLAG_NONE
def create_shared_buffer(num_bytes, options=None):
"""Creates a buffer of size |num_bytes| bytes that can be shared.
See mojo/public/c/system/buffer.h
"""
cdef c_core.MojoCreateSharedBufferOptions coptions
cdef c_core.MojoCreateSharedBufferOptions* coptions_ptr = NULL
cdef c_core.MojoHandle chandle = c_core.MOJO_HANDLE_INVALID
if options:
coptions.struct_size = sizeof(c_core.MojoCreateSharedBufferOptions)
coptions.flags = options.flags
coptions_ptr = &coptions
cdef c_core.MojoResult result = c_core.MojoCreateSharedBuffer(coptions_ptr,
num_bytes,
&chandle)
handle = Handle(chandle)
if result != c_core.MOJO_RESULT_OK:
raise MojoException(result)
return handle
class DuplicateSharedBufferOptions(object):
"""Options for duplicating a shared buffer.
See mojo/public/c/system/buffer.h
"""
FLAG_NONE = c_core.MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE
def __init__(self):
self.flags = DuplicateSharedBufferOptions.FLAG_NONE
# Copyright 2014 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.
import("//third_party/cython/rules.gni")
group("python") {
deps = [
":embedder",
]
}
group("tests") {
deps = [
"//mojo/python/tests",
]
}
python_binary_module("embedder") {
python_base_module = "mojo"
sources = [
"system/mojo/embedder.pyx",
]
deps = [
"//mojo/system",
]
datadeps = [
"//mojo/public/python:system",
]
}
# Copyright 2014 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.
# distutils: language = c++
from libc.stdint cimport uintptr_t
from mojo import system
cdef extern from "third_party/cython/python_export.h":
pass
cdef extern from "base/memory/scoped_ptr.h":
cdef cppclass scoped_ptr[T]:
scoped_ptr(T*)
cdef extern from "mojo/embedder/platform_support.h" \
namespace "mojo::embedder" nogil:
cdef cppclass PlatformSupport:
pass
cdef extern from "mojo/embedder/simple_platform_support.h" \
namespace "mojo::embedder" nogil:
cdef cppclass SimplePlatformSupport(PlatformSupport):
SimplePlatformSupport()
cdef extern from "mojo/embedder/embedder.h" nogil:
cdef void InitCEmbedder "mojo::embedder::Init"(
scoped_ptr[PlatformSupport] platform_support)
cdef extern from "mojo/public/platform/native/system_thunks.h" nogil:
cdef struct MojoSystemThunks:
pass
cdef MojoSystemThunks MojoMakeSystemThunks()
def init():
InitCEmbedder(scoped_ptr[PlatformSupport](
new SimplePlatformSupport()))
cdef MojoSystemThunks thunks = MojoMakeSystemThunks()
system.set_system_thunks(<uintptr_t>(&thunks))
# Copyright 2014 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.
import("//third_party/cython/rules.gni")
group("tests") {
deps = [
":test_core",
]
}
action("test_core") {
script = "test_core.py"
outputs = [
"$root_out_dir/no_file",
]
inputs = []
deps = [
"//mojo/public/python:system",
"//mojo/python:embedder",
]
args = [ rebase_path("$root_out_dir/python", root_build_dir) ]
}
# Copyright 2014 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.
import random
import sys
import time
import unittest
# Setup sys path
for path in sys.argv[1:]:
sys.path.append(path)
# pylint: disable=F0401
from mojo.embedder import init as init_embedder
from mojo import system
DATA_SIZE = 1024
def get_random_buffer(size):
random.seed(size)
return bytearray(''.join(chr(random.randint(0, 255)) for i in xrange(size)))
class BaseMojoTest(unittest.TestCase):
def setUp(self):
init_embedder()
class CoreTest(BaseMojoTest):
def test_results(self):
self.assertEquals(system.RESULT_OK, 0)
self.assertLess(system.RESULT_CANCELLED, 0)
self.assertLess(system.RESULT_UNKNOWN, 0)
self.assertLess(system.RESULT_INVALID_ARGUMENT, 0)
self.assertLess(system.RESULT_DEADLINE_EXCEEDED, 0)
self.assertLess(system.RESULT_NOT_FOUND, 0)
self.assertLess(system.RESULT_ALREADY_EXISTS, 0)
self.assertLess(system.RESULT_PERMISSION_DENIED, 0)
self.assertLess(system.RESULT_RESOURCE_EXHAUSTED, 0)
self.assertLess(system.RESULT_FAILED_PRECONDITION, 0)
self.assertLess(system.RESULT_ABORTED, 0)
self.assertLess(system.RESULT_OUT_OF_RANGE, 0)
self.assertLess(system.RESULT_UNIMPLEMENTED, 0)
self.assertLess(system.RESULT_INTERNAL, 0)
self.assertLess(system.RESULT_UNAVAILABLE, 0)
self.assertLess(system.RESULT_DATA_LOSS, 0)
self.assertLess(system.RESULT_BUSY, 0)
self.assertLess(system.RESULT_SHOULD_WAIT, 0)
def test_constants(self):
self.assertGreaterEqual(system.DEADLINE_INDEFINITE, 0)
self.assertGreaterEqual(system.HANDLE_SIGNAL_NONE, 0)
self.assertGreaterEqual(system.HANDLE_SIGNAL_READABLE, 0)
self.assertGreaterEqual(system.HANDLE_SIGNAL_WRITABLE, 0)
self.assertGreaterEqual(system.WRITE_MESSAGE_FLAG_NONE, 0)
self.assertGreaterEqual(system.READ_MESSAGE_FLAG_NONE, 0)
self.assertGreaterEqual(system.READ_MESSAGE_FLAG_MAY_DISCARD, 0)
self.assertGreaterEqual(system.WRITE_DATA_FLAG_NONE, 0)
self.assertGreaterEqual(system.WRITE_DATA_FLAG_ALL_OR_NONE, 0)
self.assertGreaterEqual(system.READ_DATA_FLAG_NONE, 0)
self.assertGreaterEqual(system.READ_DATA_FLAG_ALL_OR_NONE, 0)
self.assertGreaterEqual(system.READ_DATA_FLAG_DISCARD, 0)
self.assertGreaterEqual(system.READ_DATA_FLAG_QUERY, 0)
self.assertGreaterEqual(system.MAP_BUFFER_FLAG_NONE, 0)
def test_get_time_ticks_now(self):
pt1 = time.time()
v1 = system.get_time_ticks_now()
time.sleep(1e-3)
v2 = system.get_time_ticks_now()
pt2 = time.time()
self.assertGreater(v1, 0)
self.assertGreater(v2, v1 + 1000)
self.assertGreater(1e6 * (pt2 - pt1), v2 - v1)
def _test_handles_creation(self, *args):
for handle in args:
self.assertTrue(handle.is_valid())
handle.close()
self.assertFalse(handle.is_valid())
def _test_message_handle_creation(self, handles):
self._test_handles_creation(handles.handle0, handles.handle1)
def test_create_message_pipe(self):
self._test_message_handle_creation(system.MessagePipe())
def test_create_message_pipe_with_none_options(self):
self._test_message_handle_creation(system.MessagePipe(None))
def test_create_message_pipe_with_options(self):
self._test_message_handle_creation(
system.MessagePipe(system.CreateMessagePipeOptions()))
def test_wait_over_message_pipe(self):
handles = system.MessagePipe()
handle = handles.handle0
self.assertEquals(system.RESULT_OK, handle.wait(
system.HANDLE_SIGNAL_WRITABLE, system.DEADLINE_INDEFINITE))
self.assertEquals(system.RESULT_DEADLINE_EXCEEDED,
handle.wait(system.HANDLE_SIGNAL_READABLE, 0))
handles.handle1.write_message()
self.assertEquals(
system.RESULT_OK,
handle.wait(
system.HANDLE_SIGNAL_READABLE,
system.DEADLINE_INDEFINITE))
def test_wait_over_many_message_pipe(self):
handles = system.MessagePipe()
handle0 = handles.handle0
handle1 = handles.handle1
self.assertEquals(
0,
system.wait_many(
[(handle0, system.HANDLE_SIGNAL_WRITABLE),
(handle1, system.HANDLE_SIGNAL_WRITABLE)],
system.DEADLINE_INDEFINITE))
self.assertEquals(
system.RESULT_DEADLINE_EXCEEDED,
system.wait_many(
[(handle0, system.HANDLE_SIGNAL_READABLE),
(handle1, system.HANDLE_SIGNAL_READABLE)], 0))
handle0.write_message()
self.assertEquals(
1,
system.wait_many(
[(handle0, system.HANDLE_SIGNAL_READABLE),
(handle1, system.HANDLE_SIGNAL_READABLE)],
system.DEADLINE_INDEFINITE))
def test_send_bytes_over_message_pipe(self):
handles = system.MessagePipe()
data = get_random_buffer(DATA_SIZE)
handles.handle0.write_message(data)
(res, buffers, next_message) = handles.handle1.read_message()
self.assertEquals(system.RESULT_RESOURCE_EXHAUSTED, res)
self.assertEquals(None, buffers)
self.assertEquals((DATA_SIZE, 0), next_message)
result = bytearray(DATA_SIZE)
(res, buffers, next_message) = handles.handle1.read_message(result)
self.assertEquals(system.RESULT_OK, res)
self.assertEquals(None, next_message)
self.assertEquals((data, []), buffers)
def test_send_empty_data_over_message_pipe(self):
handles = system.MessagePipe()
handles.handle0.write_message(None)
(res, buffers, next_message) = handles.handle1.read_message()
self.assertEquals(system.RESULT_OK, res)
self.assertEquals(None, next_message)
self.assertEquals((None, []), buffers)
def test_send_handle_over_message_pipe(self):
handles = system.MessagePipe()
handles_to_send = system.MessagePipe()
handles.handle0.write_message(handles=[handles_to_send.handle0,
handles_to_send.handle1])
(res, buffers, next_message) = handles.handle1.read_message(
max_number_of_handles=2)
self.assertFalse(handles_to_send.handle0.is_valid())
self.assertFalse(handles_to_send.handle1.is_valid())
self.assertEquals(system.RESULT_OK, res)
self.assertEquals(None, next_message)
self.assertEquals(None, buffers[0])
self.assertEquals(2, len(buffers[1]))
handles = buffers[1]
for handle in handles:
self.assertTrue(handle.is_valid())
(res, buffers, next_message) = handle.read_message()
self.assertEquals(system.RESULT_SHOULD_WAIT, res)
for handle in handles:
handle.write_message()
for handle in handles:
(res, buffers, next_message) = handle.read_message()
self.assertEquals(system.RESULT_OK, res)
def _test_data_handle_creation(self, handles):
self._test_handles_creation(
handles.producer_handle, handles.consumer_handle)
def test_create_data_pipe(self):
self._test_data_handle_creation(system.DataPipe())
def test_create_data_pipe_with_none_options(self):
self._test_data_handle_creation(system.DataPipe(None))
def test_create_data_pipe_with_default_options(self):
self._test_data_handle_creation(
system.DataPipe(system.CreateDataPipeOptions()))
def test_create_data_pipe_with_discard_flag(self):
options = system.CreateDataPipeOptions()
options.flags = system.CreateDataPipeOptions.FLAG_MAY_DISCARD
self._test_data_handle_creation(system.DataPipe(options))
def test_create_data_pipe_with_element_size(self):
options = system.CreateDataPipeOptions()
options.element_num_bytes = 5
self._test_data_handle_creation(system.DataPipe(options))
def test_create_data_pipe_with_capacity(self):
options = system.CreateDataPipeOptions()
options.element_capacity_num_bytes = DATA_SIZE
self._test_data_handle_creation(system.DataPipe(options))
def test_create_data_pipe_with_incorrect_parameters(self):
options = system.CreateDataPipeOptions()
options.element_num_bytes = 5
options.capacity_num_bytes = DATA_SIZE
with self.assertRaises(system.MojoException) as cm:
self._test_data_handle_creation(system.DataPipe(options))
self.assertEquals(system.RESULT_INVALID_ARGUMENT, cm.exception.mojo_result)
def test_send_empty_data_over_data_pipe(self):
pipes = system.DataPipe()
self.assertEquals((system.RESULT_OK, 0), pipes.producer_handle.write_data())
self.assertEquals(
(system.RESULT_OK, None), pipes.consumer_handle.read_data())
def test_send_data_over_data_pipe(self):
pipes = system.DataPipe()
data = get_random_buffer(DATA_SIZE)
self.assertEquals((system.RESULT_OK, DATA_SIZE),
pipes.producer_handle.write_data(data))
self.assertEquals((system.RESULT_OK, data),
pipes.consumer_handle.read_data(bytearray(DATA_SIZE)))
def test_two_phase_write_on_data_pipe(self):
pipes = system.DataPipe()
(res, buf) = pipes.producer_handle.begin_write_data(DATA_SIZE)
self.assertEquals(system.RESULT_OK, res)
self.assertGreaterEqual(len(buf.buffer), DATA_SIZE)
data = get_random_buffer(DATA_SIZE)
buf.buffer[0:DATA_SIZE] = data
self.assertEquals(system.RESULT_OK, buf.end(DATA_SIZE))
self.assertEquals((system.RESULT_OK, data),
pipes.consumer_handle.read_data(bytearray(DATA_SIZE)))
def test_two_phase_read_on_data_pipe(self):
pipes = system.DataPipe()
data = get_random_buffer(DATA_SIZE)
self.assertEquals((system.RESULT_OK, DATA_SIZE),
pipes.producer_handle.write_data(data))
(res, buf) = pipes.consumer_handle.begin_read_data()
self.assertEquals(system.RESULT_OK, res)
self.assertEquals(DATA_SIZE, len(buf.buffer))
self.assertEquals(data, buf.buffer)
self.assertEquals(system.RESULT_OK, buf.end(DATA_SIZE))
def test_create_shared_buffer(self):
self._test_handles_creation(system.create_shared_buffer(DATA_SIZE))
def test_create_shared_buffer_with_none_options(self):
self._test_handles_creation(system.create_shared_buffer(DATA_SIZE, None))
def test_create_shared_buffer_with_default_options(self):
self._test_handles_creation(
system.create_shared_buffer(
DATA_SIZE,
system.CreateSharedBufferOptions()))
def test_duplicate_shared_buffer(self):
handle = system.create_shared_buffer(DATA_SIZE)
self._test_handles_creation(handle.duplicate())
def test_duplicate_shared_buffer_with_none_options(self):
handle = system.create_shared_buffer(DATA_SIZE)
self._test_handles_creation(handle.duplicate(None))
def test_duplicate_shared_buffer_with_default_options(self):
handle = system.create_shared_buffer(DATA_SIZE)
self._test_handles_creation(
handle.duplicate(system.DuplicateSharedBufferOptions()))
def test_send_bytes_over_shared_buffer(self):
handle = system.create_shared_buffer(DATA_SIZE)
duplicated = handle.duplicate()
data = get_random_buffer(DATA_SIZE)
(res1, buf1) = handle.map(0, DATA_SIZE)
(res2, buf2) = duplicated.map(0, DATA_SIZE)
self.assertEquals(system.RESULT_OK, res1)
self.assertEquals(system.RESULT_OK, res2)
self.assertEquals(DATA_SIZE, len(buf1.buffer))
self.assertEquals(DATA_SIZE, len(buf2.buffer))
self.assertEquals(buf1.buffer, buf2.buffer)
buf1.buffer[:] = data
self.assertEquals(data, buf1.buffer)
self.assertEquals(data, buf2.buffer)
self.assertEquals(buf1.buffer, buf2.buffer)
if __name__ == '__main__':
suite = unittest.TestLoader().loadTestsFromTestCase(CoreTest)
test_results = unittest.TextTestRunner(verbosity=0).run(suite)
if not test_results.wasSuccessful():
sys.exit(1)
sys.exit(0)
# Copyright 2014 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.
import argparse
import os
import shutil
import sys
def touch(fname):
if os.path.exists(fname):
os.utime(fname, None)
else:
open(fname, 'a').close()
def main():
"""Command line utility to copy python binary modules to the correct package
hierarchy.
"""
parser = argparse.ArgumentParser(
description='Copy python binary modules to the correct package '
'hierarchy.')
parser.add_argument('timestamp', help='The timetsamp file.')
parser.add_argument('lib_dir', help='The directory containing the modules')
parser.add_argument('destination_dir',
help='The destination directory of the module')
parser.add_argument('mappings', nargs='+',
help='The mapping from module to library.')
opts = parser.parse_args()
if not os.path.exists(opts.destination_dir):
os.makedirs(opts.destination_dir)
for mapping in opts.mappings:
[module, library] = mapping.split('=')
shutil.copy(os.path.join(opts.lib_dir, library),
os.path.join(opts.destination_dir, module))
touch(opts.timestamp)
if __name__ == '__main__':
main()
# Copyright 2014 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.
{
'variables': {
'python_flags': '<(DEPTH)/third_party/cython/python_flags.py',
},
'conditions': [
['OS=="mac"', {
'variables': {
'module_prefix': '',
'module_suffix': '.so',
},
}, {
'variables': {
'module_prefix': '<(SHARED_LIB_PREFIX)',
'module_suffix': '<(SHARED_LIB_SUFFIX)',
},
}],
],
'type': 'loadable_module',
'rules': [
{
'rule_name': '<(_target_name)_cython_compiler',
'extension': 'pyx',
'variables': {
'cython_compiler': '<(DEPTH)/third_party/cython/src/cython.py',
},
'inputs': [
'<(cython_compiler)',
],
'outputs': [
'<(SHARED_INTERMEDIATE_DIR)/cython/<(python_base_module)/<(RULE_INPUT_ROOT).cc',
],
'action': [
'python', '<(cython_compiler)',
'--cplus',
'-I<(DEPTH)',
'-o', '<@(_outputs)',
'<(RULE_INPUT_PATH)',
],
'message': 'Generating C++ source from <(RULE_INPUT_PATH)',
'process_outputs_as_sources': 1,
}
],
'include_dirs': [
'<!@(python <(python_flags) --includes)',
'<(DEPTH)',
],
'libraries': [
'<!@(python <(python_flags) --libraries)',
],
'cflags': [
'-Wno-unused-function',
],
'xcode_settings': {
'WARNING_CFLAGS': [ '-Wno-unused-function' ],
},
'library_dirs': [
'<!@(python <(python_flags) --library_dirs)',
],
'direct_dependent_settings': {
'variables': {
'python_binary_modules': [
'<(python_cython_module)<(module_suffix)=<(module_prefix)<(_target_name)<(module_suffix)',
],
},
},
'hard_dependency': 1,
}
// Copyright 2014 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.
#if defined(PyMODINIT_FUNC)
#undef PyMODINIT_FUNC
#endif
#if defined(WIN32)
#define PyMODINIT_FUNC extern "C" __declspec(dllexport) void
#else
#define PyMODINIT_FUNC extern "C" __attribute__((visibility("default"))) void
#endif
# Copyright 2014 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.
import argparse
import os
import sys
from distutils import sysconfig
from distutils.command import build_ext
from distutils.dist import Distribution
from distutils.extension import Extension
def main():
"""Command line utility to retrieve compilation options for python modules'
"""
parser = argparse.ArgumentParser(
description='Retrieves compilation options for python modules.')
parser.add_argument('--gn',
help='Returns all values in a format suitable for gn',
action='store_true')
parser.add_argument('--libraries', help='Returns libraries',
action='store_true')
parser.add_argument('--includes', help='Returns includes',
action='store_true')
parser.add_argument('--library_dirs', help='Returns library_dirs',
action='store_true')
opts = parser.parse_args()
ext = Extension('Dummy', [])
b = build_ext.build_ext(Distribution())
b.initialize_options()
b.finalize_options()
result = []
if opts.libraries:
libraries = b.get_libraries(ext)
if sys.platform == 'darwin':
libraries += [ '-lpython%s' % sys.version[:3] ]
result = result + libraries
if opts.includes:
result = result + b.include_dirs
if opts.library_dirs:
if sys.platform == 'darwin':
result.append('%s/lib' % sysconfig.get_config_vars('prefix')[0])
if opts.gn:
for x in result:
print x
else:
print ''.join(['"%s"' % x for x in result])
if __name__ == '__main__':
main()
# Copyright 2014 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.
{
'variables': {
'python_binary_modules%': [],
'python_module_destination': '<(PRODUCT_DIR)/python/<(python_base_module)',
'cp': '<(DEPTH)/third_party/cython/cp_python_binary_modules.py',
'timestamp': '<(SHARED_INTERMEDIATE_DIR)/<(_target_name)_py_module.stamp',
},
'rules': [
{
'rule_name': '<(_target_name)_cp_python',
'extension': 'py',
'inputs': [
'<(DEPTH)/build/cp.py',
],
'outputs': [
'<(python_module_destination)/<(RULE_INPUT_NAME)',
],
'action': [
'python',
'<@(_inputs)',
'<(RULE_INPUT_PATH)',
'<@(_outputs)',
],
'message': 'Moving <(RULE_INPUT_PATH) to its destination',
}
],
'actions': [
{
'action_name': '<(_target_name)_move_to_python_modules',
'inputs': [
'<(cp)',
],
'outputs': [
'<(timestamp)',
],
'action': [
'python',
'<(cp)',
'<(timestamp)',
'<(PRODUCT_DIR)',
'<(python_module_destination)',
'>@(python_binary_modules)',
],
},
],
'hard_dependency': 1,
}
# Copyright 2014 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.
template("python_binary_module") {
# Only available on linux for now.
assert(is_linux)
assert(defined(invoker.sources))
assert(defined(invoker.python_base_module))
cython_root = "//third_party/cython"
cython_script = "$cython_root/src/cython.py"
cython_output = "${target_out_dir}/${target_name}.cc"
generator_target_name = target_name + "_cython_compiler"
shared_library_name = target_name + "_shared_library"
config_name = target_name + "_python_config"
if (is_linux) {
shared_library_prefix = "lib"
shared_library_suffix = ".so"
python_module_suffix = ".so"
}
target_visibility = [
":$generator_target_name",
":$shared_library_name",
":$target_name",
]
action(generator_target_name) {
visibility = target_visibility
script = cython_script
sources = invoker.sources
outputs = [ cython_output ]
args = [
"--cplus",
"-I", rebase_path("//", root_build_dir),
"-o", rebase_path(cython_output, root_build_dir),
] + rebase_path(sources, root_build_dir)
}
config(config_name) {
visibility = target_visibility
python_flags = "//third_party/cython/python_flags.py"
include_dirs = exec_script(python_flags,
[ "--gn", "--includes" ],
"list lines")
libs = exec_script(python_flags,
[ "--gn", "--libraries" ],
"list lines")
lib_dirs = exec_script(python_flags,
[ "--gn", "--library_dirs" ],
"list lines")
}
shared_library(shared_library_name) {
visibility = target_visibility
deps = [
":$generator_target_name",
]
if (defined(invoker.deps)) {
deps += invoker.deps
}
if (defined(invoker.datadeps)) {
datadeps = invoker.datadeps
}
sources = [ cython_output ]
configs += [ ":$config_name" ]
}
copy(target_name) {
python_base_module = invoker.python_base_module
sources = [
"$root_out_dir/${shared_library_prefix}${shared_library_name}${shared_library_suffix}"
]
outputs = [
"$root_out_dir/python/$python_base_module/${target_name}${python_module_suffix}"
]
deps = [
":$shared_library_name"
]
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment