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