Home | History | Annotate | Download | only in mojo
      1 # Copyright 2014 The Chromium Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 # distutils language = c++
      6 
      7 cimport c_core
      8 cimport c_environment
      9 
     10 
     11 from cpython.buffer cimport PyBUF_CONTIG
     12 from cpython.buffer cimport PyBUF_CONTIG_RO
     13 from cpython.buffer cimport Py_buffer
     14 from cpython.buffer cimport PyBuffer_FillInfo
     15 from cpython.buffer cimport PyBuffer_Release
     16 from cpython.buffer cimport PyObject_GetBuffer
     17 from cpython.mem cimport PyMem_Malloc, PyMem_Free
     18 from libc.stdint cimport int32_t, int64_t, uint32_t, uint64_t, uintptr_t
     19 
     20 def SetSystemThunks(system_thunks_as_object):
     21   """Bind the basic Mojo Core functions.
     22 
     23   This should only be used by the embedder.
     24   """
     25   cdef const c_core.MojoSystemThunks* system_thunks = (
     26       <const c_core.MojoSystemThunks*><uintptr_t>system_thunks_as_object)
     27   c_core.MojoSetSystemThunks(system_thunks)
     28 
     29 HANDLE_INVALID = c_core.MOJO_HANDLE_INVALID
     30 RESULT_OK = c_core.MOJO_RESULT_OK
     31 RESULT_CANCELLED = c_core.MOJO_RESULT_CANCELLED
     32 RESULT_UNKNOWN = c_core.MOJO_RESULT_UNKNOWN
     33 RESULT_INVALID_ARGUMENT = c_core.MOJO_RESULT_INVALID_ARGUMENT
     34 RESULT_DEADLINE_EXCEEDED = c_core.MOJO_RESULT_DEADLINE_EXCEEDED
     35 RESULT_NOT_FOUND = c_core.MOJO_RESULT_NOT_FOUND
     36 RESULT_ALREADY_EXISTS = c_core.MOJO_RESULT_ALREADY_EXISTS
     37 RESULT_PERMISSION_DENIED = c_core.MOJO_RESULT_PERMISSION_DENIED
     38 RESULT_RESOURCE_EXHAUSTED = c_core.MOJO_RESULT_RESOURCE_EXHAUSTED
     39 RESULT_FAILED_PRECONDITION = c_core.MOJO_RESULT_FAILED_PRECONDITION
     40 RESULT_ABORTED = c_core.MOJO_RESULT_ABORTED
     41 RESULT_OUT_OF_RANGE = c_core.MOJO_RESULT_OUT_OF_RANGE
     42 RESULT_UNIMPLEMENTED = c_core.MOJO_RESULT_UNIMPLEMENTED
     43 RESULT_INTERNAL = c_core.MOJO_RESULT_INTERNAL
     44 RESULT_UNAVAILABLE = c_core.MOJO_RESULT_UNAVAILABLE
     45 RESULT_DATA_LOSS = c_core.MOJO_RESULT_DATA_LOSS
     46 RESULT_BUSY = c_core.MOJO_RESULT_BUSY
     47 RESULT_SHOULD_WAIT = c_core.MOJO_RESULT_SHOULD_WAIT
     48 DEADLINE_INDEFINITE = c_core.MOJO_DEADLINE_INDEFINITE
     49 HANDLE_SIGNAL_NONE = c_core.MOJO_HANDLE_SIGNAL_NONE
     50 HANDLE_SIGNAL_READABLE = c_core.MOJO_HANDLE_SIGNAL_READABLE
     51 HANDLE_SIGNAL_WRITABLE = c_core.MOJO_HANDLE_SIGNAL_WRITABLE
     52 WRITE_MESSAGE_FLAG_NONE = c_core.MOJO_WRITE_MESSAGE_FLAG_NONE
     53 READ_MESSAGE_FLAG_NONE = c_core.MOJO_READ_MESSAGE_FLAG_NONE
     54 READ_MESSAGE_FLAG_MAY_DISCARD = c_core.MOJO_READ_MESSAGE_FLAG_MAY_DISCARD
     55 WRITE_DATA_FLAG_NONE = c_core.MOJO_WRITE_DATA_FLAG_NONE
     56 WRITE_DATA_FLAG_ALL_OR_NONE = c_core.MOJO_WRITE_DATA_FLAG_ALL_OR_NONE
     57 READ_DATA_FLAG_NONE = c_core.MOJO_READ_DATA_FLAG_NONE
     58 READ_DATA_FLAG_ALL_OR_NONE = c_core.MOJO_READ_DATA_FLAG_ALL_OR_NONE
     59 READ_DATA_FLAG_DISCARD = c_core.MOJO_READ_DATA_FLAG_DISCARD
     60 READ_DATA_FLAG_QUERY = c_core.MOJO_READ_DATA_FLAG_QUERY
     61 MAP_BUFFER_FLAG_NONE = c_core.MOJO_MAP_BUFFER_FLAG_NONE
     62 
     63 def GetTimeTicksNow():
     64   """Monotonically increasing tick count representing "right now."
     65 
     66   See mojo/public/c/system/functions.h
     67   """
     68   return c_core.MojoGetTimeTicksNow()
     69 
     70 cdef class _ScopedMemory:
     71   """Allocate memory at creation, and deallocate it at destruction."""
     72   cdef void* memory
     73   def __init__(self, size):
     74     self.memory = PyMem_Malloc(size)
     75 
     76   def __dealloc__(self):
     77     PyMem_Free(self.memory)
     78 
     79 cdef class _ScopedBuffer:
     80   """Retrieve pointer to a buffer a creation, and release it at destruction.
     81   """
     82   cdef Py_buffer _buf
     83   cdef void* buf
     84   cdef Py_ssize_t len
     85 
     86   def __init__(self, obj, flags=PyBUF_CONTIG_RO):
     87     if obj:
     88       if PyObject_GetBuffer(obj, &self._buf, flags) < 0:
     89         raise TypeError('Unable to read buffer.')
     90       self.buf = self._buf.buf
     91       self.len = self._buf.len
     92     else:
     93       self.buf = NULL
     94       self.len = 0
     95 
     96   def __dealloc__(self):
     97     if self.buf:
     98       PyBuffer_Release(&self._buf)
     99 
    100 def _SliceBuffer(buffer, size):
    101   """Slice the given buffer, reducing it to the given size.
    102 
    103   Return None if None is passed in.
    104   """
    105   if not buffer:
    106     return buffer
    107   return buffer[:size]
    108 
    109 cdef class _NativeMemoryView(object):
    110   """Create a python buffer wrapping the given memory.
    111 
    112   Will also retain the given handle until this object is deallocated.
    113   """
    114   cdef void* _memory
    115   cdef uint32_t _size
    116   cdef char _read_only
    117   cdef char _wrapped
    118   cdef object _handle
    119 
    120   def __init__(self, handle):
    121     self._handle = handle
    122 
    123   def __cinit__(self):
    124     self._memory = NULL
    125     self._size = 0
    126     self._read_only = True
    127     self._wrapped = False
    128 
    129   cdef Wrap(self,
    130             const void* memory,
    131             uint32_t size,
    132             read_only=True):
    133     """Makes this buffer wraps the given memory.
    134 
    135     Must be called before using this buffer, and must only be called once.
    136     """
    137     assert not self._wrapped
    138     self._wrapped = True
    139     self._memory = <void*>memory
    140     self._size = size
    141     self._read_only = read_only
    142 
    143   # buffer interface (PEP 3118)
    144   def __getbuffer__(self, Py_buffer *view, int flags):
    145     assert self._wrapped
    146     if view == NULL:
    147       return
    148     PyBuffer_FillInfo(view,
    149                       self,
    150                       self._memory,
    151                       self._size,
    152                       self._read_only,
    153                       flags)
    154 
    155   def __releasebuffer__(self, Py_buffer *view):
    156     assert self._wrapped
    157     pass
    158 
    159   # legacy buffer interface
    160   def __getsegcount__(self, Py_ssize_t *sizes):
    161     assert self._wrapped
    162     if sizes != NULL:
    163       sizes[0] = self._size
    164     return 1
    165 
    166   def __getreadbuffer__(self, Py_ssize_t index, void **data):
    167     assert self._wrapped
    168     if index != 0:
    169       raise SystemError('Index out of bounds: %d' % index)
    170     data[0] = self._memory
    171     return self._size
    172 
    173   def __getwritebuffer__(self, Py_ssize_t index, void **data):
    174     assert self._wrapped
    175     if index != 0:
    176       raise SystemError('Index out of bounds: %d' % index)
    177     if self._read_only:
    178       raise TypeError('Buffer is read-only.')
    179     data[0] = self._memory
    180     return self._size
    181 
    182 class MojoException(Exception):
    183   """Exception wrapping a mojo result error code."""
    184 
    185   def __init__(self, mojo_result):
    186     self.mojo_result = mojo_result
    187 
    188 def WaitMany(handles_and_signals, deadline):
    189   """Waits on a list of handles.
    190 
    191   Args:
    192     handles_and_signals: list of tuples of handle and signal.
    193 
    194   See mojo/public/c/system/functions.h
    195   """
    196   cdef uint32_t length = len(handles_and_signals)
    197   cdef _ScopedMemory handles_alloc = _ScopedMemory(
    198       sizeof(c_core.MojoHandle) * length)
    199   cdef _ScopedMemory signals_alloc = _ScopedMemory(
    200       sizeof(c_core.MojoHandleSignals) * length)
    201   cdef c_core.MojoHandle* handles = <c_core.MojoHandle*>handles_alloc.memory
    202   cdef c_core.MojoHandleSignals* signals = (
    203       <c_core.MojoHandleSignals*>signals_alloc.memory)
    204   cdef int index = 0
    205   for (h, s) in handles_and_signals:
    206     handles[index] = (<Handle?>h)._mojo_handle
    207     signals[index] = s
    208     index += 1
    209   cdef c_core.MojoResult result = c_core.MOJO_RESULT_OK
    210   cdef c_core.MojoDeadline cdeadline = deadline
    211   with nogil:
    212     result = c_core.MojoWaitMany(handles, signals, length, cdeadline)
    213   return result
    214 
    215 cdef class DataPipeTwoPhaseBuffer(object):
    216   """Return value for two phases read and write.
    217 
    218   The buffer field contains the python buffer where data can be read or written.
    219   When done with the buffer, the |end| method must be called with the number of
    220   bytes read or written.
    221   """
    222 
    223   cdef object _buffer
    224   cdef Handle _handle
    225   cdef char _read
    226 
    227   def __init__(self, handle, buffer, read=True):
    228     self._buffer = buffer
    229     self._handle = handle
    230     self._read = read
    231 
    232   def End(self, num_bytes):
    233     self._buffer = None
    234     cdef c_core.MojoResult result
    235     if self._read:
    236       result = c_core.MojoEndReadData(self._handle._mojo_handle, num_bytes)
    237     else:
    238       result = c_core.MojoEndWriteData(self._handle._mojo_handle, num_bytes)
    239     self._handle = None
    240     return result
    241 
    242   @property
    243   def buffer(self):
    244     return self._buffer
    245 
    246   def __dealloc__(self):
    247     assert not self._buffer
    248 
    249 cdef class MappedBuffer(object):
    250   """Return value for the |map| operation on shared buffer handles.
    251 
    252   The buffer field contains the python buffer where data can be read or written.
    253   When done with the buffer, the |unmap| method must be called.
    254   """
    255 
    256   cdef object _buffer
    257   cdef object _handle
    258   cdef object _cleanup
    259 
    260   def __init__(self, handle, buffer, cleanup):
    261     self._buffer = buffer
    262     self._handle = handle
    263     self._cleanup = cleanup
    264 
    265   def UnMap(self):
    266     self._buffer = None
    267     cdef c_core.MojoResult result = self._cleanup()
    268     self._cleanup = None
    269     self._handle = None
    270     return result
    271 
    272   @property
    273   def buffer(self):
    274     return self._buffer
    275 
    276   def __dealloc__(self):
    277     if self._buffer:
    278       self.UnMap()
    279 
    280 cdef class Handle(object):
    281   """A mojo object."""
    282 
    283   cdef c_core.MojoHandle _mojo_handle
    284 
    285   def __init__(self, mojo_handle=c_core.MOJO_HANDLE_INVALID):
    286     self._mojo_handle = mojo_handle
    287 
    288   def _Invalidate(self):
    289     """Invalidate the current handle.
    290 
    291     The close operation is not called. It is the responsability of the caller to
    292     ensure that the handle is not leaked.
    293     """
    294     self._mojo_handle = c_core.MOJO_HANDLE_INVALID
    295 
    296   def IsValid(self):
    297     """Returns whether this handle is valid."""
    298     return self._mojo_handle != c_core.MOJO_HANDLE_INVALID
    299 
    300   def Close(self):
    301     """Closes this handle.
    302 
    303     See mojo/public/c/system/functions.h
    304     """
    305     cdef c_core.MojoResult result = c_core.MOJO_RESULT_OK
    306     if self.IsValid():
    307       result = c_core.MojoClose(self._mojo_handle)
    308       self._Invalidate()
    309     return result
    310 
    311   def __dealloc__(self):
    312     self.Close()
    313 
    314   def Wait(self, signals, deadline):
    315     """Waits on the given handle.
    316 
    317     See mojo/public/c/system/functions.h
    318     """
    319     cdef c_core.MojoHandle handle = self._mojo_handle
    320     cdef c_core.MojoHandleSignals csignals = signals
    321     cdef c_core.MojoDeadline cdeadline = deadline
    322     cdef c_core.MojoResult result
    323     with nogil:
    324       result = c_core.MojoWait(handle, csignals, cdeadline)
    325     return result
    326 
    327   def AsyncWait(self, signals, deadline, callback):
    328     cdef c_core.MojoHandle handle = self._mojo_handle
    329     cdef c_core.MojoHandleSignals csignals = signals
    330     cdef c_core.MojoDeadline cdeadline = deadline
    331     cdef c_environment.MojoAsyncWaitID wait_id = _ASYNC_WAITER.AsyncWait(
    332         handle,
    333         csignals,
    334         cdeadline,
    335         callback)
    336     def cancel():
    337       _ASYNC_WAITER.CancelWait(wait_id)
    338     return cancel
    339 
    340   def WriteMessage(self,
    341                     buffer=None,
    342                     handles=None,
    343                     flags=WRITE_MESSAGE_FLAG_NONE):
    344     """Writes a message to the message pipe.
    345 
    346     This method can only be used on a handle obtained from |MessagePipe()|.
    347 
    348     See mojo/public/c/system/message_pipe.h
    349     """
    350     cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer)
    351     cdef uint32_t input_buffer_length = buffer_as_buffer.len
    352     cdef c_core.MojoHandle* input_handles = NULL
    353     cdef uint32_t input_handles_length = 0
    354     cdef _ScopedMemory handles_alloc = None
    355     if handles:
    356       input_handles_length = len(handles)
    357       handles_alloc = _ScopedMemory(sizeof(c_core.MojoHandle) *
    358                                     input_handles_length)
    359       input_handles = <c_core.MojoHandle*>handles_alloc.memory
    360       for i in xrange(input_handles_length):
    361         input_handles[i] = (<Handle?>handles[i])._mojo_handle
    362     cdef c_core.MojoResult res = c_core.MojoWriteMessage(self._mojo_handle,
    363                                                          buffer_as_buffer.buf,
    364                                                          input_buffer_length,
    365                                                          input_handles,
    366                                                          input_handles_length,
    367                                                          flags)
    368     if res == c_core.MOJO_RESULT_OK and handles:
    369       # Handles have been transferred. Let's invalidate those.
    370       for handle in handles:
    371         handle._Invalidate()
    372     return res
    373 
    374   def ReadMessage(self,
    375                    buffer=None,
    376                    max_number_of_handles=0,
    377                    flags=READ_MESSAGE_FLAG_NONE):
    378     """Reads a message from the message pipe.
    379 
    380     This method can only be used on a handle obtained from |MessagePipe()|.
    381 
    382     This method returns a triplet of value (code, data, sizes):
    383     - if code is RESULT_OK, sizes will be None, and data will be a pair of
    384       (buffer, handles) where buffer is a view of the input buffer with the read
    385       data, and handles is a list of received handles.
    386     - if code is RESULT_RESOURCE_EXHAUSTED, data will be None and sizes will be
    387       a pair of (buffer_size, handles_size) where buffer_size is the size of the
    388       next message data and handles_size is the number of handles in the next
    389       message.
    390     - if code is any other value, data and sizes will be None.
    391 
    392     See mojo/public/c/system/message_pipe.h
    393     """
    394     cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer, PyBUF_CONTIG)
    395     cdef uint32_t input_buffer_length = buffer_as_buffer.len
    396     cdef c_core.MojoHandle* input_handles = NULL
    397     cdef uint32_t input_handles_length = 0
    398     cdef _ScopedMemory handles_alloc = None
    399     if max_number_of_handles > 0:
    400       input_handles_length = max_number_of_handles
    401       handles_alloc = _ScopedMemory(sizeof(c_core.MojoHandle) *
    402                                     input_handles_length)
    403       input_handles = <c_core.MojoHandle*>handles_alloc.memory
    404     cdef res = c_core.MojoReadMessage(self._mojo_handle,
    405                                       buffer_as_buffer.buf,
    406                                       &input_buffer_length,
    407                                       input_handles,
    408                                       &input_handles_length,
    409                                       flags)
    410     if res == c_core.MOJO_RESULT_RESOURCE_EXHAUSTED:
    411       return (res, None, (input_buffer_length, input_handles_length))
    412     if res == c_core.MOJO_RESULT_OK:
    413       returned_handles = [Handle(input_handles[i])
    414                           for i in xrange(input_handles_length)]
    415       return (res,
    416               (_SliceBuffer(buffer, input_buffer_length), returned_handles),
    417               None)
    418     return (res, None, None)
    419 
    420   def WriteData(self, buffer=None, flags=WRITE_DATA_FLAG_NONE):
    421     """
    422     Writes the given data to the data pipe producer.
    423 
    424     This method can only be used on a producer handle obtained from
    425     |DataPipe()|.
    426 
    427     This method returns a tuple (code, num_bytes).
    428     - If code is RESULT_OK, num_bytes is the number of written bytes.
    429     - Otherwise, num_bytes is None.
    430 
    431     See mojo/public/c/system/data_pipe.h
    432     """
    433     cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer)
    434     cdef uint32_t input_buffer_length = buffer_as_buffer.len
    435     cdef c_core.MojoResult res = c_core.MojoWriteData(self._mojo_handle,
    436                                                       buffer_as_buffer.buf,
    437                                                       &input_buffer_length,
    438                                                       flags)
    439     if res == c_core.MOJO_RESULT_OK:
    440       return (res, input_buffer_length)
    441     return (res, None)
    442 
    443   def BeginWriteData(self,
    444                        min_size=None,
    445                        flags=WRITE_DATA_FLAG_NONE):
    446     """
    447     Begins a two-phase write to the data pipe producer.
    448 
    449     This method can only be used on a producer handle obtained from
    450     |DataPipe()|.
    451 
    452     This method returns a tuple (code, two_phase_buffer).
    453     - If code is RESULT_OK, two_phase_buffer is a writable
    454       DataPipeTwoPhaseBuffer
    455     - Otherwise, two_phase_buffer is None.
    456 
    457     See mojo/public/c/system/data_pipe.h
    458     """
    459     cdef void* out_buffer
    460     cdef uint32_t out_size = 0
    461     if min_size:
    462       flags |= c_core.MOJO_WRITE_DATA_FLAG_ALL_OR_NONE
    463       out_size = min_size
    464     cdef c_core.MojoResult res = c_core.MojoBeginWriteData(self._mojo_handle,
    465                                                            &out_buffer,
    466                                                            &out_size,
    467                                                            flags)
    468     if res != c_core.MOJO_RESULT_OK:
    469       return (res, None)
    470     cdef _NativeMemoryView view_buffer = _NativeMemoryView(self)
    471     view_buffer.Wrap(out_buffer, out_size, read_only=False)
    472     return (res, DataPipeTwoPhaseBuffer(self, memoryview(view_buffer), False))
    473 
    474   def ReadData(self, buffer=None, flags=READ_DATA_FLAG_NONE):
    475     """Reads data from the data pipe consumer.
    476 
    477     This method can only be used on a consumer handle obtained from
    478     |DataPipe()|.
    479 
    480     This method returns a tuple (code, buffer)
    481     - if code is RESULT_OK, buffer will be a view of the input buffer with the
    482       read data.
    483     - otherwise, buffer will be None.
    484 
    485     See mojo/public/c/system/data_pipe.h
    486     """
    487     cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer)
    488     cdef uint32_t input_buffer_length = buffer_as_buffer.len
    489     cdef c_core.MojoResult res = c_core.MojoReadData(self._mojo_handle,
    490                                                      buffer_as_buffer.buf,
    491                                                      &input_buffer_length,
    492                                                      flags)
    493     if res == c_core.MOJO_RESULT_OK:
    494       return (res, _SliceBuffer(buffer, input_buffer_length))
    495     return (res, None)
    496 
    497   def QueryData(self, flags=READ_DATA_FLAG_NONE):
    498     """Queries the amount of data available on the data pipe consumer.
    499 
    500     This method can only be used on a consumer handle obtained from
    501     |DataPipe()|.
    502 
    503     This method returns a tuple (code, num_bytes)
    504     - if code is RESULT_OK, num_bytes will be the number of bytes available on
    505       the data pipe consumer.
    506     - otherwise, num_bytes will be None.
    507 
    508     See mojo/public/c/system/data_pipe.h
    509     """
    510     cdef uint32_t num_bytes = 0
    511     cdef c_core.MojoResult res = c_core.MojoReadData(
    512         self._mojo_handle,
    513         NULL,
    514         &num_bytes,
    515         flags|c_core.MOJO_READ_DATA_FLAG_QUERY)
    516     return (res, num_bytes)
    517 
    518   def BeginReadData(self, min_size=None, flags=READ_DATA_FLAG_NONE):
    519     """
    520     Begins a two-phase read to the data pipe consumer.
    521 
    522     This method can only be used on a consumer handle obtained from
    523     |DataPipe()|.
    524 
    525     This method returns a tuple (code, two_phase_buffer).
    526     - If code is RESULT_OK, two_phase_buffer is a readable
    527       DataPipeTwoPhaseBuffer
    528     - Otherwise, two_phase_buffer is None.
    529 
    530     See mojo/public/c/system/data_pipe.h
    531     """
    532     cdef const void* out_buffer
    533     cdef uint32_t out_size = 0
    534     if min_size:
    535       flags |= c_core.MOJO_READ_DATA_FLAG_ALL_OR_NONE
    536       out_size = min_size
    537     cdef c_core.MojoResult res = c_core.MojoBeginReadData(self._mojo_handle,
    538                                                           &out_buffer,
    539                                                           &out_size,
    540                                                           flags)
    541     if res != c_core.MOJO_RESULT_OK:
    542       return (res, None)
    543     cdef _NativeMemoryView view_buffer = _NativeMemoryView(self)
    544     view_buffer.Wrap(out_buffer, out_size, read_only=True)
    545     return (res, DataPipeTwoPhaseBuffer(self, memoryview(view_buffer), True))
    546 
    547   def Duplicate(self, options=None):
    548     """Duplicate the shared buffer handle.
    549 
    550     This method can only be used on a handle obtained from
    551     |CreateSharedBuffer()| or |Duplicate()|.
    552 
    553     See mojo/public/c/system/buffer.h
    554     """
    555     cdef c_core.MojoDuplicateBufferHandleOptions coptions
    556     cdef c_core.MojoDuplicateBufferHandleOptions* coptions_ptr = NULL
    557     cdef c_core.MojoHandle cnew_handle = c_core.MOJO_HANDLE_INVALID
    558     if options:
    559       coptions.struct_size = sizeof(c_core.MojoDuplicateBufferHandleOptions)
    560       coptions.flags = options.flags
    561       coptions_ptr = &coptions
    562     cdef c_core.MojoResult result = c_core.MojoDuplicateBufferHandle(
    563         self._mojo_handle, coptions_ptr, &cnew_handle)
    564     new_handle = Handle(cnew_handle)
    565     if result != c_core.MOJO_RESULT_OK:
    566       raise MojoException(result)
    567     return new_handle
    568 
    569   def Map(self, offset, num_bytes, flags=MAP_BUFFER_FLAG_NONE):
    570     """Maps the part (at offset |offset| of length |num_bytes|) of the buffer.
    571 
    572     This method can only be used on a handle obtained from
    573     |CreateSharedBuffer()| or |Duplicate()|.
    574 
    575     This method returns a tuple (code, mapped_buffer).
    576     - If code is RESULT_OK, mapped_buffer is a readable/writable
    577       MappedBuffer
    578     - Otherwise, mapped_buffer is None.
    579 
    580     See mojo/public/c/system/buffer.h
    581     """
    582     cdef void* buffer
    583     res = c_core.MojoMapBuffer(self._mojo_handle,
    584                                offset,
    585                                num_bytes,
    586                                &buffer,
    587                                flags)
    588     if res != c_core.MOJO_RESULT_OK:
    589       return (res, None)
    590     cdef _NativeMemoryView view_buffer = _NativeMemoryView(self)
    591     view_buffer.Wrap(buffer, num_bytes, read_only=False)
    592     return (res, MappedBuffer(self,
    593                               memoryview(view_buffer),
    594                               lambda: c_core.MojoUnmapBuffer(buffer)))
    595 
    596 class CreateMessagePipeOptions(object):
    597   """Options for creating a message pipe.
    598 
    599   See mojo/public/c/system/message_pipe.h
    600   """
    601   FLAG_NONE = c_core.MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE
    602 
    603   def __init__(self):
    604     self.flags = CreateMessagePipeOptions.FLAG_NONE
    605 
    606 class MessagePipe(object):
    607   """Creates a message pipe.
    608 
    609   The two ends of the message pipe are accessible with the members handle0 and
    610   handle1.
    611 
    612   See mojo/public/c/system/message_pipe.h
    613   """
    614   def __init__(self, options=None):
    615     cdef c_core.MojoCreateMessagePipeOptions coptions
    616     cdef c_core.MojoCreateMessagePipeOptions* coptions_ptr = NULL
    617     cdef c_core.MojoHandle chandle0 = c_core.MOJO_HANDLE_INVALID
    618     cdef c_core.MojoHandle chandle1 = c_core.MOJO_HANDLE_INVALID
    619     if options:
    620       coptions.struct_size = sizeof(c_core.MojoCreateMessagePipeOptions)
    621       coptions.flags = options.flags
    622       coptions_ptr = &coptions
    623     cdef c_core.MojoResult result = c_core.MojoCreateMessagePipe(coptions_ptr,
    624                                                                  &chandle0,
    625                                                                  &chandle1)
    626     self.handle0 = Handle(chandle0)
    627     self.handle1 = Handle(chandle1)
    628     if result != c_core.MOJO_RESULT_OK:
    629       raise c_core.MojoException(result)
    630 
    631 
    632 class CreateDataPipeOptions(object):
    633   """Options for creating a data pipe.
    634 
    635   See mojo/public/c/system/data_pipe.h
    636   """
    637   FLAG_NONE = c_core.MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE
    638   FLAG_MAY_DISCARD = c_core.MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD
    639 
    640   def __init__(self):
    641     self.flags = CreateDataPipeOptions.FLAG_NONE
    642     self.element_num_bytes = 1
    643     self.capacity_num_bytes = 0
    644 
    645 class DataPipe(object):
    646   """Creates a data pipe.
    647 
    648   The producer end of the data pipe is accessible with the member
    649   producer_handle and the consumer end of the data pipe is accessible with the
    650   member cconsumer_handle.
    651 
    652   See mojo/public/c/system/data_pipe.h
    653   """
    654   def __init__(self, options=None):
    655     cdef c_core.MojoCreateDataPipeOptions coptions
    656     cdef c_core.MojoCreateDataPipeOptions* coptions_ptr = NULL
    657     cdef c_core.MojoHandle cproducer_handle = c_core.MOJO_HANDLE_INVALID
    658     cdef c_core.MojoHandle cconsumer_handle = c_core.MOJO_HANDLE_INVALID
    659     if options:
    660       coptions.struct_size = sizeof(c_core.MojoCreateDataPipeOptions)
    661       coptions.flags = options.flags
    662       coptions.element_num_bytes = options.element_num_bytes
    663       coptions.capacity_num_bytes = options.capacity_num_bytes
    664       coptions_ptr = &coptions
    665     cdef c_core.MojoResult result = c_core.MojoCreateDataPipe(coptions_ptr,
    666                                                               &cproducer_handle,
    667                                                               &cconsumer_handle)
    668     self.producer_handle = Handle(cproducer_handle)
    669     self.consumer_handle = Handle(cconsumer_handle)
    670     if result != c_core.MOJO_RESULT_OK:
    671       raise MojoException(result)
    672 
    673 class CreateSharedBufferOptions(object):
    674   """Options for creating a shared buffer.
    675 
    676   See mojo/public/c/system/buffer.h
    677   """
    678   FLAG_NONE = c_core.MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE
    679 
    680   def __init__(self):
    681     self.flags = CreateSharedBufferOptions.FLAG_NONE
    682 
    683 def CreateSharedBuffer(num_bytes, options=None):
    684   """Creates a buffer of size |num_bytes| bytes that can be shared.
    685 
    686   See mojo/public/c/system/buffer.h
    687   """
    688   cdef c_core.MojoCreateSharedBufferOptions coptions
    689   cdef c_core.MojoCreateSharedBufferOptions* coptions_ptr = NULL
    690   cdef c_core.MojoHandle chandle = c_core.MOJO_HANDLE_INVALID
    691   if options:
    692     coptions.struct_size = sizeof(c_core.MojoCreateSharedBufferOptions)
    693     coptions.flags = options.flags
    694     coptions_ptr = &coptions
    695   cdef c_core.MojoResult result = c_core.MojoCreateSharedBuffer(coptions_ptr,
    696                                                                 num_bytes,
    697                                                                 &chandle)
    698   handle = Handle(chandle)
    699   if result != c_core.MOJO_RESULT_OK:
    700     raise MojoException(result)
    701   return handle
    702 
    703 class DuplicateSharedBufferOptions(object):
    704   """Options for duplicating a shared buffer.
    705 
    706   See mojo/public/c/system/buffer.h
    707   """
    708   FLAG_NONE = c_core.MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE
    709 
    710   def __init__(self):
    711     self.flags = DuplicateSharedBufferOptions.FLAG_NONE
    712 
    713 
    714 cdef class RunLoop(object):
    715   """RunLoop to use when using asynchronous operations on handles."""
    716 
    717   cdef c_environment.CRunLoop c_run_loop
    718 
    719   def Run(self):
    720     """Run the runloop until Quit is called."""
    721     self.c_run_loop.Run()
    722 
    723   def RunUntilIdle(self):
    724     """Run the runloop until Quit is called or no operation is waiting."""
    725     self.c_run_loop.RunUntilIdle()
    726 
    727   def Quit(self):
    728     """Quit the runloop."""
    729     self.c_run_loop.Quit()
    730 
    731   def PostDelayedTask(self, runnable, delay=0):
    732     """
    733     Post a task on the runloop. This must be called from the thread owning the
    734     runloop.
    735     """
    736     cdef c_environment.CClosure closure = c_environment.BuildClosure(runnable)
    737     self.c_run_loop.PostDelayedTask(closure, delay)
    738 
    739 
    740 cdef c_environment.CEnvironment* _ENVIRONMENT = new c_environment.CEnvironment()
    741 cdef c_environment.PythonAsyncWaiter* _ASYNC_WAITER = new c_environment.PythonAsyncWaiter()
    742