1

I encountered some problems while trying to make a synchronous function that calls asynchronous functions.(python 3.6.9, cocotb 1.4.0)

As shown in the following example code. The read_cb function will call read function(in FakeDriver class).

After running, I get the error

yield self._fake_lock() RuntimeError: Task got bad yield: <cocotb.decorators.RunningCoroutine object at 0x7f7fecdbfe10> 

What I want is

init FakerDriver locking... locking done read... addr: 0x01 unlocking... unlocking done read done 
import cocotb import asyncio from cocotb.decorators import coroutine from cocotb.triggers import Event class FakeDriver(): def __init__(self): print("init FakeDriver") self.busy_event = Event("driver_busy") self.busy = False @coroutine def read(self, addr): print("read...") yield self._fake_lock() print("addr: ", addr) self._fake_unlock() print("read done") @coroutine def _fake_lock(self): print("locking...") if self.busy: yield self.busy_event.wait() self.busy_event.clear() self.busy = True print("locking done") def _fake_unlock(self): print("unlocking...") self.busy = False self.busy_event.set() print("unlocking done") def read_cb(): dri = FakeDriver() loop = asyncio.get_event_loop() task = loop.create_task(dri.read("0x01")) ret = loop.run_until_complete(task) loop.close() if __name__ == "__main__": read_cb() 
5
  • What version of python are you using? Are you trying to support an old version of python 3? The @coroutine decorator (of asyncio) is deprecated. And you should use async def syntax instead. This will probably true for the cocotb library too. See docs.python.org/3.8/library/asyncio-task.html#asyncio.coroutine If you are trying to use an old version of python, then you should probably be doing yield from rather than yield. Commented Dec 29, 2021 at 11:06
  • The old version of python is 3.4. In 3.5+ you should use async def and await, and python 3.3 doesn't have asyncio. Commented Dec 29, 2021 at 11:14
  • @Dunes Hi, I am using python3.6.9 cocotb 1.4.0. If using yield from, there will be a error: yield from self._fake_lock() TypeError: iter() returned non-iterator of type 'RunningCoroutine' Commented Dec 29, 2021 at 11:34
  • 1
    Did you try yield from for both coroutines? Also, did you try using stuff like async def read(self, addr) (without @coroutine) and await self._fake_lock()? Again, you'll need to do that for both functions. Commented Dec 29, 2021 at 11:42
  • @Dunes, As you said. It works. Thank you so much for you advice. Commented Dec 30, 2021 at 3:03

1 Answer 1

1

Do not mix up cocotb's own implementation of coroutines with asyncio's. In your case, get rid of the asyncio import completely and, with your oldish cocotb 1.4.0, use cocotb's fork() instead of create_task() (as described in https://docs.cocotb.org/en/v1.4.0/quickstart.html?highlight=fork#parallel-and-sequential-execution).

Before you create lots of new code using the deprecated yield etc. in cocotb, consider upgrading cocotb to 1.6.1 and use async def/await (again from cocotb, not asyncio), and instead of fork(), use start_soon() (see https://docs.cocotb.org/en/v1.6.1/coroutines.html#concurrent-execution and https://www.fossi-foundation.org/2021/10/20/cocotb-1-6-0).

(I now see you also asked this in https://github.com/cocotb/cocotb/issues/2819)

Sign up to request clarification or add additional context in comments.

8 Comments

I'm not writing code from scratch. This project already has a lot of code. Due to historical reasons, I can't upgrade cocotb yet. In the above code, if I change read_cb function todef read_cb(): dri = FakeDriver() ret = cocotb.fork(dri.read("0x22")) there will be an error: File "fake_driver.py", line 66, in read_cb ret = cocotb.fork(dri.read("0x22")) File "/home/pengfei/.local/lib/python3.6/site-packages/cocotb/__init__.py", line 135, in fork return scheduler.add(coro) AttributeError: 'NoneType' object has no attribute 'add' Do you have any advice?
The only way scheduler could be None is if you are not running an HDL simulator. cocotb only runs within an HDL simulator.
@ktb Thank you for your guidance. You're absolutely right. Since this is my first time using cocotb, I don't know this:-)
@ktb Another question, if read_cb function is def read_cb(): dri = FakeDriver() ret = cocotb.fork(dri.read("0x22")). How can I get the return value of the dri.read("0x22") function? The type of ret is RunningCoroutine, not a return value from dri.read("0x22").
fork runs read concurrently and independently, allowing the function calling fork to continue running. You must yield dri.read("0x22") if you want to wait until read finishes running, or you can yield task some time later.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.