summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorqsr <qsr@chromium.org>2014-08-25 10:00:45 -0700
committerCommit bot <commit-bot@chromium.org>2014-08-25 17:01:40 +0000
commit28e16123231497d889ef08ebd917e80d5008ffbf (patch)
tree8e7a961631240f7792423918d84730926d77f4d2
parent0aff6f3f6d49226f59a6b5adce44b1cd0b30ffbd (diff)
downloadchromium_src-28e16123231497d889ef08ebd917e80d5008ffbf.zip
chromium_src-28e16123231497d889ef08ebd917e80d5008ffbf.tar.gz
chromium_src-28e16123231497d889ef08ebd917e80d5008ffbf.tar.bz2
Core mojo API for python.
Review URL: https://codereview.chromium.org/377293002 Cr-Commit-Position: refs/heads/master@{#291701}
-rw-r--r--mojo/BUILD.gn6
-rw-r--r--mojo/mojo.gyp79
-rw-r--r--mojo/public/BUILD.gn6
-rw-r--r--mojo/public/python/BUILD.gn33
-rw-r--r--mojo/public/python/mojo/__init__.py3
-rw-r--r--mojo/public/python/mojo/c_core.pxd201
-rw-r--r--mojo/public/python/mojo/system.pyx696
-rw-r--r--mojo/python/BUILD.gn29
-rw-r--r--mojo/python/system/mojo/embedder.pyx41
-rw-r--r--mojo/python/tests/BUILD.gn24
-rw-r--r--mojo/python/tests/test_core.py314
-rw-r--r--third_party/cython/cp_python_binary_modules.py42
-rw-r--r--third_party/cython/cython_compiler.gypi71
-rw-r--r--third_party/cython/python_export.h13
-rw-r--r--third_party/cython/python_flags.py53
-rw-r--r--third_party/cython/python_module.gypi51
-rw-r--r--third_party/cython/rules.gni84
17 files changed, 1746 insertions, 0 deletions
diff --git a/mojo/BUILD.gn b/mojo/BUILD.gn
index 4a46ecd..39b3859 100644
--- a/mojo/BUILD.gn
+++ b/mojo/BUILD.gn
@@ -13,6 +13,12 @@ group("mojo") {
"//mojo/services",
"//mojo/shell:mojo_shell",
]
+
+ if (is_linux) {
+ deps += [
+ "//mojo/python",
+ ]
+ }
}
group("tests") {
diff --git a/mojo/mojo.gyp b/mojo/mojo.gyp
index f38a793..acd8409 100644
--- a/mojo/mojo.gyp
+++ b/mojo/mojo.gyp
@@ -87,6 +87,13 @@
'mojo_dbus_echo_service',
],
}],
+ ['component != "shared_library" and OS == "linux"', {
+ 'dependencies': [
+ 'mojo_python_embedder',
+ 'mojo_python_system',
+ 'mojo_python',
+ ],
+ }],
]
},
{
@@ -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',
+ ],
+ },
+ ],
+ }],
],
}
diff --git a/mojo/public/BUILD.gn b/mojo/public/BUILD.gn
index 631b6e9..03aefb9 100644
--- a/mojo/public/BUILD.gn
+++ b/mojo/public/BUILD.gn
@@ -14,6 +14,12 @@ group("public") {
"//mojo/public/js/bindings",
]
+ if (is_linux) {
+ deps += [
+ "//mojo/public/python",
+ ]
+ }
+
if (is_android) {
deps += [
"//mojo/public/java:system",
diff --git a/mojo/public/python/BUILD.gn b/mojo/public/python/BUILD.gn
new file mode 100644
index 0000000..c1c6fbc
--- /dev/null
+++ b/mojo/public/python/BUILD.gn
@@ -0,0 +1,33 @@
+# 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",
+ ]
+}
diff --git a/mojo/public/python/mojo/__init__.py b/mojo/public/python/mojo/__init__.py
new file mode 100644
index 0000000..4d6aabb
--- /dev/null
+++ b/mojo/public/python/mojo/__init__.py
@@ -0,0 +1,3 @@
+# 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.
diff --git a/mojo/public/python/mojo/c_core.pxd b/mojo/public/python/mojo/c_core.pxd
new file mode 100644
index 0000000..80b8487d
--- /dev/null
+++ b/mojo/public/python/mojo/c_core.pxd
@@ -0,0 +1,201 @@
+# 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)
diff --git a/mojo/public/python/mojo/system.pyx b/mojo/public/python/mojo/system.pyx
new file mode 100644
index 0000000..80b8dd3
--- /dev/null
+++ b/mojo/public/python/mojo/system.pyx
@@ -0,0 +1,696 @@
+# 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
diff --git a/mojo/python/BUILD.gn b/mojo/python/BUILD.gn
new file mode 100644
index 0000000..18b8737
--- /dev/null
+++ b/mojo/python/BUILD.gn
@@ -0,0 +1,29 @@
+# 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",
+ ]
+}
diff --git a/mojo/python/system/mojo/embedder.pyx b/mojo/python/system/mojo/embedder.pyx
new file mode 100644
index 0000000..c7021f0
--- /dev/null
+++ b/mojo/python/system/mojo/embedder.pyx
@@ -0,0 +1,41 @@
+# 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))
diff --git a/mojo/python/tests/BUILD.gn b/mojo/python/tests/BUILD.gn
new file mode 100644
index 0000000..0d2949d
--- /dev/null
+++ b/mojo/python/tests/BUILD.gn
@@ -0,0 +1,24 @@
+# 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) ]
+}
diff --git a/mojo/python/tests/test_core.py b/mojo/python/tests/test_core.py
new file mode 100644
index 0000000..be0253b
--- /dev/null
+++ b/mojo/python/tests/test_core.py
@@ -0,0 +1,314 @@
+# 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)
diff --git a/third_party/cython/cp_python_binary_modules.py b/third_party/cython/cp_python_binary_modules.py
new file mode 100644
index 0000000..dd38e64
--- /dev/null
+++ b/third_party/cython/cp_python_binary_modules.py
@@ -0,0 +1,42 @@
+# 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()
diff --git a/third_party/cython/cython_compiler.gypi b/third_party/cython/cython_compiler.gypi
new file mode 100644
index 0000000..39d8318
--- /dev/null
+++ b/third_party/cython/cython_compiler.gypi
@@ -0,0 +1,71 @@
+# 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,
+}
diff --git a/third_party/cython/python_export.h b/third_party/cython/python_export.h
new file mode 100644
index 0000000..e943399
--- /dev/null
+++ b/third_party/cython/python_export.h
@@ -0,0 +1,13 @@
+// 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
diff --git a/third_party/cython/python_flags.py b/third_party/cython/python_flags.py
new file mode 100644
index 0000000..03c4ad7
--- /dev/null
+++ b/third_party/cython/python_flags.py
@@ -0,0 +1,53 @@
+# 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()
diff --git a/third_party/cython/python_module.gypi b/third_party/cython/python_module.gypi
new file mode 100644
index 0000000..a61ca2d
--- /dev/null
+++ b/third_party/cython/python_module.gypi
@@ -0,0 +1,51 @@
+# 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,
+}
diff --git a/third_party/cython/rules.gni b/third_party/cython/rules.gni
new file mode 100644
index 0000000..22a56c3
--- /dev/null
+++ b/third_party/cython/rules.gni
@@ -0,0 +1,84 @@
+# 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"
+ ]
+ }
+}