Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Kill popping_{enum,generated}
[simgrid.git] / src / simix / simcalls.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3
4 # Copyright (c) 2014-2022. The SimGrid Team. All rights reserved.
5
6 # This program is free software; you can redistribute it and/or modify it
7 # under the terms of the license (GNU LGPL) which comes with this package.
8
9 import re
10 import glob
11 import sys
12
13 class Arg:
14
15     def __init__(self, name, thetype):
16         self.name = name
17         self.type = thetype
18         self.simcall_types = []
19
20     def field(self):
21         return self.simcall_types[self.type]
22
23     def rettype(self):
24         return self.type
25
26
27 class Simcall:
28     simcalls_pre = None
29
30     def __init__(self, name, handler, res, args, call_kind):
31         self.name = name
32         self.res = res
33         self.args = args
34         self.need_handler = handler
35         self.call_kind = call_kind
36
37     def check(self):
38         # smx_*.c void simcall_HANDLER_host_on(smx_simcall_t simcall,
39         # smx_host_t h)
40         if self.simcalls_pre is None:
41             self.simcalls_pre = set()
42             for fn in glob.glob('smx_*') + glob.glob('../kernel/actor/ActorImpl*') + \
43                     glob.glob('../mc/*cpp') + glob.glob('../kernel/activity/*cpp'):
44                 f = open(fn)
45                 self.simcalls_pre |= set(re.findall(r'simcall_HANDLER_(.*?)\(', f.read()))
46                 f.close()
47         if self.need_handler:
48             if self.name not in self.simcalls_pre:
49                 print('# ERROR: No function called simcall_HANDLER_%s' % self.name)
50                 print('# Add something like this to the relevant C file (like smx_io.c if it\'s an IO call):')
51                 print('%s simcall_HANDLER_%s(smx_simcall_t simcall%s)' % (self.res.rettype(), self.name, ''.
52                                                                           join(', %s %s' % (arg.rettype(), arg.name)for arg in self.args)))
53                 print('{')
54                 print('  // Your code handling the simcall')
55                 print('}')
56                 return False
57         else:
58             if self.name in self.simcalls_pre:
59                 print(
60                     '# ERROR: You have a function called simcall_HANDLER_%s, but that simcall is not using any handler' %
61                     self.name)
62                 print('# Either change your simcall definition, or kill that function')
63                 return False
64         return True
65
66     def string(self):
67         return '    "Simcall::%s",' % self.name.upper()
68
69     def accessors(self):
70         res = []
71         res.append('')
72         regex = re.compile(r"^boost::intrusive_ptr<(.*?)>(.*)$")  # to compute the raw type
73         # Arguments getter/setters
74         for i, arg in enumerate(self.args):
75             rawtype = regex.sub(r'\1*\2', arg.rettype())
76             res.append('static inline %s simcall_%s__get__%s(smx_simcall_t simcall)' % (
77                 arg.rettype(), self.name, arg.name))
78             res.append('{')
79             res.append('  return simgrid::simix::unmarshal<%s>(simcall->args_[%i]);' % (arg.rettype(), i))
80             res.append('}')
81             res.append('static inline %s simcall_%s__getraw__%s(smx_simcall_t simcall)' % (
82                 rawtype, self.name, arg.name))
83             res.append('{')
84             res.append('  return simgrid::simix::unmarshal_raw<%s>(simcall->args_[%i]);' % (rawtype, i))
85             res.append('}')
86             res.append('static inline void simcall_%s__set__%s(smx_simcall_t simcall, %s arg)' % (
87                 self.name, arg.name, arg.rettype()))
88             res.append('{')
89             res.append('  simgrid::simix::marshal<%s>(simcall->args_[%i], arg);' % (arg.rettype(), i))
90             res.append('}')
91
92         # Return value getter/setters
93         if self.res.type != 'void':
94             rawtype = regex.sub(r'\1*\2', self.res.rettype())
95             res.append(
96                 'static inline %s simcall_%s__get__result(smx_simcall_t simcall)' % (self.res.rettype(), self.name))
97             res.append('{')
98             res.append('  return simgrid::simix::unmarshal<%s>(simcall->result_);' % self.res.rettype())
99             res.append('}')
100             res.append('static inline %s simcall_%s__getraw__result(smx_simcall_t simcall)' % (rawtype, self.name))
101             res.append('{')
102             res.append('  return simgrid::simix::unmarshal_raw<%s>(simcall->result_);' % rawtype)
103             res.append('}')
104             res.append(
105                 'static inline void simcall_%s__set__result(smx_simcall_t simcall, %s result)' % (self.name, self.res.rettype()))
106             res.append('{')
107             res.append('  simgrid::simix::marshal<%s>(simcall->result_, result);' % (self.res.rettype()))
108             res.append('}')
109         return '\n'.join(res)
110
111     def case(self):
112         res = []
113         indent = '    '
114         args = ["simcall_.code_"]
115         res.append(indent + 'case Simcall::%s:' % (self.name.upper()))
116         if self.need_handler:
117             call = "simcall_HANDLER_%s(&simcall_%s%s)" % (self.name,
118                                                           ", " if args else "",
119                                                           ', '.join(args))
120         else:
121             call = "SIMIX_%s(%s)" % (self.name, ', '.join(args))
122         res.append(indent + "  " + call + ";")
123         if self.call_kind != 'Blck':
124             res.append(indent + '  simcall_answer();')
125         res.append(indent + '  break;')
126         res.append('')
127         return '\n'.join(res)
128
129     def handler_prototype(self):
130         if self.need_handler:
131             return "XBT_PRIVATE void simcall_HANDLER_%s(smx_simcall_t simcall%s);" % (self.name,
132                                                                                     ''.join(', %s %s' % (arg.rettype(), arg.name)
133                                                                                             for i, arg in enumerate(self.args)))
134         return ""
135
136
137 def parse(fn):
138     simcalls = []
139     resdi = None
140     simcalls_guarded = {}
141     for line in open(fn).read().split('\n'):
142         if line.startswith('##'):
143             resdi = []
144             simcalls_guarded[re.search(r'## *(.*)', line).group(1)] = resdi
145         if line.startswith('#') or not line:
146             continue
147         match = re.match(
148             r'^(\S+)\s+([^\)\(\s]+)\s*\(*(.*)\)\s*(\[\[.*\]\])?\s*;\s*$', line)
149         if not match:
150             raise AssertionError(line)
151         ret, name, args, attrs = match.groups()
152         sargs = []
153         if not re.match(r"^\s*$", args):
154             for arg in re.split(",", args):
155                 args = args.strip()
156                 match = re.match(r"^(.*?)\s*?(\S+)$", arg)
157                 t, n = match.groups()
158                 t = t.strip()
159                 n = n.strip()
160                 sargs.append(Arg(n, t))
161         if ret != "void":
162             raise Exception ("Func simcalls (ie, returning a value) not supported anymore")
163         ans = 'Proc'
164         handler = True
165         if attrs:
166             attrs = attrs[2:-2]
167             for attr in re.split(",", attrs):
168                 if attr == "block":
169                     ans = "Blck"
170                 elif attr == "nohandler":
171                     handler = False
172                 else:
173                     raise AssertionError("Unknown attribute %s in: %s" % (attr, line))
174         sim = Simcall(name, handler, Arg('result', ret), sargs, ans)
175         if resdi is None:
176             simcalls.append(sim)
177         else:
178             resdi.append(sim)
179     return simcalls, simcalls_guarded
180
181
182 def header(name):
183     fd = open(name, 'w')
184     fd.write('/**********************************************************************/\n')
185     fd.write('/* File generated by src/simix/simcalls.py from src/simix/simcalls.in */\n')
186     fd.write('/*                                                                    */\n')
187     fd.write('/*                    DO NOT EVER CHANGE THIS FILE                    */\n')
188     fd.write('/*                                                                    */\n')
189     fd.write('/* change simcalls specification in src/simix/simcalls.in             */\n')
190     fd.write('/* Copyright (c) 2014-2022. The SimGrid Team. All rights reserved.    */\n')
191     fd.write('/**********************************************************************/\n\n')
192     fd.write('/*\n')
193     fd.write(' * Note that the name comes from http://en.wikipedia.org/wiki/Popping\n')
194     fd.write(' * Indeed, the control flow is doing a strange dance in there.\n')
195     fd.write(' *\n')
196     fd.write(' * That\'s not about http://en.wikipedia.org/wiki/Poop, despite the odor :)\n')
197     fd.write(' */\n\n')
198     return fd
199
200
201 def handle(fd, func, simcalls, guarded_simcalls):
202     def nonempty(e):
203         return e != ''
204     fd.write('\n'.join(filter(nonempty, (func(simcall) for simcall in simcalls))))
205
206     for guard, ll in guarded_simcalls.items():
207         fd.write('\n#if %s\n' % (guard))
208         fd.write('\n'.join(func(simcall) for simcall in ll))
209         fd.write('\n#endif')
210
211     fd.write('\n')
212
213 def main():
214     simcalls, simcalls_dict = parse('simcalls.in')
215
216     ok = True
217     ok &= all(map(Simcall.check, simcalls))
218     for _k, v in simcalls_dict.items():
219         ok &= all(map(Simcall.check, v))
220     if not ok:
221         print("Some checks fail!")
222         sys.exit(1)
223
224
225 if __name__ == '__main__':
226     main()