def __init__(cls, name, bases, nmspc): super().__init__(name, bases, nmspc) p_list = [(lambda x: False, lambda x: None)] cls._call_match = Match(p_list) cls._cast_match = Match(p_list) cls._info_match = Match(p_list) patterns = { 'call': [], 'cast': [], 'info': [], } for attr in nmspc.values(): cls._maybe_add_pattern(attr, patterns) for handler_type, type_patterns in patterns.items(): cls._finalize_match(handler_type, type_patterns)
def _finalize_match(cls, handler_type, type_patterns): if not type_patterns: return attr_name = "_{}_match".format(handler_type) type_patterns.sort(key=lambda tp: tp[0]) type_patterns = [tp[1] for tp in type_patterns] m = Match(type_patterns) setattr(cls, attr_name, m)
def __init__(self): self.state = 'init' super().__init__() self.__timeout_coro = None call_match = _atom_match_factory(Atom('$gen_call')) cast_match = _atom_match_factory(Atom('$gen_cast')) self._match = Match([(call_match, self._pre_handle_call), (cast_match, self._pre_handle_cast), (lambda x: True, self._pre_handle_info)])
async def _do_call(self, label, request, timeout=5): calling_pid = self._calling_process.pid_ m_ref = self._node.monitor_process(calling_pid, self._destination_pid) msg = (label, (calling_pid, m_ref), request) await self._node.send(calling_pid, self._destination_pid, msg) def pattern(in_msg): if type(in_msg) != tuple: return False if len(in_msg) != 2: return False if in_msg[0] != m_ref: return False return True match = Match([(pattern, lambda x: x[1])]) res = await self._calling_process.receive(match, timeout) self._node.demonitor_process(calling_pid, self._destination_pid, m_ref) return res
def __init__(self, passive: bool = False) -> None: """ Create a process and register itself. Pid is generated by the node object. :arg passive: Passive process has to handle their ``self.inbox_`` from the user code. Active process will run the poll loop on the inbox and call ``self.handle_one_inbox_message`` for every incoming message. """ self.state = 'init' self.passive_ = passive # type: bool """ Having ``passive=True`` will only wake up this ``Process`` when a message arrives, to handle it, otherwise it will not get any CPU time for any empty polling loops. Having ``passive=False`` will run :py:func:`~Pyrlang.process.Process.process_loop`` polling inbox. """ node_obj = self.node_db.get() self.node_name_ = node_obj.node_name_ # type: str """ Convenience field to see the Node """ self.inbox_ = asyncio.Queue() """ Message queue. Messages are detected by the ``_run`` loop and handled one by one in ``handle_one_inbox_message()``. """ self.__tmp_inbox = asyncio.Queue() # used for selective receives self.pid_ = node_obj.register_new_process(self) """ Process identifier for this object. Remember that when creating a process, it registers itself in the node, and this creates a reference. References prevent an object from being garbage collected. To destroy a process, get rid of this extra reference by calling ``exit()`` and telling it the cause of its death. """ self.is_exiting_ = False self._monitored_by = dict() # type: Dict[Reference, Pid] """ Who monitors us. Either local or remote processes. """ self._monitors = dict() # type: Dict[Reference, Pid] """ Who we monitor. NOTE: For simplicity multiple monitors of same target are not implemented. """ self._links = set() # type: Set[Pid] """ Bi-directional linked process pids. Each linked pid pair is unique hence using a set to store them. """ self._signals = asyncio.Queue() """ Exit (and maybe later other) signals are placed here and handled at safe moments of time between handling messages. """ if not self._match: self._match = Match() LOG.debug("Spawned process %s", self.pid_) if not self.passive_: event_loop = asyncio.get_event_loop() event_loop.create_task(self.process_loop()) event_loop.create_task(self.handle_signals())