Re: [PATCH v8 4/7] scripts: add block-coroutine-wrapper.py
24.09.2020 20:56, Eric Blake wrote: On 9/15/20 11:44 AM, Vladimir Sementsov-Ogievskiy wrote: We have a very frequent pattern of creating coroutine from function with several arguments: +++ b/docs/devel/block-coroutine-wrapper.rst @@ -0,0 +1,54 @@ +=== +block-coroutine-wrapper +=== + +A lot of functions in QEMJ block layer (see ``block/*``) can by called My editor italicized everhting after block/*... +only in coroutine context. Such functions are normally marked by +coroutine_fn specifier. Still, sometimes we need to call them from +non-coroutine context, for this we need to start a coroutine, run the +needed function from it and wait for coroutine finish in +BDRV_POLL_WHILE() loop. To run a coroutine we need a function with one +void* argument. So for each coroutine_fn function, which needs ...through void*. I wonder if you need to use \* to let .rst know that these are literal *, and not markup for a different font style. Although I did not check the actual generated docs to see how they look. Intuitively, `` should have greater priority than *. I now check ./build/docs/devel/block-coroutine-wrapper.html , it looks OK: A lot of functions in QEMU block layer (see block/*) can only be -- Best regards, Vladimir
Re: [PATCH v8 4/7] scripts: add block-coroutine-wrapper.py
On 9/15/20 11:44 AM, Vladimir Sementsov-Ogievskiy wrote: We have a very frequent pattern of creating coroutine from function with several arguments: +++ b/docs/devel/block-coroutine-wrapper.rst @@ -0,0 +1,54 @@ +=== +block-coroutine-wrapper +=== + +A lot of functions in QEMJ block layer (see ``block/*``) can by called My editor italicized everhting after block/*... +only in coroutine context. Such functions are normally marked by +coroutine_fn specifier. Still, sometimes we need to call them from +non-coroutine context, for this we need to start a coroutine, run the +needed function from it and wait for coroutine finish in +BDRV_POLL_WHILE() loop. To run a coroutine we need a function with one +void* argument. So for each coroutine_fn function, which needs ...through void*. I wonder if you need to use \* to let .rst know that these are literal *, and not markup for a different font style. Although I did not check the actual generated docs to see how they look. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3226 Virtualization: qemu.org | libvirt.org
Re: [PATCH v8 4/7] scripts: add block-coroutine-wrapper.py
On 9/23/20 8:00 PM, Eric Blake wrote: There's enough grammar fixes, and the fact that John is working on python cleanups, to make me wonder if we need a v9, or if I should just stage it where it is with any other cleanups as followups. But I'm liking the reduced maintenance burden once it is in, and don't want to drag it out to the point that it needs more rebasing as other things land first. Don't worry about it too much. I'd rather we have a helpful script sooner than later than worry about Python style purity before I have the CI mechanisms for it fully established. (I eyeballed it and it looks like you already use type hints, so I have faith it won't need much cleanup.) Thanks! --js
Re: [PATCH v8 4/7] scripts: add block-coroutine-wrapper.py
On Tue, Sep 15, 2020 at 07:44:08PM +0300, Vladimir Sementsov-Ogievskiy wrote: > create mode 100755 scripts/block-coroutine-wrapper.py Please see docs/devel/build-system.rst "Support scripts" for the preferred way of adding Python scripts to the build system. Mode should be 644 and the interpreter line should be "#! /usr/bin/env python3" (with the space). That way meson will run it under the configured --python= interpreter. > > diff --git a/docs/devel/block-coroutine-wrapper.rst > b/docs/devel/block-coroutine-wrapper.rst > new file mode 100644 > index 00..f7050bbc8f > --- /dev/null > +++ b/docs/devel/block-coroutine-wrapper.rst > @@ -0,0 +1,54 @@ > +=== > +block-coroutine-wrapper > +=== > + > +A lot of functions in QEMJ block layer (see ``block/*``) can by called s/QEMJ/QEMU/ > +only in coroutine context. Such functions are normally marked by > +coroutine_fn specifier. Still, sometimes we need to call them from > +non-coroutine context, for this we need to start a coroutine, run the > +needed function from it and wait for coroutine finish in > +BDRV_POLL_WHILE() loop. To run a coroutine we need a function with one > +void* argument. So for each coroutine_fn function, which needs > +non-coroutine interface, we should define a structure to pack the > +parameters, define a separate function to unpack the parameters and > +call the original function and finally define a new interface function > +with same list of arguments as original one, which will pack the > +parameters into a struct, create a coroutine, run it and wait in > +BDRV_POLL_WHILE() loop. It's boring to create such wrappers by hand, so > +we have a script to generate them. > + > +Usage > += > + > +Assume we have defined ``coroutine_fn`` function > +``bdrv_co_foo()`` and need a non-coroutine interface for it, > +called ``bdrv_foo()``. In this case the script can help. To > +trigger the generation: > + > +1. You need ``bdrv_foo`` declaration somewhere (for example in > + ``block/coroutines.h`` with ``generated_co_wrapper`` mark, > + like this: > + > +.. code-block:: c > + > +int generated_co_wrapper bdrv_foor(); s/foor/foo/ signature.asc Description: PGP signature
Re: [PATCH v8 4/7] scripts: add block-coroutine-wrapper.py
24.09.2020 04:20, Eric Blake wrote: On 9/23/20 7:00 PM, Eric Blake wrote: Tested-by: Eric Blake There's enough grammar fixes, and the fact that John is working on python cleanups, to make me wonder if we need a v9, or if I should just stage it where it is with any other cleanups as followups. But I'm liking the reduced maintenance burden once it is in, and don't want to drag it out to the point that it needs more rebasing as other things land first. Here's what I've squashed in and temporarily pushed to my tree if you want to double-check my rebase work: https://repo.or.cz/qemu/ericb.git/shortlog/refs/heads/master diff --git a/docs/devel/block-coroutine-wrapper.rst b/docs/devel/block-coroutine-wrapper.rst index f7050bbc8fa6..d09fff2cc539 100644 --- a/docs/devel/block-coroutine-wrapper.rst +++ b/docs/devel/block-coroutine-wrapper.rst @@ -2,43 +2,43 @@ block-coroutine-wrapper === -A lot of functions in QEMJ block layer (see ``block/*``) can by called -only in coroutine context. Such functions are normally marked by +A lot of functions in QEMU block layer (see ``block/*``) can only be +called in coroutine context. Such functions are normally marked by the coroutine_fn specifier. Still, sometimes we need to call them from -non-coroutine context, for this we need to start a coroutine, run the +non-coroutine context; for this we need to start a coroutine, run the needed function from it and wait for coroutine finish in BDRV_POLL_WHILE() loop. To run a coroutine we need a function with one -void* argument. So for each coroutine_fn function, which needs +void* argument. So for each coroutine_fn function which needs a non-coroutine interface, we should define a structure to pack the parameters, define a separate function to unpack the parameters and call the original function and finally define a new interface function with same list of arguments as original one, which will pack the parameters into a struct, create a coroutine, run it and wait in -BDRV_POLL_WHILE() loop. It's boring to create such wrappers by hand, so -we have a script to generate them. +BDRV_POLL_WHILE() loop. It's boring to create such wrappers by hand, +so we have a script to generate them. Usage = -Assume we have defined ``coroutine_fn`` function +Assume we have defined the ``coroutine_fn`` function ``bdrv_co_foo()`` and need a non-coroutine interface for it, called ``bdrv_foo()``. In this case the script can help. To trigger the generation: -1. You need ``bdrv_foo`` declaration somewhere (for example in - ``block/coroutines.h`` with ``generated_co_wrapper`` mark, +1. You need ``bdrv_foo`` declaration somewhere (for example, in + ``block/coroutines.h``) with the ``generated_co_wrapper`` mark, like this: .. code-block:: c - int generated_co_wrapper bdrv_foor(); + int generated_co_wrapper bdrv_foo(); 2. You need to feed this declaration to block-coroutine-wrapper script. - For this, add .h (or .c) file with the declaration to + For this, add the .h (or .c) file with the declaration to the ``input: files(...)`` list of ``block_gen_c`` target declaration in ``block/meson.build`` -You are done. On build, coroutine wrappers will be generated in +You are done. During the build, coroutine wrappers will be generated in ``/block/block-gen.c``. Links diff --git a/docs/devel/index.rst b/docs/devel/index.rst index 04773ce076b3..cb0abe1e6988 100644 --- a/docs/devel/index.rst +++ b/docs/devel/index.rst @@ -31,3 +31,4 @@ Contents: reset s390-dasd-ipl clocks + block-coroutine-wrapper diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py index d859c07a5f55..8c0a08d9b020 100755 --- a/scripts/block-coroutine-wrapper.py +++ b/scripts/block-coroutine-wrapper.py @@ -2,7 +2,7 @@ """Generate coroutine wrappers for block subsystem. The program parses one or several concatenated c files from stdin, -searches for functions with 'generated_co_wrapper' specifier +searches for functions with the 'generated_co_wrapper' specifier and generates corresponding wrappers on stdout. Usage: block-coroutine-wrapper.py generated-file.c FILE.[ch]... @@ -39,7 +39,7 @@ def prettify(code: str) -> str: 'BraceWrapping': {'AfterFunction': True}, 'BreakBeforeBraces': 'Custom', 'SortIncludes': False, - 'MaxEmptyLinesToKeep': 2 + 'MaxEmptyLinesToKeep': 2, }) p = subprocess.run(['clang-format', f'-style={style}'], check=True, encoding='utf-8', input=code, @@ -168,7 +168,7 @@ int {func.name}({ func.gen_list('{decl}') }) def gen_wrappers_file(input_code: str) -> str: - res = gen_header() + res = '' for func in func_decl_iter(input_code): res += '\n\n\n' res += gen_wrapper(func) @@ -181,6 +181,7 @@ if __name__ == '__main__': exit(f'Usage: {sys.argv[0]} OUT_FILE.c
Re: [PATCH v8 4/7] scripts: add block-coroutine-wrapper.py
24.09.2020 03:18, Eric Blake wrote: On 9/15/20 11:44 AM, Vladimir Sementsov-Ogievskiy wrote: We have a very frequent pattern of creating coroutine from function with several arguments: +++ b/scripts/block-coroutine-wrapper.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python3 +"""Generate coroutine wrappers for block subsystem. Looking at the generated file after patch 5 is applied,... + +def gen_header(): + copyright = re.sub('^.*Copyright', 'Copyright', __doc__, flags=re.DOTALL) + copyright = re.sub('^(?=.)', ' * ', copyright.strip(), flags=re.MULTILINE) + copyright = re.sub('^$', ' *', copyright, flags=re.MULTILINE) + return f"""\ This generated comment... + + +def gen_wrappers_file(input_code: str) -> str: + res = gen_header() ...is getting inserted into the generated file... + for func in func_decl_iter(input_code): + res += '\n\n\n' + res += gen_wrapper(func) + + return prettify(res) # prettify to wrap long lines + + +if __name__ == '__main__': + if len(sys.argv) < 3: + exit(f'Usage: {sys.argv[0]} OUT_FILE.c IN_FILE.[ch]...') + + with open(sys.argv[1], 'w') as f_out: + for fname in sys.argv[2:]: + with open(fname) as f_in: + f_out.write(gen_wrappers_file(f_in.read())) multiple times. You'll want to hoist the call to gen_header outside the loop over fname in sys.argv[2:]. Right, thanks for fixing. I missed it when rebasing on meson system (and move to calling gen_wrappers_file() several times). Hmm, gen_wrappers_file() is now a bit misleading name, it would better be just gen_wrappers() -- Best regards, Vladimir
Re: [PATCH v8 4/7] scripts: add block-coroutine-wrapper.py
24.09.2020 03:00, Eric Blake wrote: On 9/15/20 3:02 PM, Vladimir Sementsov-Ogievskiy wrote: 15.09.2020 19:44, Vladimir Sementsov-Ogievskiy wrote: We have a very frequent pattern of creating coroutine from function with several arguments: - create structure to pack parameters - create _entry function to call original function taking parameters from struct - do different magic to handle completion: set ret to NOT_DONE or EINPROGRESS or use separate bool field - fill the struct and create coroutine from _entry function and this struct as a parameter - do coroutine enter and BDRV_POLL_WHILE loop Let's reduce code duplication by generating coroutine wrappers. This patch adds scripts/block-coroutine-wrapper.py together with some friends, which will generate functions with declared prototypes marked by 'generated_co_wrapper' specifier. 4. add header with generated_co_wrapper declaration into COROUTINE_HEADERS list in Makefile This phrase is out-of-date. I also see 4 steps here,... Still, no function is now marked, this work is for the following commit. Signed-off-by: Vladimir Sementsov-Ogievskiy --- docs/devel/block-coroutine-wrapper.rst | 54 +++ block/block-gen.h | 49 +++ include/block/block.h | 10 ++ block/meson.build | 8 ++ scripts/block-coroutine-wrapper.py | 187 + 5 files changed, 308 insertions(+) create mode 100644 docs/devel/block-coroutine-wrapper.rst create mode 100644 block/block-gen.h create mode 100755 scripts/block-coroutine-wrapper.py Also needed: diff --git a/docs/devel/index.rst b/docs/devel/index.rst index 04773ce076..cb0abe1e69 100644 --- a/docs/devel/index.rst +++ b/docs/devel/index.rst @@ -31,3 +31,4 @@ Contents: reset s390-dasd-ipl clocks + block-coroutine-wrapper I've squashed that in. +++ b/docs/devel/block-coroutine-wrapper.rst @@ -0,0 +1,54 @@ +=== +block-coroutine-wrapper +=== + +A lot of functions in QEMJ block layer (see ``block/*``) can by called QEMU s/by called only/only be called/ +only in coroutine context. Such functions are normally marked by by the +coroutine_fn specifier. Still, sometimes we need to call them from +non-coroutine context, for this we need to start a coroutine, run the s/context,/context;/ +needed function from it and wait for coroutine finish in in a +BDRV_POLL_WHILE() loop. To run a coroutine we need a function with one +void* argument. So for each coroutine_fn function, which needs needs a +non-coroutine interface, we should define a structure to pack the +parameters, define a separate function to unpack the parameters and +call the original function and finally define a new interface function +with same list of arguments as original one, which will pack the +parameters into a struct, create a coroutine, run it and wait in +BDRV_POLL_WHILE() loop. It's boring to create such wrappers by hand, so +we have a script to generate them. +Usage += + +Assume we have defined ``coroutine_fn`` function +``bdrv_co_foo()`` and need a non-coroutine interface for it, +called ``bdrv_foo()``. In this case the script can help. To +trigger the generation: + +1. You need ``bdrv_foo`` declaration somewhere (for example in + ``block/coroutines.h`` with ``generated_co_wrapper`` mark, + like this: Missing a closing ). + +.. code-block:: c + + int generated_co_wrapper bdrv_foor(); s/foor/foo/ + +2. You need to feed this declaration to block-coroutine-wrapper script. to the block- + For this, add .h (or .c) file with the declaration to + ``input: files(...)`` list of ``block_gen_c`` target declaration in + ``block/meson.build`` + +You are done. On build, coroutine wrappers will be generated in s/On/During the/ +``/block/block-gen.c``. ...but 2 in the .rst. Presumably, the .rst steps belong in the commit message as well. +++ b/block/block-gen.h +++ b/include/block/block.h @@ -10,6 +10,16 @@ #include "block/blockjob.h" #include "qemu/hbitmap.h" +/* + * generated_co_wrapper + * + * Function specifier, which does nothing but marking functions to be s/marking/mark/ + * generated by scripts/block-coroutine-wrapper.py + * + * Read more in docs/devel/block-coroutine-wrapper.rst + */ +#define generated_co_wrapper + /* block.c */ typedef struct BlockDriver BlockDriver; typedef struct BdrvChild BdrvChild; diff --git a/block/meson.build b/block/meson.build index a3e56b7cd1..88ad73583a 100644 --- a/block/meson.build +++ b/block/meson.build @@ -107,6 +107,14 @@ module_block_h = custom_target('module_block.h', command: [module_block_py, '@OUTPUT0@', modsrc]) block_ss.add(module_block_h) +wrapper_py = find_program('../scripts/block-coroutine-wrapper.py') +block_gen_c = custom_target('block-gen.c', + output: 'block-gen.c', +
Re: [PATCH v8 4/7] scripts: add block-coroutine-wrapper.py
On 9/23/20 7:00 PM, Eric Blake wrote: Tested-by: Eric Blake There's enough grammar fixes, and the fact that John is working on python cleanups, to make me wonder if we need a v9, or if I should just stage it where it is with any other cleanups as followups. But I'm liking the reduced maintenance burden once it is in, and don't want to drag it out to the point that it needs more rebasing as other things land first. Here's what I've squashed in and temporarily pushed to my tree if you want to double-check my rebase work: https://repo.or.cz/qemu/ericb.git/shortlog/refs/heads/master diff --git a/docs/devel/block-coroutine-wrapper.rst b/docs/devel/block-coroutine-wrapper.rst index f7050bbc8fa6..d09fff2cc539 100644 --- a/docs/devel/block-coroutine-wrapper.rst +++ b/docs/devel/block-coroutine-wrapper.rst @@ -2,43 +2,43 @@ block-coroutine-wrapper === -A lot of functions in QEMJ block layer (see ``block/*``) can by called -only in coroutine context. Such functions are normally marked by +A lot of functions in QEMU block layer (see ``block/*``) can only be +called in coroutine context. Such functions are normally marked by the coroutine_fn specifier. Still, sometimes we need to call them from -non-coroutine context, for this we need to start a coroutine, run the +non-coroutine context; for this we need to start a coroutine, run the needed function from it and wait for coroutine finish in BDRV_POLL_WHILE() loop. To run a coroutine we need a function with one -void* argument. So for each coroutine_fn function, which needs +void* argument. So for each coroutine_fn function which needs a non-coroutine interface, we should define a structure to pack the parameters, define a separate function to unpack the parameters and call the original function and finally define a new interface function with same list of arguments as original one, which will pack the parameters into a struct, create a coroutine, run it and wait in -BDRV_POLL_WHILE() loop. It's boring to create such wrappers by hand, so -we have a script to generate them. +BDRV_POLL_WHILE() loop. It's boring to create such wrappers by hand, +so we have a script to generate them. Usage = -Assume we have defined ``coroutine_fn`` function +Assume we have defined the ``coroutine_fn`` function ``bdrv_co_foo()`` and need a non-coroutine interface for it, called ``bdrv_foo()``. In this case the script can help. To trigger the generation: -1. You need ``bdrv_foo`` declaration somewhere (for example in - ``block/coroutines.h`` with ``generated_co_wrapper`` mark, +1. You need ``bdrv_foo`` declaration somewhere (for example, in + ``block/coroutines.h``) with the ``generated_co_wrapper`` mark, like this: .. code-block:: c -int generated_co_wrapper bdrv_foor(); +int generated_co_wrapper bdrv_foo(); 2. You need to feed this declaration to block-coroutine-wrapper script. - For this, add .h (or .c) file with the declaration to + For this, add the .h (or .c) file with the declaration to the ``input: files(...)`` list of ``block_gen_c`` target declaration in ``block/meson.build`` -You are done. On build, coroutine wrappers will be generated in +You are done. During the build, coroutine wrappers will be generated in ``/block/block-gen.c``. Links diff --git a/docs/devel/index.rst b/docs/devel/index.rst index 04773ce076b3..cb0abe1e6988 100644 --- a/docs/devel/index.rst +++ b/docs/devel/index.rst @@ -31,3 +31,4 @@ Contents: reset s390-dasd-ipl clocks + block-coroutine-wrapper diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py index d859c07a5f55..8c0a08d9b020 100755 --- a/scripts/block-coroutine-wrapper.py +++ b/scripts/block-coroutine-wrapper.py @@ -2,7 +2,7 @@ """Generate coroutine wrappers for block subsystem. The program parses one or several concatenated c files from stdin, -searches for functions with 'generated_co_wrapper' specifier +searches for functions with the 'generated_co_wrapper' specifier and generates corresponding wrappers on stdout. Usage: block-coroutine-wrapper.py generated-file.c FILE.[ch]... @@ -39,7 +39,7 @@ def prettify(code: str) -> str: 'BraceWrapping': {'AfterFunction': True}, 'BreakBeforeBraces': 'Custom', 'SortIncludes': False, -'MaxEmptyLinesToKeep': 2 +'MaxEmptyLinesToKeep': 2, }) p = subprocess.run(['clang-format', f'-style={style}'], check=True, encoding='utf-8', input=code, @@ -168,7 +168,7 @@ int {func.name}({ func.gen_list('{decl}') }) def gen_wrappers_file(input_code: str) -> str: -res = gen_header() +res = '' for func in func_decl_iter(input_code): res += '\n\n\n' res += gen_wrapper(func) @@ -181,6 +181,7 @@ if __name__ == '__main__': exit(f'Usage: {sys.argv[0]} OUT_FILE.c IN_FILE.[ch]...') with open(sys.argv[1], 'w') as f_out: +
Re: [PATCH v8 4/7] scripts: add block-coroutine-wrapper.py
On 9/15/20 11:44 AM, Vladimir Sementsov-Ogievskiy wrote: We have a very frequent pattern of creating coroutine from function with several arguments: +++ b/scripts/block-coroutine-wrapper.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python3 +"""Generate coroutine wrappers for block subsystem. Looking at the generated file after patch 5 is applied,... + +def gen_header(): +copyright = re.sub('^.*Copyright', 'Copyright', __doc__, flags=re.DOTALL) +copyright = re.sub('^(?=.)', ' * ', copyright.strip(), flags=re.MULTILINE) +copyright = re.sub('^$', ' *', copyright, flags=re.MULTILINE) +return f"""\ This generated comment... + + +def gen_wrappers_file(input_code: str) -> str: +res = gen_header() ...is getting inserted into the generated file... +for func in func_decl_iter(input_code): +res += '\n\n\n' +res += gen_wrapper(func) + +return prettify(res) # prettify to wrap long lines + + +if __name__ == '__main__': +if len(sys.argv) < 3: +exit(f'Usage: {sys.argv[0]} OUT_FILE.c IN_FILE.[ch]...') + +with open(sys.argv[1], 'w') as f_out: +for fname in sys.argv[2:]: +with open(fname) as f_in: +f_out.write(gen_wrappers_file(f_in.read())) multiple times. You'll want to hoist the call to gen_header outside the loop over fname in sys.argv[2:]. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3226 Virtualization: qemu.org | libvirt.org
Re: [PATCH v8 4/7] scripts: add block-coroutine-wrapper.py
On 9/15/20 3:02 PM, Vladimir Sementsov-Ogievskiy wrote: 15.09.2020 19:44, Vladimir Sementsov-Ogievskiy wrote: We have a very frequent pattern of creating coroutine from function with several arguments: - create structure to pack parameters - create _entry function to call original function taking parameters from struct - do different magic to handle completion: set ret to NOT_DONE or EINPROGRESS or use separate bool field - fill the struct and create coroutine from _entry function and this struct as a parameter - do coroutine enter and BDRV_POLL_WHILE loop Let's reduce code duplication by generating coroutine wrappers. This patch adds scripts/block-coroutine-wrapper.py together with some friends, which will generate functions with declared prototypes marked by 'generated_co_wrapper' specifier. 4. add header with generated_co_wrapper declaration into COROUTINE_HEADERS list in Makefile This phrase is out-of-date. I also see 4 steps here,... Still, no function is now marked, this work is for the following commit. Signed-off-by: Vladimir Sementsov-Ogievskiy --- docs/devel/block-coroutine-wrapper.rst | 54 +++ block/block-gen.h | 49 +++ include/block/block.h | 10 ++ block/meson.build | 8 ++ scripts/block-coroutine-wrapper.py | 187 + 5 files changed, 308 insertions(+) create mode 100644 docs/devel/block-coroutine-wrapper.rst create mode 100644 block/block-gen.h create mode 100755 scripts/block-coroutine-wrapper.py Also needed: diff --git a/docs/devel/index.rst b/docs/devel/index.rst index 04773ce076..cb0abe1e69 100644 --- a/docs/devel/index.rst +++ b/docs/devel/index.rst @@ -31,3 +31,4 @@ Contents: reset s390-dasd-ipl clocks + block-coroutine-wrapper I've squashed that in. +++ b/docs/devel/block-coroutine-wrapper.rst @@ -0,0 +1,54 @@ +=== +block-coroutine-wrapper +=== + +A lot of functions in QEMJ block layer (see ``block/*``) can by called QEMU s/by called only/only be called/ +only in coroutine context. Such functions are normally marked by by the +coroutine_fn specifier. Still, sometimes we need to call them from +non-coroutine context, for this we need to start a coroutine, run the s/context,/context;/ +needed function from it and wait for coroutine finish in in a +BDRV_POLL_WHILE() loop. To run a coroutine we need a function with one +void* argument. So for each coroutine_fn function, which needs needs a +non-coroutine interface, we should define a structure to pack the +parameters, define a separate function to unpack the parameters and +call the original function and finally define a new interface function +with same list of arguments as original one, which will pack the +parameters into a struct, create a coroutine, run it and wait in +BDRV_POLL_WHILE() loop. It's boring to create such wrappers by hand, so +we have a script to generate them. +Usage += + +Assume we have defined ``coroutine_fn`` function +``bdrv_co_foo()`` and need a non-coroutine interface for it, +called ``bdrv_foo()``. In this case the script can help. To +trigger the generation: + +1. You need ``bdrv_foo`` declaration somewhere (for example in + ``block/coroutines.h`` with ``generated_co_wrapper`` mark, + like this: Missing a closing ). + +.. code-block:: c + +int generated_co_wrapper bdrv_foor(); s/foor/foo/ + +2. You need to feed this declaration to block-coroutine-wrapper script. to the block- + For this, add .h (or .c) file with the declaration to + ``input: files(...)`` list of ``block_gen_c`` target declaration in + ``block/meson.build`` + +You are done. On build, coroutine wrappers will be generated in s/On/During the/ +``/block/block-gen.c``. ...but 2 in the .rst. Presumably, the .rst steps belong in the commit message as well. +++ b/block/block-gen.h +++ b/include/block/block.h @@ -10,6 +10,16 @@ #include "block/blockjob.h" #include "qemu/hbitmap.h" +/* + * generated_co_wrapper + * + * Function specifier, which does nothing but marking functions to be s/marking/mark/ + * generated by scripts/block-coroutine-wrapper.py + * + * Read more in docs/devel/block-coroutine-wrapper.rst + */ +#define generated_co_wrapper + /* block.c */ typedef struct BlockDriver BlockDriver; typedef struct BdrvChild BdrvChild; diff --git a/block/meson.build b/block/meson.build index a3e56b7cd1..88ad73583a 100644 --- a/block/meson.build +++ b/block/meson.build @@ -107,6 +107,14 @@ module_block_h = custom_target('module_block.h', command: [module_block_py, '@OUTPUT0@', modsrc]) block_ss.add(module_block_h) +wrapper_py = find_program('../scripts/block-coroutine-wrapper.py') +block_gen_c = custom_target('block-gen.c', +output: 'block-gen.c', +input:
Re: [PATCH v8 4/7] scripts: add block-coroutine-wrapper.py
15.09.2020 19:44, Vladimir Sementsov-Ogievskiy wrote: We have a very frequent pattern of creating coroutine from function with several arguments: - create structure to pack parameters - create _entry function to call original function taking parameters from struct - do different magic to handle completion: set ret to NOT_DONE or EINPROGRESS or use separate bool field - fill the struct and create coroutine from _entry function and this struct as a parameter - do coroutine enter and BDRV_POLL_WHILE loop Let's reduce code duplication by generating coroutine wrappers. This patch adds scripts/block-coroutine-wrapper.py together with some friends, which will generate functions with declared prototypes marked by 'generated_co_wrapper' specifier. The usage of new code generation is as follows: 1. define somewhere int coroutine_fn bdrv_co_NAME(...) {...} function 2. declare in some header file int generated_co_wrapper bdrv_NAME(...); function with same list of parameters. (you'll need to include "block/generated-co-wrapper.h" to get the specifier) 3. both declarations should be available through block/coroutines.h header. 4. add header with generated_co_wrapper declaration into COROUTINE_HEADERS list in Makefile Still, no function is now marked, this work is for the following commit. Signed-off-by: Vladimir Sementsov-Ogievskiy --- docs/devel/block-coroutine-wrapper.rst | 54 +++ block/block-gen.h | 49 +++ include/block/block.h | 10 ++ block/meson.build | 8 ++ scripts/block-coroutine-wrapper.py | 187 + 5 files changed, 308 insertions(+) create mode 100644 docs/devel/block-coroutine-wrapper.rst create mode 100644 block/block-gen.h create mode 100755 scripts/block-coroutine-wrapper.py Also needed: diff --git a/docs/devel/index.rst b/docs/devel/index.rst index 04773ce076..cb0abe1e69 100644 --- a/docs/devel/index.rst +++ b/docs/devel/index.rst @@ -31,3 +31,4 @@ Contents: reset s390-dasd-ipl clocks + block-coroutine-wrapper -- Best regards, Vladimir