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 |