Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(core): remove loop.chan #4348

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 0 additions & 98 deletions core/src/trezor/loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,104 +453,6 @@ def maybe_close(self) -> None:
taker.close()


class chan:
"""
Two-ended channel.
The receiving end pauses until a value to be received is available. The sending end
can choose to wait until the value is received, or it can publish the value without
waiting.

Example:

>>> # in task #1:
>>> signal = loop.chan()
>>> while True:
>>> result = await signal.take()
>>> print("awaited result:", result)

>>> # in task #2:
>>> signal.publish("Published without waiting")
>>> print("publish completed")
>>> await signal.put("Put with await")
>>> print("put completed")

Example Output:

publish completed
awaited result: Published without waiting
awaited result: Put with await
put completed
"""

class Put(Syscall):
def __init__(self, ch: "chan", value: Any) -> None:
self.ch = ch
self.value = value
self.task: Task | None = None

def handle(self, task: Task) -> None:
self.task = task
self.ch._schedule_put(task, self.value)

class Take(Syscall):
def __init__(self, ch: "chan") -> None:
self.ch = ch
self.task: Task | None = None

def handle(self, task: Task) -> None:
self.task = task
self.ch._schedule_take(task)

def __init__(self) -> None:
self.putters: list[tuple[Task | None, Any]] = []
self.takers: list[Task] = []

def put(self, value: Any) -> Awaitable[None]: # type: ignore [awaitable-return-type]
put = chan.Put(self, value)
try:
return (yield put) # type: ignore [awaitable-return-type]
except: # noqa: E722
entry = (put.task, value)
if entry in self.putters:
self.putters.remove(entry)
raise

def take(self) -> Awaitable[Any]: # type: ignore [awaitable-return-type]
take = chan.Take(self)
try:
return (yield take) # type: ignore [awaitable-return-type]
except: # noqa: E722
if take.task in self.takers:
self.takers.remove(take.task)
raise

def publish(self, value: Any) -> None:
if self.takers:
taker = self.takers.pop(0)
schedule(taker, value)
else:
self.putters.append((None, value))

def _schedule_put(self, putter: Task, value: Any) -> bool:
if self.takers:
taker = self.takers.pop(0)
schedule(taker, value)
schedule(putter)
return True
else:
self.putters.append((putter, value))
return False

def _schedule_take(self, taker: Task) -> None:
if self.putters:
putter, value = self.putters.pop(0)
schedule(taker, value)
if putter is not None:
schedule(putter)
else:
self.takers.append(taker)


class spawn(Syscall):
"""Spawn a task asynchronously and get an awaitable reference to it.

Expand Down
16 changes: 6 additions & 10 deletions docs/core/src/event-loop.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,12 @@ is scheduled to run on the next tick.

_Upcoming changes may solve this in relevant cases, by inlining syscall operations._

**`loop.mailbox()`** is an unidirectional communication channel, simplification of Go
channels.

It allows to put a `value` in the channel using `put(value)` on the mailbox instance.
To retrieve the value, use `await` on the same `mailbox` instance.

**`loop.spawn(task)`**: Start the task asynchronously. Return an object that allows
the caller to await its result, or shut the task down.

Expand All @@ -206,13 +212,3 @@ If the task is cancelled (usually by calling `task.close()`), the awaiter receiv

It is also possible to register a synchronous finalizer callback via
`task.set_finalizer`. This is used internally to implement workflow management.

**`loop.chan()`** is a unidirectional communication channel that actually implements two
syscalls:

* **`chan.put()`** sends a value to the channel, and waits until it is picked up
by a taker task.
* **`chan.take()`** waits until a value is sent to the channel and then returns it.

It is possible to put in a value without waiting for a taker, by calling
`chan.publish()`. It is not possible to take a value without waiting.
Loading