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