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