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.
5 # distutils language = c++
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 cpython.object cimport Py_EQ, Py_NE
19 from libc.stdint cimport int32_t, int64_t, uint32_t, uint64_t, uintptr_t
24 def SetSystemThunks(system_thunks_as_object):
25 """Bind the basic Mojo Core functions.
27 This should only be used by the embedder.
29 cdef const c_core.MojoSystemThunks* system_thunks = (
30 <const c_core.MojoSystemThunks*><uintptr_t>system_thunks_as_object)
31 c_core.MojoSetSystemThunks(system_thunks)
33 HANDLE_INVALID = c_core.MOJO_HANDLE_INVALID
34 RESULT_OK = c_core.MOJO_RESULT_OK
35 RESULT_CANCELLED = c_core.MOJO_RESULT_CANCELLED
36 RESULT_UNKNOWN = c_core.MOJO_RESULT_UNKNOWN
37 RESULT_INVALID_ARGUMENT = c_core.MOJO_RESULT_INVALID_ARGUMENT
38 RESULT_DEADLINE_EXCEEDED = c_core.MOJO_RESULT_DEADLINE_EXCEEDED
39 RESULT_NOT_FOUND = c_core.MOJO_RESULT_NOT_FOUND
40 RESULT_ALREADY_EXISTS = c_core.MOJO_RESULT_ALREADY_EXISTS
41 RESULT_PERMISSION_DENIED = c_core.MOJO_RESULT_PERMISSION_DENIED
42 RESULT_RESOURCE_EXHAUSTED = c_core.MOJO_RESULT_RESOURCE_EXHAUSTED
43 RESULT_FAILED_PRECONDITION = c_core.MOJO_RESULT_FAILED_PRECONDITION
44 RESULT_ABORTED = c_core.MOJO_RESULT_ABORTED
45 RESULT_OUT_OF_RANGE = c_core.MOJO_RESULT_OUT_OF_RANGE
46 RESULT_UNIMPLEMENTED = c_core.MOJO_RESULT_UNIMPLEMENTED
47 RESULT_INTERNAL = c_core.MOJO_RESULT_INTERNAL
48 RESULT_UNAVAILABLE = c_core.MOJO_RESULT_UNAVAILABLE
49 RESULT_DATA_LOSS = c_core.MOJO_RESULT_DATA_LOSS
50 RESULT_BUSY = c_core.MOJO_RESULT_BUSY
51 RESULT_SHOULD_WAIT = c_core.MOJO_RESULT_SHOULD_WAIT
52 DEADLINE_INDEFINITE = c_core.MOJO_DEADLINE_INDEFINITE
53 HANDLE_SIGNAL_NONE = c_core.MOJO_HANDLE_SIGNAL_NONE
54 HANDLE_SIGNAL_READABLE = c_core.MOJO_HANDLE_SIGNAL_READABLE
55 HANDLE_SIGNAL_WRITABLE = c_core.MOJO_HANDLE_SIGNAL_WRITABLE
56 WRITE_MESSAGE_FLAG_NONE = c_core.MOJO_WRITE_MESSAGE_FLAG_NONE
57 READ_MESSAGE_FLAG_NONE = c_core.MOJO_READ_MESSAGE_FLAG_NONE
58 READ_MESSAGE_FLAG_MAY_DISCARD = c_core.MOJO_READ_MESSAGE_FLAG_MAY_DISCARD
59 WRITE_DATA_FLAG_NONE = c_core.MOJO_WRITE_DATA_FLAG_NONE
60 WRITE_DATA_FLAG_ALL_OR_NONE = c_core.MOJO_WRITE_DATA_FLAG_ALL_OR_NONE
61 READ_DATA_FLAG_NONE = c_core.MOJO_READ_DATA_FLAG_NONE
62 READ_DATA_FLAG_ALL_OR_NONE = c_core.MOJO_READ_DATA_FLAG_ALL_OR_NONE
63 READ_DATA_FLAG_DISCARD = c_core.MOJO_READ_DATA_FLAG_DISCARD
64 READ_DATA_FLAG_QUERY = c_core.MOJO_READ_DATA_FLAG_QUERY
65 MAP_BUFFER_FLAG_NONE = c_core.MOJO_MAP_BUFFER_FLAG_NONE
67 def GetTimeTicksNow():
68 """Monotonically increasing tick count representing "right now."
70 See mojo/public/c/system/functions.h
72 return c_core.MojoGetTimeTicksNow()
74 cdef class _ScopedMemory:
75 """Allocate memory at creation, and deallocate it at destruction."""
77 def __init__(self, size):
78 self.memory = PyMem_Malloc(size)
80 def __dealloc__(self):
81 PyMem_Free(self.memory)
83 cdef class _ScopedBuffer:
84 """Retrieve pointer to a buffer a creation, and release it at destruction.
90 def __init__(self, obj, flags=PyBUF_CONTIG_RO):
92 if PyObject_GetBuffer(obj, &self._buf, flags) < 0:
93 raise TypeError('Unable to read buffer.')
94 self.buf = self._buf.buf
95 self.len = self._buf.len
100 def __dealloc__(self):
102 PyBuffer_Release(&self._buf)
104 def _SliceBuffer(buffer, size):
105 """Slice the given buffer, reducing it to the given size.
107 Return None if None is passed in.
113 cdef class _NativeMemoryView(object):
114 """Create a python buffer wrapping the given memory.
116 Will also retain the given handle until this object is deallocated.
124 def __init__(self, handle):
125 self._handle = handle
130 self._read_only = True
131 self._wrapped = False
137 """Makes this buffer wraps the given memory.
139 Must be called before using this buffer, and must only be called once.
141 assert not self._wrapped
143 self._memory = <void*>memory
145 self._read_only = read_only
147 # buffer interface (PEP 3118)
148 def __getbuffer__(self, Py_buffer *view, int flags):
152 PyBuffer_FillInfo(view,
159 def __releasebuffer__(self, Py_buffer *view):
163 # legacy buffer interface
164 def __getsegcount__(self, Py_ssize_t *sizes):
167 sizes[0] = self._size
170 def __getreadbuffer__(self, Py_ssize_t index, void **data):
173 raise SystemError('Index out of bounds: %d' % index)
174 data[0] = self._memory
177 def __getwritebuffer__(self, Py_ssize_t index, void **data):
180 raise SystemError('Index out of bounds: %d' % index)
182 raise TypeError('Buffer is read-only.')
183 data[0] = self._memory
186 class MojoException(Exception):
187 """Exception wrapping a mojo result error code."""
189 def __init__(self, mojo_result):
190 self.mojo_result = mojo_result
192 def WaitMany(handles_and_signals, deadline):
193 """Waits on a list of handles.
196 handles_and_signals: list of tuples of handle and signal.
198 See mojo/public/c/system/functions.h
200 cdef uint32_t length = len(handles_and_signals)
201 cdef _ScopedMemory handles_alloc = _ScopedMemory(
202 sizeof(c_core.MojoHandle) * length)
203 cdef _ScopedMemory signals_alloc = _ScopedMemory(
204 sizeof(c_core.MojoHandleSignals) * length)
205 cdef c_core.MojoHandle* handles = <c_core.MojoHandle*>handles_alloc.memory
206 cdef c_core.MojoHandleSignals* signals = (
207 <c_core.MojoHandleSignals*>signals_alloc.memory)
209 for (h, s) in handles_and_signals:
210 handles[index] = (<Handle?>h)._mojo_handle
213 cdef c_core.MojoResult result = c_core.MOJO_RESULT_OK
214 cdef c_core.MojoDeadline cdeadline = deadline
216 result = c_core.MojoWaitMany(handles, signals, length, cdeadline)
219 cdef class DataPipeTwoPhaseBuffer(object):
220 """Return value for two phases read and write.
222 The buffer field contains the python buffer where data can be read or written.
223 When done with the buffer, the |end| method must be called with the number of
224 bytes read or written.
231 def __init__(self, handle, buffer, read=True):
232 self._buffer = buffer
233 self._handle = handle
236 def End(self, num_bytes):
238 cdef c_core.MojoResult result
240 result = c_core.MojoEndReadData(self._handle._mojo_handle, num_bytes)
242 result = c_core.MojoEndWriteData(self._handle._mojo_handle, num_bytes)
250 def __dealloc__(self):
251 assert not self._buffer
253 cdef class MappedBuffer(object):
254 """Return value for the |map| operation on shared buffer handles.
256 The buffer field contains the python buffer where data can be read or written.
257 When done with the buffer, the |unmap| method must be called.
264 def __init__(self, handle, buffer, cleanup):
265 self._buffer = buffer
266 self._handle = handle
267 self._cleanup = cleanup
271 cdef c_core.MojoResult result = self._cleanup()
280 def __dealloc__(self):
284 cdef class Handle(object):
287 cdef c_core.MojoHandle _mojo_handle
289 def __init__(self, mojo_handle=c_core.MOJO_HANDLE_INVALID):
290 self._mojo_handle = mojo_handle
292 def _Invalidate(self):
293 """Invalidate the current handle.
295 The close operation is not called. It is the responsability of the caller to
296 ensure that the handle is not leaked.
298 self._mojo_handle = c_core.MOJO_HANDLE_INVALID
300 def __richcmp__(self, other, op):
301 if op != Py_EQ and op != Py_NE:
302 raise TypeError('Handle is not ordered')
304 if type(self) is not type(other):
305 equality = id(self) == id(other)
307 equality = (<Handle>self)._mojo_handle == (<Handle>other)._mojo_handle
314 """Returns whether this handle is valid."""
315 return self._mojo_handle != c_core.MOJO_HANDLE_INVALID
318 """Closes this handle.
320 See mojo/public/c/system/functions.h
322 cdef c_core.MojoResult result = c_core.MOJO_RESULT_OK
324 result = c_core.MojoClose(self._mojo_handle)
328 def __dealloc__(self):
331 def Wait(self, signals, deadline):
332 """Waits on the given handle.
334 See mojo/public/c/system/functions.h
336 cdef c_core.MojoHandle handle = self._mojo_handle
337 cdef c_core.MojoHandleSignals csignals = signals
338 cdef c_core.MojoDeadline cdeadline = deadline
339 cdef c_core.MojoResult result
341 result = c_core.MojoWait(handle, csignals, cdeadline)
344 def AsyncWait(self, signals, deadline, callback):
345 cdef c_core.MojoHandle handle = self._mojo_handle
346 cdef c_core.MojoHandleSignals csignals = signals
347 cdef c_core.MojoDeadline cdeadline = deadline
348 cdef c_environment.MojoAsyncWaitID wait_id = _ASYNC_WAITER.AsyncWait(
354 _ASYNC_WAITER.CancelWait(wait_id)
357 def WriteMessage(self,
360 flags=WRITE_MESSAGE_FLAG_NONE):
361 """Writes a message to the message pipe.
363 This method can only be used on a handle obtained from |MessagePipe()|.
365 See mojo/public/c/system/message_pipe.h
367 cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer)
368 cdef uint32_t input_buffer_length = buffer_as_buffer.len
369 cdef c_core.MojoHandle* input_handles = NULL
370 cdef uint32_t input_handles_length = 0
371 cdef _ScopedMemory handles_alloc = None
373 input_handles_length = len(handles)
374 handles_alloc = _ScopedMemory(sizeof(c_core.MojoHandle) *
375 input_handles_length)
376 input_handles = <c_core.MojoHandle*>handles_alloc.memory
377 for i in xrange(input_handles_length):
378 input_handles[i] = (<Handle?>handles[i])._mojo_handle
379 cdef c_core.MojoResult res = c_core.MojoWriteMessage(self._mojo_handle,
380 buffer_as_buffer.buf,
383 input_handles_length,
385 if res == c_core.MOJO_RESULT_OK and handles:
386 # Handles have been transferred. Let's invalidate those.
387 for handle in handles:
391 def ReadMessage(self,
393 max_number_of_handles=0,
394 flags=READ_MESSAGE_FLAG_NONE):
395 """Reads a message from the message pipe.
397 This method can only be used on a handle obtained from |MessagePipe()|.
399 This method returns a triplet of value (code, data, sizes):
400 - if code is RESULT_OK, sizes will be None, and data will be a pair of
401 (buffer, handles) where buffer is a view of the input buffer with the read
402 data, and handles is a list of received handles.
403 - if code is RESULT_RESOURCE_EXHAUSTED, data will be None and sizes will be
404 a pair of (buffer_size, handles_size) where buffer_size is the size of the
405 next message data and handles_size is the number of handles in the next
407 - if code is any other value, data and sizes will be None.
409 See mojo/public/c/system/message_pipe.h
411 cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer, PyBUF_CONTIG)
412 cdef uint32_t input_buffer_length = buffer_as_buffer.len
413 cdef c_core.MojoHandle* input_handles = NULL
414 cdef uint32_t input_handles_length = 0
415 cdef _ScopedMemory handles_alloc = None
416 if max_number_of_handles > 0:
417 input_handles_length = max_number_of_handles
418 handles_alloc = _ScopedMemory(sizeof(c_core.MojoHandle) *
419 input_handles_length)
420 input_handles = <c_core.MojoHandle*>handles_alloc.memory
421 cdef res = c_core.MojoReadMessage(self._mojo_handle,
422 buffer_as_buffer.buf,
423 &input_buffer_length,
425 &input_handles_length,
427 if res == c_core.MOJO_RESULT_RESOURCE_EXHAUSTED:
428 return (res, None, (input_buffer_length, input_handles_length))
429 if res == c_core.MOJO_RESULT_OK:
430 returned_handles = [Handle(input_handles[i])
431 for i in xrange(input_handles_length)]
433 (_SliceBuffer(buffer, input_buffer_length), returned_handles),
435 return (res, None, None)
437 def WriteData(self, buffer=None, flags=WRITE_DATA_FLAG_NONE):
439 Writes the given data to the data pipe producer.
441 This method can only be used on a producer handle obtained from
444 This method returns a tuple (code, num_bytes).
445 - If code is RESULT_OK, num_bytes is the number of written bytes.
446 - Otherwise, num_bytes is None.
448 See mojo/public/c/system/data_pipe.h
450 cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer)
451 cdef uint32_t input_buffer_length = buffer_as_buffer.len
452 cdef c_core.MojoResult res = c_core.MojoWriteData(self._mojo_handle,
453 buffer_as_buffer.buf,
454 &input_buffer_length,
456 if res == c_core.MOJO_RESULT_OK:
457 return (res, input_buffer_length)
460 def BeginWriteData(self,
462 flags=WRITE_DATA_FLAG_NONE):
464 Begins a two-phase write to the data pipe producer.
466 This method can only be used on a producer handle obtained from
469 This method returns a tuple (code, two_phase_buffer).
470 - If code is RESULT_OK, two_phase_buffer is a writable
471 DataPipeTwoPhaseBuffer
472 - Otherwise, two_phase_buffer is None.
474 See mojo/public/c/system/data_pipe.h
476 cdef void* out_buffer
477 cdef uint32_t out_size = 0
479 flags |= c_core.MOJO_WRITE_DATA_FLAG_ALL_OR_NONE
481 cdef c_core.MojoResult res = c_core.MojoBeginWriteData(self._mojo_handle,
485 if res != c_core.MOJO_RESULT_OK:
487 cdef _NativeMemoryView view_buffer = _NativeMemoryView(self)
488 view_buffer.Wrap(out_buffer, out_size, read_only=False)
489 return (res, DataPipeTwoPhaseBuffer(self, memoryview(view_buffer), False))
491 def ReadData(self, buffer=None, flags=READ_DATA_FLAG_NONE):
492 """Reads data from the data pipe consumer.
494 This method can only be used on a consumer handle obtained from
497 This method returns a tuple (code, buffer)
498 - if code is RESULT_OK, buffer will be a view of the input buffer with the
500 - otherwise, buffer will be None.
502 See mojo/public/c/system/data_pipe.h
504 cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer)
505 cdef uint32_t input_buffer_length = buffer_as_buffer.len
506 cdef c_core.MojoResult res = c_core.MojoReadData(self._mojo_handle,
507 buffer_as_buffer.buf,
508 &input_buffer_length,
510 if res == c_core.MOJO_RESULT_OK:
511 return (res, _SliceBuffer(buffer, input_buffer_length))
514 def QueryData(self, flags=READ_DATA_FLAG_NONE):
515 """Queries the amount of data available on the data pipe consumer.
517 This method can only be used on a consumer handle obtained from
520 This method returns a tuple (code, num_bytes)
521 - if code is RESULT_OK, num_bytes will be the number of bytes available on
522 the data pipe consumer.
523 - otherwise, num_bytes will be None.
525 See mojo/public/c/system/data_pipe.h
527 cdef uint32_t num_bytes = 0
528 cdef c_core.MojoResult res = c_core.MojoReadData(
532 flags|c_core.MOJO_READ_DATA_FLAG_QUERY)
533 return (res, num_bytes)
535 def BeginReadData(self, min_size=None, flags=READ_DATA_FLAG_NONE):
537 Begins a two-phase read to the data pipe consumer.
539 This method can only be used on a consumer handle obtained from
542 This method returns a tuple (code, two_phase_buffer).
543 - If code is RESULT_OK, two_phase_buffer is a readable
544 DataPipeTwoPhaseBuffer
545 - Otherwise, two_phase_buffer is None.
547 See mojo/public/c/system/data_pipe.h
549 cdef const void* out_buffer
550 cdef uint32_t out_size = 0
552 flags |= c_core.MOJO_READ_DATA_FLAG_ALL_OR_NONE
554 cdef c_core.MojoResult res = c_core.MojoBeginReadData(self._mojo_handle,
558 if res != c_core.MOJO_RESULT_OK:
560 cdef _NativeMemoryView view_buffer = _NativeMemoryView(self)
561 view_buffer.Wrap(out_buffer, out_size, read_only=True)
562 return (res, DataPipeTwoPhaseBuffer(self, memoryview(view_buffer), True))
564 def Duplicate(self, options=None):
565 """Duplicate the shared buffer handle.
567 This method can only be used on a handle obtained from
568 |CreateSharedBuffer()| or |Duplicate()|.
570 See mojo/public/c/system/buffer.h
572 cdef c_core.MojoDuplicateBufferHandleOptions coptions
573 cdef c_core.MojoDuplicateBufferHandleOptions* coptions_ptr = NULL
574 cdef c_core.MojoHandle cnew_handle = c_core.MOJO_HANDLE_INVALID
576 coptions.struct_size = sizeof(c_core.MojoDuplicateBufferHandleOptions)
577 coptions.flags = options.flags
578 coptions_ptr = &coptions
579 cdef c_core.MojoResult result = c_core.MojoDuplicateBufferHandle(
580 self._mojo_handle, coptions_ptr, &cnew_handle)
581 new_handle = Handle(cnew_handle)
582 if result != c_core.MOJO_RESULT_OK:
583 raise MojoException(result)
586 def Map(self, offset, num_bytes, flags=MAP_BUFFER_FLAG_NONE):
587 """Maps the part (at offset |offset| of length |num_bytes|) of the buffer.
589 This method can only be used on a handle obtained from
590 |CreateSharedBuffer()| or |Duplicate()|.
592 This method returns a tuple (code, mapped_buffer).
593 - If code is RESULT_OK, mapped_buffer is a readable/writable
595 - Otherwise, mapped_buffer is None.
597 See mojo/public/c/system/buffer.h
600 res = c_core.MojoMapBuffer(self._mojo_handle,
605 if res != c_core.MOJO_RESULT_OK:
607 cdef _NativeMemoryView view_buffer = _NativeMemoryView(self)
608 view_buffer.Wrap(buffer, num_bytes, read_only=False)
609 return (res, MappedBuffer(self,
610 memoryview(view_buffer),
611 lambda: c_core.MojoUnmapBuffer(buffer)))
613 class CreateMessagePipeOptions(object):
614 """Options for creating a message pipe.
616 See mojo/public/c/system/message_pipe.h
618 FLAG_NONE = c_core.MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE
621 self.flags = CreateMessagePipeOptions.FLAG_NONE
623 class MessagePipe(object):
624 """Creates a message pipe.
626 The two ends of the message pipe are accessible with the members handle0 and
629 See mojo/public/c/system/message_pipe.h
631 def __init__(self, options=None):
632 cdef c_core.MojoCreateMessagePipeOptions coptions
633 cdef c_core.MojoCreateMessagePipeOptions* coptions_ptr = NULL
634 cdef c_core.MojoHandle chandle0 = c_core.MOJO_HANDLE_INVALID
635 cdef c_core.MojoHandle chandle1 = c_core.MOJO_HANDLE_INVALID
637 coptions.struct_size = sizeof(c_core.MojoCreateMessagePipeOptions)
638 coptions.flags = options.flags
639 coptions_ptr = &coptions
640 cdef c_core.MojoResult result = c_core.MojoCreateMessagePipe(coptions_ptr,
643 self.handle0 = Handle(chandle0)
644 self.handle1 = Handle(chandle1)
645 if result != c_core.MOJO_RESULT_OK:
646 raise c_core.MojoException(result)
649 class CreateDataPipeOptions(object):
650 """Options for creating a data pipe.
652 See mojo/public/c/system/data_pipe.h
654 FLAG_NONE = c_core.MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE
655 FLAG_MAY_DISCARD = c_core.MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD
658 self.flags = CreateDataPipeOptions.FLAG_NONE
659 self.element_num_bytes = 1
660 self.capacity_num_bytes = 0
662 class DataPipe(object):
663 """Creates a data pipe.
665 The producer end of the data pipe is accessible with the member
666 producer_handle and the consumer end of the data pipe is accessible with the
667 member cconsumer_handle.
669 See mojo/public/c/system/data_pipe.h
671 def __init__(self, options=None):
672 cdef c_core.MojoCreateDataPipeOptions coptions
673 cdef c_core.MojoCreateDataPipeOptions* coptions_ptr = NULL
674 cdef c_core.MojoHandle cproducer_handle = c_core.MOJO_HANDLE_INVALID
675 cdef c_core.MojoHandle cconsumer_handle = c_core.MOJO_HANDLE_INVALID
677 coptions.struct_size = sizeof(c_core.MojoCreateDataPipeOptions)
678 coptions.flags = options.flags
679 coptions.element_num_bytes = options.element_num_bytes
680 coptions.capacity_num_bytes = options.capacity_num_bytes
681 coptions_ptr = &coptions
682 cdef c_core.MojoResult result = c_core.MojoCreateDataPipe(coptions_ptr,
685 self.producer_handle = Handle(cproducer_handle)
686 self.consumer_handle = Handle(cconsumer_handle)
687 if result != c_core.MOJO_RESULT_OK:
688 raise MojoException(result)
690 class CreateSharedBufferOptions(object):
691 """Options for creating a shared buffer.
693 See mojo/public/c/system/buffer.h
695 FLAG_NONE = c_core.MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE
698 self.flags = CreateSharedBufferOptions.FLAG_NONE
700 def CreateSharedBuffer(num_bytes, options=None):
701 """Creates a buffer of size |num_bytes| bytes that can be shared.
703 See mojo/public/c/system/buffer.h
705 cdef c_core.MojoCreateSharedBufferOptions coptions
706 cdef c_core.MojoCreateSharedBufferOptions* coptions_ptr = NULL
707 cdef c_core.MojoHandle chandle = c_core.MOJO_HANDLE_INVALID
709 coptions.struct_size = sizeof(c_core.MojoCreateSharedBufferOptions)
710 coptions.flags = options.flags
711 coptions_ptr = &coptions
712 cdef c_core.MojoResult result = c_core.MojoCreateSharedBuffer(coptions_ptr,
715 handle = Handle(chandle)
716 if result != c_core.MOJO_RESULT_OK:
717 raise MojoException(result)
720 class DuplicateSharedBufferOptions(object):
721 """Options for duplicating a shared buffer.
723 See mojo/public/c/system/buffer.h
725 FLAG_NONE = c_core.MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE
728 self.flags = DuplicateSharedBufferOptions.FLAG_NONE
731 # Keeps a thread local weak reference to the current run loop.
732 _RUN_LOOPS = threading.local()
735 cdef class RunLoop(object):
736 """RunLoop to use when using asynchronous operations on handles."""
738 cdef c_environment.CRunLoop* c_run_loop
741 assert not <uintptr_t>(c_environment.CRunLoopCurrent())
742 self.c_run_loop = new c_environment.CRunLoop()
743 _RUN_LOOPS.loop = id(self)
745 def __dealloc__(self):
751 if hasattr(_RUN_LOOPS, 'loop'):
752 return ctypes.cast(_RUN_LOOPS.loop, ctypes.py_object).value
756 """Run the runloop until Quit is called."""
757 self.c_run_loop.Run()
759 def RunUntilIdle(self):
760 """Run the runloop until Quit is called or no operation is waiting."""
761 self.c_run_loop.RunUntilIdle()
764 """Quit the runloop."""
765 self.c_run_loop.Quit()
767 def PostDelayedTask(self, runnable, delay=0):
769 Post a task on the runloop. This must be called from the thread owning the
772 cdef c_environment.CClosure closure = c_environment.BuildClosure(runnable)
773 self.c_run_loop.PostDelayedTask(closure, delay)
776 cdef c_environment.CEnvironment* _ENVIRONMENT = new c_environment.CEnvironment()
777 cdef c_environment.PythonAsyncWaiter* _ASYNC_WAITER = new c_environment.PythonAsyncWaiter()