|
@@ -2,7 +2,7 @@
|
|
"""Generate coroutine wrappers for block subsystem.
|
|
"""Generate coroutine wrappers for block subsystem.
|
|
|
|
|
|
The program parses one or several concatenated c files from stdin,
|
|
The program parses one or several concatenated c files from stdin,
|
|
-searches for functions with the 'co_wrapper_mixed' specifier
|
|
|
|
|
|
+searches for functions with the 'co_wrapper' specifier
|
|
and generates corresponding wrappers on stdout.
|
|
and generates corresponding wrappers on stdout.
|
|
|
|
|
|
Usage: block-coroutine-wrapper.py generated-file.c FILE.[ch]...
|
|
Usage: block-coroutine-wrapper.py generated-file.c FILE.[ch]...
|
|
@@ -62,10 +62,25 @@ def __init__(self, param_decl: str) -> None:
|
|
|
|
|
|
|
|
|
|
class FuncDecl:
|
|
class FuncDecl:
|
|
- def __init__(self, return_type: str, name: str, args: str) -> None:
|
|
|
|
|
|
+ def __init__(self, return_type: str, name: str, args: str,
|
|
|
|
+ variant: str) -> None:
|
|
self.return_type = return_type.strip()
|
|
self.return_type = return_type.strip()
|
|
self.name = name.strip()
|
|
self.name = name.strip()
|
|
|
|
+ self.struct_name = snake_to_camel(self.name)
|
|
self.args = [ParamDecl(arg.strip()) for arg in args.split(',')]
|
|
self.args = [ParamDecl(arg.strip()) for arg in args.split(',')]
|
|
|
|
+ self.create_only_co = 'mixed' not in variant
|
|
|
|
+
|
|
|
|
+ subsystem, subname = self.name.split('_', 1)
|
|
|
|
+ self.co_name = f'{subsystem}_co_{subname}'
|
|
|
|
+
|
|
|
|
+ t = self.args[0].type
|
|
|
|
+ if t == 'BlockDriverState *':
|
|
|
|
+ bs = 'bs'
|
|
|
|
+ elif t == 'BdrvChild *':
|
|
|
|
+ bs = 'child->bs'
|
|
|
|
+ else:
|
|
|
|
+ bs = 'blk_bs(blk)'
|
|
|
|
+ self.bs = bs
|
|
|
|
|
|
def gen_list(self, format: str) -> str:
|
|
def gen_list(self, format: str) -> str:
|
|
return ', '.join(format.format_map(arg.__dict__) for arg in self.args)
|
|
return ', '.join(format.format_map(arg.__dict__) for arg in self.args)
|
|
@@ -74,8 +89,9 @@ def gen_block(self, format: str) -> str:
|
|
return '\n'.join(format.format_map(arg.__dict__) for arg in self.args)
|
|
return '\n'.join(format.format_map(arg.__dict__) for arg in self.args)
|
|
|
|
|
|
|
|
|
|
-# Match wrappers declared with a co_wrapper_mixed mark
|
|
|
|
-func_decl_re = re.compile(r'^int\s*co_wrapper_mixed\s*'
|
|
|
|
|
|
+# Match wrappers declared with a co_wrapper mark
|
|
|
|
+func_decl_re = re.compile(r'^int\s*co_wrapper'
|
|
|
|
+ r'(?P<variant>(_[a-z][a-z0-9_]*)?)\s*'
|
|
r'(?P<wrapper_name>[a-z][a-z0-9_]*)'
|
|
r'(?P<wrapper_name>[a-z][a-z0-9_]*)'
|
|
r'\((?P<args>[^)]*)\);$', re.MULTILINE)
|
|
r'\((?P<args>[^)]*)\);$', re.MULTILINE)
|
|
|
|
|
|
@@ -84,7 +100,8 @@ def func_decl_iter(text: str) -> Iterator:
|
|
for m in func_decl_re.finditer(text):
|
|
for m in func_decl_re.finditer(text):
|
|
yield FuncDecl(return_type='int',
|
|
yield FuncDecl(return_type='int',
|
|
name=m.group('wrapper_name'),
|
|
name=m.group('wrapper_name'),
|
|
- args=m.group('args'))
|
|
|
|
|
|
+ args=m.group('args'),
|
|
|
|
+ variant=m.group('variant'))
|
|
|
|
|
|
|
|
|
|
def snake_to_camel(func_name: str) -> str:
|
|
def snake_to_camel(func_name: str) -> str:
|
|
@@ -97,24 +114,67 @@ def snake_to_camel(func_name: str) -> str:
|
|
return ''.join(words)
|
|
return ''.join(words)
|
|
|
|
|
|
|
|
|
|
|
|
+def create_mixed_wrapper(func: FuncDecl) -> str:
|
|
|
|
+ """
|
|
|
|
+ Checks if we are already in coroutine
|
|
|
|
+ """
|
|
|
|
+ name = func.co_name
|
|
|
|
+ struct_name = func.struct_name
|
|
|
|
+ return f"""\
|
|
|
|
+int {func.name}({ func.gen_list('{decl}') })
|
|
|
|
+{{
|
|
|
|
+ if (qemu_in_coroutine()) {{
|
|
|
|
+ return {name}({ func.gen_list('{name}') });
|
|
|
|
+ }} else {{
|
|
|
|
+ {struct_name} s = {{
|
|
|
|
+ .poll_state.bs = {func.bs},
|
|
|
|
+ .poll_state.in_progress = true,
|
|
|
|
+
|
|
|
|
+{ func.gen_block(' .{name} = {name},') }
|
|
|
|
+ }};
|
|
|
|
+
|
|
|
|
+ s.poll_state.co = qemu_coroutine_create({name}_entry, &s);
|
|
|
|
+
|
|
|
|
+ return bdrv_poll_co(&s.poll_state);
|
|
|
|
+ }}
|
|
|
|
+}}"""
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def create_co_wrapper(func: FuncDecl) -> str:
|
|
|
|
+ """
|
|
|
|
+ Assumes we are not in coroutine, and creates one
|
|
|
|
+ """
|
|
|
|
+ name = func.co_name
|
|
|
|
+ struct_name = func.struct_name
|
|
|
|
+ return f"""\
|
|
|
|
+int {func.name}({ func.gen_list('{decl}') })
|
|
|
|
+{{
|
|
|
|
+ {struct_name} s = {{
|
|
|
|
+ .poll_state.bs = {func.bs},
|
|
|
|
+ .poll_state.in_progress = true,
|
|
|
|
+
|
|
|
|
+{ func.gen_block(' .{name} = {name},') }
|
|
|
|
+ }};
|
|
|
|
+ assert(!qemu_in_coroutine());
|
|
|
|
+
|
|
|
|
+ s.poll_state.co = qemu_coroutine_create({name}_entry, &s);
|
|
|
|
+
|
|
|
|
+ return bdrv_poll_co(&s.poll_state);
|
|
|
|
+}}"""
|
|
|
|
+
|
|
|
|
+
|
|
def gen_wrapper(func: FuncDecl) -> str:
|
|
def gen_wrapper(func: FuncDecl) -> str:
|
|
assert not '_co_' in func.name
|
|
assert not '_co_' in func.name
|
|
assert func.return_type == 'int'
|
|
assert func.return_type == 'int'
|
|
assert func.args[0].type in ['BlockDriverState *', 'BdrvChild *',
|
|
assert func.args[0].type in ['BlockDriverState *', 'BdrvChild *',
|
|
'BlockBackend *']
|
|
'BlockBackend *']
|
|
|
|
|
|
- subsystem, subname = func.name.split('_', 1)
|
|
|
|
-
|
|
|
|
- name = f'{subsystem}_co_{subname}'
|
|
|
|
|
|
+ name = func.co_name
|
|
|
|
+ struct_name = func.struct_name
|
|
|
|
|
|
- t = func.args[0].type
|
|
|
|
- if t == 'BlockDriverState *':
|
|
|
|
- bs = 'bs'
|
|
|
|
- elif t == 'BdrvChild *':
|
|
|
|
- bs = 'child->bs'
|
|
|
|
- else:
|
|
|
|
- bs = 'blk_bs(blk)'
|
|
|
|
- struct_name = snake_to_camel(name)
|
|
|
|
|
|
+ creation_function = create_mixed_wrapper
|
|
|
|
+ if func.create_only_co:
|
|
|
|
+ creation_function = create_co_wrapper
|
|
|
|
|
|
return f"""\
|
|
return f"""\
|
|
/*
|
|
/*
|
|
@@ -136,23 +196,7 @@ def gen_wrapper(func: FuncDecl) -> str:
|
|
aio_wait_kick();
|
|
aio_wait_kick();
|
|
}}
|
|
}}
|
|
|
|
|
|
-int {func.name}({ func.gen_list('{decl}') })
|
|
|
|
-{{
|
|
|
|
- if (qemu_in_coroutine()) {{
|
|
|
|
- return {name}({ func.gen_list('{name}') });
|
|
|
|
- }} else {{
|
|
|
|
- {struct_name} s = {{
|
|
|
|
- .poll_state.bs = {bs},
|
|
|
|
- .poll_state.in_progress = true,
|
|
|
|
-
|
|
|
|
-{ func.gen_block(' .{name} = {name},') }
|
|
|
|
- }};
|
|
|
|
-
|
|
|
|
- s.poll_state.co = qemu_coroutine_create({name}_entry, &s);
|
|
|
|
-
|
|
|
|
- return bdrv_poll_co(&s.poll_state);
|
|
|
|
- }}
|
|
|
|
-}}"""
|
|
|
|
|
|
+{creation_function(func)}"""
|
|
|
|
|
|
|
|
|
|
def gen_wrappers(input_code: str) -> str:
|
|
def gen_wrappers(input_code: str) -> str:
|