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