Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / mojo / public / python / mojo / system.pyx
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 cpython.object cimport Py_EQ, Py_NE
19 from libc.stdint cimport int32_t, int64_t, uint32_t, uint64_t, uintptr_t
20
21 import ctypes
22 import threading
23
24 def SetSystemThunks(system_thunks_as_object):
25   """Bind the basic Mojo Core functions.
26
27   This should only be used by the embedder.
28   """
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)
32
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
66
67 def GetTimeTicksNow():
68   """Monotonically increasing tick count representing "right now."
69
70   See mojo/public/c/system/functions.h
71   """
72   return c_core.MojoGetTimeTicksNow()
73
74 cdef class _ScopedMemory:
75   """Allocate memory at creation, and deallocate it at destruction."""
76   cdef void* memory
77   def __init__(self, size):
78     self.memory = PyMem_Malloc(size)
79
80   def __dealloc__(self):
81     PyMem_Free(self.memory)
82
83 cdef class _ScopedBuffer:
84   """Retrieve pointer to a buffer a creation, and release it at destruction.
85   """
86   cdef Py_buffer _buf
87   cdef void* buf
88   cdef Py_ssize_t len
89
90   def __init__(self, obj, flags=PyBUF_CONTIG_RO):
91     if obj:
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
96     else:
97       self.buf = NULL
98       self.len = 0
99
100   def __dealloc__(self):
101     if self.buf:
102       PyBuffer_Release(&self._buf)
103
104 def _SliceBuffer(buffer, size):
105   """Slice the given buffer, reducing it to the given size.
106
107   Return None if None is passed in.
108   """
109   if not buffer:
110     return buffer
111   return buffer[:size]
112
113 cdef class _NativeMemoryView(object):
114   """Create a python buffer wrapping the given memory.
115
116   Will also retain the given handle until this object is deallocated.
117   """
118   cdef void* _memory
119   cdef uint32_t _size
120   cdef char _read_only
121   cdef char _wrapped
122   cdef object _handle
123
124   def __init__(self, handle):
125     self._handle = handle
126
127   def __cinit__(self):
128     self._memory = NULL
129     self._size = 0
130     self._read_only = True
131     self._wrapped = False
132
133   cdef Wrap(self,
134             const void* memory,
135             uint32_t size,
136             read_only=True):
137     """Makes this buffer wraps the given memory.
138
139     Must be called before using this buffer, and must only be called once.
140     """
141     assert not self._wrapped
142     self._wrapped = True
143     self._memory = <void*>memory
144     self._size = size
145     self._read_only = read_only
146
147   # buffer interface (PEP 3118)
148   def __getbuffer__(self, Py_buffer *view, int flags):
149     assert self._wrapped
150     if view == NULL:
151       return
152     PyBuffer_FillInfo(view,
153                       self,
154                       self._memory,
155                       self._size,
156                       self._read_only,
157                       flags)
158
159   def __releasebuffer__(self, Py_buffer *view):
160     assert self._wrapped
161     pass
162
163   # legacy buffer interface
164   def __getsegcount__(self, Py_ssize_t *sizes):
165     assert self._wrapped
166     if sizes != NULL:
167       sizes[0] = self._size
168     return 1
169
170   def __getreadbuffer__(self, Py_ssize_t index, void **data):
171     assert self._wrapped
172     if index != 0:
173       raise SystemError('Index out of bounds: %d' % index)
174     data[0] = self._memory
175     return self._size
176
177   def __getwritebuffer__(self, Py_ssize_t index, void **data):
178     assert self._wrapped
179     if index != 0:
180       raise SystemError('Index out of bounds: %d' % index)
181     if self._read_only:
182       raise TypeError('Buffer is read-only.')
183     data[0] = self._memory
184     return self._size
185
186 class MojoException(Exception):
187   """Exception wrapping a mojo result error code."""
188
189   def __init__(self, mojo_result):
190     self.mojo_result = mojo_result
191
192 def WaitMany(handles_and_signals, deadline):
193   """Waits on a list of handles.
194
195   Args:
196     handles_and_signals: list of tuples of handle and signal.
197
198   See mojo/public/c/system/functions.h
199   """
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)
208   cdef int index = 0
209   for (h, s) in handles_and_signals:
210     handles[index] = (<Handle?>h)._mojo_handle
211     signals[index] = s
212     index += 1
213   cdef c_core.MojoResult result = c_core.MOJO_RESULT_OK
214   cdef c_core.MojoDeadline cdeadline = deadline
215   with nogil:
216     result = c_core.MojoWaitMany(handles, signals, length, cdeadline)
217   return result
218
219 cdef class DataPipeTwoPhaseBuffer(object):
220   """Return value for two phases read and write.
221
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.
225   """
226
227   cdef object _buffer
228   cdef Handle _handle
229   cdef char _read
230
231   def __init__(self, handle, buffer, read=True):
232     self._buffer = buffer
233     self._handle = handle
234     self._read = read
235
236   def End(self, num_bytes):
237     self._buffer = None
238     cdef c_core.MojoResult result
239     if self._read:
240       result = c_core.MojoEndReadData(self._handle._mojo_handle, num_bytes)
241     else:
242       result = c_core.MojoEndWriteData(self._handle._mojo_handle, num_bytes)
243     self._handle = None
244     return result
245
246   @property
247   def buffer(self):
248     return self._buffer
249
250   def __dealloc__(self):
251     assert not self._buffer
252
253 cdef class MappedBuffer(object):
254   """Return value for the |map| operation on shared buffer handles.
255
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.
258   """
259
260   cdef object _buffer
261   cdef object _handle
262   cdef object _cleanup
263
264   def __init__(self, handle, buffer, cleanup):
265     self._buffer = buffer
266     self._handle = handle
267     self._cleanup = cleanup
268
269   def UnMap(self):
270     self._buffer = None
271     cdef c_core.MojoResult result = self._cleanup()
272     self._cleanup = None
273     self._handle = None
274     return result
275
276   @property
277   def buffer(self):
278     return self._buffer
279
280   def __dealloc__(self):
281     if self._buffer:
282       self.UnMap()
283
284 cdef class Handle(object):
285   """A mojo object."""
286
287   cdef c_core.MojoHandle _mojo_handle
288
289   def __init__(self, mojo_handle=c_core.MOJO_HANDLE_INVALID):
290     self._mojo_handle = mojo_handle
291
292   def _Invalidate(self):
293     """Invalidate the current handle.
294
295     The close operation is not called. It is the responsability of the caller to
296     ensure that the handle is not leaked.
297     """
298     self._mojo_handle = c_core.MOJO_HANDLE_INVALID
299
300   def __richcmp__(self, other, op):
301     if op != Py_EQ and op != Py_NE:
302       raise TypeError('Handle is not ordered')
303     cdef int equality
304     if type(self) is not type(other):
305       equality = id(self) == id(other)
306     else:
307       equality = (<Handle>self)._mojo_handle == (<Handle>other)._mojo_handle
308     if op == Py_EQ:
309       return equality
310     else:
311       return not equality
312
313   def IsValid(self):
314     """Returns whether this handle is valid."""
315     return self._mojo_handle != c_core.MOJO_HANDLE_INVALID
316
317   def Close(self):
318     """Closes this handle.
319
320     See mojo/public/c/system/functions.h
321     """
322     cdef c_core.MojoResult result = c_core.MOJO_RESULT_OK
323     if self.IsValid():
324       result = c_core.MojoClose(self._mojo_handle)
325       self._Invalidate()
326     return result
327
328   def __dealloc__(self):
329     self.Close()
330
331   def Wait(self, signals, deadline):
332     """Waits on the given handle.
333
334     See mojo/public/c/system/functions.h
335     """
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
340     with nogil:
341       result = c_core.MojoWait(handle, csignals, cdeadline)
342     return result
343
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(
349         handle,
350         csignals,
351         cdeadline,
352         callback)
353     def cancel():
354       _ASYNC_WAITER.CancelWait(wait_id)
355     return cancel
356
357   def WriteMessage(self,
358                     buffer=None,
359                     handles=None,
360                     flags=WRITE_MESSAGE_FLAG_NONE):
361     """Writes a message to the message pipe.
362
363     This method can only be used on a handle obtained from |MessagePipe()|.
364
365     See mojo/public/c/system/message_pipe.h
366     """
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
372     if handles:
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,
381                                                          input_buffer_length,
382                                                          input_handles,
383                                                          input_handles_length,
384                                                          flags)
385     if res == c_core.MOJO_RESULT_OK and handles:
386       # Handles have been transferred. Let's invalidate those.
387       for handle in handles:
388         handle._Invalidate()
389     return res
390
391   def ReadMessage(self,
392                    buffer=None,
393                    max_number_of_handles=0,
394                    flags=READ_MESSAGE_FLAG_NONE):
395     """Reads a message from the message pipe.
396
397     This method can only be used on a handle obtained from |MessagePipe()|.
398
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
406       message.
407     - if code is any other value, data and sizes will be None.
408
409     See mojo/public/c/system/message_pipe.h
410     """
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,
424                                       input_handles,
425                                       &input_handles_length,
426                                       flags)
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)]
432       return (res,
433               (_SliceBuffer(buffer, input_buffer_length), returned_handles),
434               None)
435     return (res, None, None)
436
437   def WriteData(self, buffer=None, flags=WRITE_DATA_FLAG_NONE):
438     """
439     Writes the given data to the data pipe producer.
440
441     This method can only be used on a producer handle obtained from
442     |DataPipe()|.
443
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.
447
448     See mojo/public/c/system/data_pipe.h
449     """
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,
455                                                       flags)
456     if res == c_core.MOJO_RESULT_OK:
457       return (res, input_buffer_length)
458     return (res, None)
459
460   def BeginWriteData(self,
461                        min_size=None,
462                        flags=WRITE_DATA_FLAG_NONE):
463     """
464     Begins a two-phase write to the data pipe producer.
465
466     This method can only be used on a producer handle obtained from
467     |DataPipe()|.
468
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.
473
474     See mojo/public/c/system/data_pipe.h
475     """
476     cdef void* out_buffer
477     cdef uint32_t out_size = 0
478     if min_size:
479       flags |= c_core.MOJO_WRITE_DATA_FLAG_ALL_OR_NONE
480       out_size = min_size
481     cdef c_core.MojoResult res = c_core.MojoBeginWriteData(self._mojo_handle,
482                                                            &out_buffer,
483                                                            &out_size,
484                                                            flags)
485     if res != c_core.MOJO_RESULT_OK:
486       return (res, None)
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))
490
491   def ReadData(self, buffer=None, flags=READ_DATA_FLAG_NONE):
492     """Reads data from the data pipe consumer.
493
494     This method can only be used on a consumer handle obtained from
495     |DataPipe()|.
496
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
499       read data.
500     - otherwise, buffer will be None.
501
502     See mojo/public/c/system/data_pipe.h
503     """
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,
509                                                      flags)
510     if res == c_core.MOJO_RESULT_OK:
511       return (res, _SliceBuffer(buffer, input_buffer_length))
512     return (res, None)
513
514   def QueryData(self, flags=READ_DATA_FLAG_NONE):
515     """Queries the amount of data available on the data pipe consumer.
516
517     This method can only be used on a consumer handle obtained from
518     |DataPipe()|.
519
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.
524
525     See mojo/public/c/system/data_pipe.h
526     """
527     cdef uint32_t num_bytes = 0
528     cdef c_core.MojoResult res = c_core.MojoReadData(
529         self._mojo_handle,
530         NULL,
531         &num_bytes,
532         flags|c_core.MOJO_READ_DATA_FLAG_QUERY)
533     return (res, num_bytes)
534
535   def BeginReadData(self, min_size=None, flags=READ_DATA_FLAG_NONE):
536     """
537     Begins a two-phase read to the data pipe consumer.
538
539     This method can only be used on a consumer handle obtained from
540     |DataPipe()|.
541
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.
546
547     See mojo/public/c/system/data_pipe.h
548     """
549     cdef const void* out_buffer
550     cdef uint32_t out_size = 0
551     if min_size:
552       flags |= c_core.MOJO_READ_DATA_FLAG_ALL_OR_NONE
553       out_size = min_size
554     cdef c_core.MojoResult res = c_core.MojoBeginReadData(self._mojo_handle,
555                                                           &out_buffer,
556                                                           &out_size,
557                                                           flags)
558     if res != c_core.MOJO_RESULT_OK:
559       return (res, None)
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))
563
564   def Duplicate(self, options=None):
565     """Duplicate the shared buffer handle.
566
567     This method can only be used on a handle obtained from
568     |CreateSharedBuffer()| or |Duplicate()|.
569
570     See mojo/public/c/system/buffer.h
571     """
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
575     if options:
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)
584     return new_handle
585
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.
588
589     This method can only be used on a handle obtained from
590     |CreateSharedBuffer()| or |Duplicate()|.
591
592     This method returns a tuple (code, mapped_buffer).
593     - If code is RESULT_OK, mapped_buffer is a readable/writable
594       MappedBuffer
595     - Otherwise, mapped_buffer is None.
596
597     See mojo/public/c/system/buffer.h
598     """
599     cdef void* buffer
600     res = c_core.MojoMapBuffer(self._mojo_handle,
601                                offset,
602                                num_bytes,
603                                &buffer,
604                                flags)
605     if res != c_core.MOJO_RESULT_OK:
606       return (res, None)
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)))
612
613 class CreateMessagePipeOptions(object):
614   """Options for creating a message pipe.
615
616   See mojo/public/c/system/message_pipe.h
617   """
618   FLAG_NONE = c_core.MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE
619
620   def __init__(self):
621     self.flags = CreateMessagePipeOptions.FLAG_NONE
622
623 class MessagePipe(object):
624   """Creates a message pipe.
625
626   The two ends of the message pipe are accessible with the members handle0 and
627   handle1.
628
629   See mojo/public/c/system/message_pipe.h
630   """
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
636     if options:
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,
641                                                                  &chandle0,
642                                                                  &chandle1)
643     self.handle0 = Handle(chandle0)
644     self.handle1 = Handle(chandle1)
645     if result != c_core.MOJO_RESULT_OK:
646       raise c_core.MojoException(result)
647
648
649 class CreateDataPipeOptions(object):
650   """Options for creating a data pipe.
651
652   See mojo/public/c/system/data_pipe.h
653   """
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
656
657   def __init__(self):
658     self.flags = CreateDataPipeOptions.FLAG_NONE
659     self.element_num_bytes = 1
660     self.capacity_num_bytes = 0
661
662 class DataPipe(object):
663   """Creates a data pipe.
664
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.
668
669   See mojo/public/c/system/data_pipe.h
670   """
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
676     if options:
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,
683                                                               &cproducer_handle,
684                                                               &cconsumer_handle)
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)
689
690 class CreateSharedBufferOptions(object):
691   """Options for creating a shared buffer.
692
693   See mojo/public/c/system/buffer.h
694   """
695   FLAG_NONE = c_core.MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE
696
697   def __init__(self):
698     self.flags = CreateSharedBufferOptions.FLAG_NONE
699
700 def CreateSharedBuffer(num_bytes, options=None):
701   """Creates a buffer of size |num_bytes| bytes that can be shared.
702
703   See mojo/public/c/system/buffer.h
704   """
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
708   if options:
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,
713                                                                 num_bytes,
714                                                                 &chandle)
715   handle = Handle(chandle)
716   if result != c_core.MOJO_RESULT_OK:
717     raise MojoException(result)
718   return handle
719
720 class DuplicateSharedBufferOptions(object):
721   """Options for duplicating a shared buffer.
722
723   See mojo/public/c/system/buffer.h
724   """
725   FLAG_NONE = c_core.MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE
726
727   def __init__(self):
728     self.flags = DuplicateSharedBufferOptions.FLAG_NONE
729
730
731 # Keeps a thread local weak reference to the current run loop.
732 _RUN_LOOPS = threading.local()
733
734
735 cdef class RunLoop(object):
736   """RunLoop to use when using asynchronous operations on handles."""
737
738   cdef c_environment.CRunLoop* c_run_loop
739
740   def __init__(self):
741     assert not <uintptr_t>(c_environment.CRunLoopCurrent())
742     self.c_run_loop = new c_environment.CRunLoop()
743     _RUN_LOOPS.loop = id(self)
744
745   def __dealloc__(self):
746     del _RUN_LOOPS.loop
747     del self.c_run_loop
748
749   @staticmethod
750   def Current():
751     if hasattr(_RUN_LOOPS, 'loop'):
752       return ctypes.cast(_RUN_LOOPS.loop, ctypes.py_object).value
753     return None
754
755   def Run(self):
756     """Run the runloop until Quit is called."""
757     self.c_run_loop.Run()
758
759   def RunUntilIdle(self):
760     """Run the runloop until Quit is called or no operation is waiting."""
761     self.c_run_loop.RunUntilIdle()
762
763   def Quit(self):
764     """Quit the runloop."""
765     self.c_run_loop.Quit()
766
767   def PostDelayedTask(self, runnable, delay=0):
768     """
769     Post a task on the runloop. This must be called from the thread owning the
770     runloop.
771     """
772     cdef c_environment.CClosure closure = c_environment.BuildClosure(runnable)
773     self.c_run_loop.PostDelayedTask(closure, delay)
774
775
776 cdef c_environment.CEnvironment* _ENVIRONMENT = new c_environment.CEnvironment()
777 cdef c_environment.PythonAsyncWaiter* _ASYNC_WAITER = new c_environment.PythonAsyncWaiter()