Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(355)

Side by Side Diff: ppapi/native_client/src/tools/srpcgen.py

Issue 7920012: Add missing NaCl PPAPI test components to Chrome repo. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:executable
+ *
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 # -*- python -*-
2 # Copyright (c) 2011 The Native Client Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Build "SRPC" interfaces from specifications.
7
8 SRPC interfaces consist of one or more interface classes, typically defined
9 in a set of .srpc files. The specifications are Python dictionaries, with a
10 top level 'name' element and an 'rpcs' element. The rpcs element is a list
11 containing a number of rpc methods, each of which has a 'name', an 'inputs',
12 and an 'outputs' element. These elements are lists of input or output
13 parameters, which are lists pairs containing a name and type. The set of
14 types includes all the SRPC basic types.
15
16 These SRPC specifications are used to generate a header file and either a
17 server or client stub file, as determined by the command line flag -s or -c.
18 """
19
20 import getopt
21 #import re
22 #import string
23 #import StringIO
24 import sys
25 import os
26
27 COPYRIGHT_AND_AUTOGEN_COMMENT = """\
28 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
29 // Use of this source code is governed by a BSD-style license that can be
30 // found in the LICENSE file.
31 //
32 // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
33 //
34 // Automatically generated code. See srpcgen.py
35 //
36 // NaCl Simple Remote Procedure Call interface abstractions.
37 """
38
39 HEADER_INCLUDE_GUARD_START = """\
40 #ifndef %(include_guard)s
41 #define %(include_guard)s
42 """
43
44 HEADER_INCLUDE_GUARD_END = """\
45 \n\n#endif // %(include_guard)s
46 """
47
48 HEADER_FILE_INCLUDES = """\
49 #ifndef __native_client__
50 #include "native_client/src/include/portability.h"
51 #endif // __native_client__
52 %(EXTRA_INCLUDES)s
53 """
54
55 SOURCE_FILE_INCLUDES = """\
56 #include "%(srpcgen_h)s"
57 #ifdef __native_client__
58 #ifndef UNREFERENCED_PARAMETER
59 #define UNREFERENCED_PARAMETER(P) do { (void) P; } while (0)
60 #endif // UNREFERENCED_PARAMETER
61 #else
62 #include "native_client/src/include/portability.h"
63 #endif // __native_client__
64 %(EXTRA_INCLUDES)s
65 """
66
67 # For both .cc and .h files.
68 EXTRA_INCLUDES = [
69 '#include "native_client/src/shared/srpc/nacl_srpc.h"',
70 ]
71
72 types = {'bool': ['b', 'bool', 'u.bval', ''],
73 'char[]': ['C', 'char*', 'arrays.carr', 'u.count'],
74 'double': ['d', 'double', 'u.dval', ''],
75 'double[]': ['D', 'double*', 'arrays.darr', 'u.count'],
76 'handle': ['h', 'NaClSrpcImcDescType', 'u.hval', ''],
77 'int32_t': ['i', 'int32_t', 'u.ival', ''],
78 'int32_t[]': ['I', 'int32_t*', 'arrays.iarr', 'u.count'],
79 'int64_t': ['l', 'int64_t', 'u.lval', ''],
80 'int64_t[]': ['L', 'int64_t', 'arrays.larr', 'u.count'],
81 'PP_Instance': ['i', 'PP_Instance', 'u.ival', ''],
82 'PP_Module': ['i', 'PP_Module', 'u.ival', ''],
83 'PP_Resource': ['i', 'PP_Resource', 'u.ival', ''],
84 'string': ['s', 'char*', 'arrays.str', ''],
85 }
86
87 def AddInclude(name):
88 """Adds an include to the include section of both .cc and .h files."""
89 EXTRA_INCLUDES.append('#include "%s"' % name)
90
91
92 def HeaderFileIncludes():
93 """Includes are sorted alphabetically."""
94 EXTRA_INCLUDES.sort()
95 return HEADER_FILE_INCLUDES % {
96 'EXTRA_INCLUDES': '\n'.join(EXTRA_INCLUDES),
97 }
98
99
100 def SourceFileIncludes(srpcgen_h_file):
101 """Includes are sorted alphabetically."""
102 EXTRA_INCLUDES.sort()
103 return SOURCE_FILE_INCLUDES % {
104 'EXTRA_INCLUDES': '\n'.join(EXTRA_INCLUDES),
105 'srpcgen_h': srpcgen_h_file
106 }
107
108
109 def PrintHeaderFileTop(output, include_guard):
110 """Prints the header of the .h file including copyright,
111 header comment, include guard and includes."""
112 print >>output, COPYRIGHT_AND_AUTOGEN_COMMENT
113 print >>output, HEADER_INCLUDE_GUARD_START % {'include_guard': include_guard}
114 print >>output, HeaderFileIncludes()
115
116
117 def PrintHeaderFileBottom(output, include_guard):
118 """Prints the footer of the .h file including copyright,
119 header comment, include guard and includes."""
120 print >>output, HEADER_INCLUDE_GUARD_END % {'include_guard': include_guard}
121
122
123 def PrintSourceFileTop(output, srpcgen_h_file):
124 """Prints the header of the .cc file including copyright,
125 header comment and includes."""
126 print >>output, COPYRIGHT_AND_AUTOGEN_COMMENT
127 print >>output, SourceFileIncludes(srpcgen_h_file)
128
129
130 def CountName(name):
131 """Returns the name of the auxiliary count member used for array typed."""
132 return '%s_bytes' % name
133
134
135 def FormatRpcPrototype(is_server, class_name, indent, rpc):
136 """Returns a string for the prototype of an individual RPC."""
137
138 def FormatArgs(is_output, args):
139 """Returns a string containing the formatted arguments for an RPC."""
140
141 def FormatArg(is_output, arg):
142 """Returns a string containing a formatted argument to an RPC."""
143 if is_output:
144 suffix = '* '
145 else:
146 suffix = ' '
147 s = ''
148 type_info = types[arg[1]]
149 if type_info[3]:
150 s += 'nacl_abi_size_t%s%s, %s %s' % (suffix,
151 CountName(arg[0]),
152 type_info[1],
153 arg[0])
154 else:
155 s += '%s%s%s' % (type_info[1], suffix, arg[0])
156 return s
157 s = ''
158 for arg in args:
159 s += ',\n %s%s' % (indent, FormatArg(is_output, arg))
160 return s
161 if is_server:
162 ret_type = 'void'
163 else:
164 ret_type = 'NaClSrpcError'
165 s = '%s %s%s(\n' % (ret_type, class_name, rpc['name'])
166 # Until SRPC uses RPC/Closure on the client side, these must be different.
167 if is_server:
168 s += ' %sNaClSrpcRpc* rpc,\n' % indent
169 s += ' %sNaClSrpcClosure* done' % indent
170 else:
171 s += ' %sNaClSrpcChannel* channel' % indent
172 s += '%s' % FormatArgs(False, rpc['inputs'])
173 s += '%s' % FormatArgs(True, rpc['outputs'])
174 s += ')'
175 return s
176
177
178 def PrintHeaderFile(output, is_server, guard_name, interface_name, specs):
179 """Prints out the header file containing the prototypes for the RPCs."""
180 PrintHeaderFileTop(output, guard_name)
181 s = ''
182 # iterate over all the specified interfaces
183 if is_server:
184 suffix = 'Server'
185 else:
186 suffix = 'Client'
187 for spec in specs:
188 class_name = spec['name'] + suffix
189 rpcs = spec['rpcs']
190 s += 'class %s {\n public:\n' % class_name
191 for rpc in rpcs:
192 s += ' static %s;\n' % FormatRpcPrototype(is_server, '', ' ', rpc)
193 s += '\n private:\n %s();\n' % class_name
194 s += ' %s(const %s&);\n' % (class_name, class_name)
195 s += ' void operator=(const %s);\n' % class_name
196 s += '}; // class %s\n\n' % class_name
197 if is_server:
198 s += 'class %s {\n' % interface_name
199 s += ' public:\n'
200 s += ' static NaClSrpcHandlerDesc srpc_methods[];\n'
201 s += '}; // class %s' % interface_name
202 print >>output, s
203 PrintHeaderFileBottom(output, guard_name)
204
205
206 def PrintServerFile(output, header_name, interface_name, specs):
207 """Print the server (stub) .cc file."""
208
209 def FormatDispatchPrototype(indent, rpc):
210 """Format the prototype of a dispatcher method."""
211 s = '%sstatic void %sDispatcher(\n' % (indent, rpc['name'])
212 s += '%s NaClSrpcRpc* rpc,\n' % indent
213 s += '%s NaClSrpcArg** inputs,\n' % indent
214 s += '%s NaClSrpcArg** outputs,\n' % indent
215 s += '%s NaClSrpcClosure* done\n' % indent
216 s += '%s)' % indent
217 return s
218
219 def FormatMethodString(rpc):
220 """Format the SRPC text string for a single rpc method."""
221
222 def FormatTypes(args):
223 s = ''
224 for arg in args:
225 s += types[arg[1]][0]
226 return s
227 s = ' { "%s:%s:%s", %sDispatcher },\n' % (rpc['name'],
228 FormatTypes(rpc['inputs']),
229 FormatTypes(rpc['outputs']),
230 rpc['name'])
231 return s
232
233 def FormatCall(class_name, indent, rpc):
234 """Format a call from a dispatcher method to its stub."""
235
236 def FormatArgs(is_output, args):
237 """Format the arguments passed to the stub."""
238
239 def FormatArg(is_output, num, arg):
240 """Format an argument passed to a stub."""
241 if is_output:
242 prefix = 'outputs[' + str(num) + ']->'
243 addr_prefix = '&('
244 addr_suffix = ')'
245 else:
246 prefix = 'inputs[' + str(num) + ']->'
247 addr_prefix = ''
248 addr_suffix = ''
249 type_info = types[arg[1]]
250 if type_info[3]:
251 s = '%s%s%s%s, %s%s' % (addr_prefix,
252 prefix,
253 type_info[3],
254 addr_suffix,
255 prefix,
256 type_info[2])
257 else:
258 s = '%s%s%s%s' % (addr_prefix, prefix, type_info[2], addr_suffix)
259 return s
260 # end FormatArg
261 s = ''
262 num = 0
263 for arg in args:
264 s += ',\n%s %s' % (indent, FormatArg(is_output, num, arg))
265 num += 1
266 return s
267 # end FormatArgs
268 s = '%s::%s(\n%s rpc,\n' % (class_name, rpc['name'], indent)
269 s += '%s done' % indent
270 s += FormatArgs(False, rpc['inputs'])
271 s += FormatArgs(True, rpc['outputs'])
272 s += '\n%s)' % indent
273 return s
274 # end FormatCall
275
276 PrintSourceFileTop(output, header_name)
277 s = 'namespace {\n\n'
278 for spec in specs:
279 class_name = spec['name'] + 'Server'
280 rpcs = spec['rpcs']
281 for rpc in rpcs:
282 s += '%s {\n' % FormatDispatchPrototype('', rpc)
283 if rpc['inputs'] == []:
284 s += ' UNREFERENCED_PARAMETER(inputs);\n'
285 if rpc['outputs'] == []:
286 s += ' UNREFERENCED_PARAMETER(outputs);\n'
287 s += ' %s;\n' % FormatCall(class_name, ' ', rpc)
288 s += '}\n\n'
289 s += '} // namespace\n\n'
290 s += 'NaClSrpcHandlerDesc %s::srpc_methods[] = {\n' % interface_name
291 for spec in specs:
292 class_name = spec['name'] + 'Server'
293 rpcs = spec['rpcs']
294 for rpc in rpcs:
295 s += FormatMethodString(rpc)
296 s += ' { NULL, NULL }\n};\n'
297 print >>output, s
298
299
300 def PrintClientFile(output, header_name, specs, thread_check):
301 """Prints the client (proxy) .cc file."""
302
303 def InstanceInputArg(rpc):
304 """Returns the name of the PP_Instance arg or None if there is none."""
305 for arg in rpc['inputs']:
306 if arg[1] == 'PP_Instance':
307 return arg[0]
308 return None
309
310 def DeadNexeHandling(rpc, retval):
311 """Generates the code necessary to handle death of a nexe during the rpc
312 call. This is only possible if PP_Instance arg is present, otherwise"""
313 instance = InstanceInputArg(rpc);
314 if instance is not None:
315 check = (' if (%s == NACL_SRPC_RESULT_INTERNAL)\n'
316 ' ppapi_proxy::CleanUpAfterDeadNexe(%s);\n')
317 return check % (retval, instance)
318 return '' # No handling
319
320
321 def FormatCall(rpc):
322 """Format a call to the generic dispatcher, NaClSrpcInvokeBySignature."""
323
324 def FormatTypes(args):
325 """Format a the type signature string for either inputs or outputs."""
326 s = ''
327 for arg in args:
328 s += types[arg[1]][0]
329 return s
330 def FormatArgs(args):
331 """Format the arguments for the call to the generic dispatcher."""
332
333 def FormatArg(arg):
334 """Format a single argument for the call to the generic dispatcher."""
335 s = ''
336 type_info = types[arg[1]]
337 if type_info[3]:
338 s += '%s, ' % CountName(arg[0])
339 s += arg[0]
340 return s
341 # end FormatArg
342 s = ''
343 for arg in args:
344 s += ',\n %s' % FormatArg(arg)
345 return s
346 #end FormatArgs
347 s = '(\n channel,\n "%s:%s:%s"' % (rpc['name'],
348 FormatTypes(rpc['inputs']),
349 FormatTypes(rpc['outputs']))
350 s += FormatArgs(rpc['inputs'])
351 s += FormatArgs(rpc['outputs']) + '\n )'
352 return s
353 # end FormatCall
354
355 # We need this to handle dead nexes.
356 if header_name.startswith('trusted'):
357 AddInclude('native_client/src/shared/ppapi_proxy/browser_globals.h')
358 if thread_check:
359 AddInclude('native_client/src/shared/ppapi_proxy/plugin_globals.h')
360 AddInclude('ppapi/c/ppb_core.h')
361 AddInclude('native_client/src/shared/platform/nacl_check.h')
362 PrintSourceFileTop(output, header_name)
363 s = ''
364
365 for spec in specs:
366 class_name = spec['name'] + 'Client'
367 rpcs = spec['rpcs']
368 for rpc in rpcs:
369 s += '%s {\n' % FormatRpcPrototype('', class_name + '::', '', rpc)
370 if thread_check and rpc['name'] not in ['PPB_GetInterface',
371 'PPB_Core_CallOnMainThread']:
372 error = '"%s: PPAPI calls are not supported off the main thread\\n"'
373 s += ' VCHECK(ppapi_proxy::PPBCoreInterface()->IsMainThread(),\n'
374 s += ' (%s,\n' % error
375 s += ' __FUNCTION__));\n'
376 s += ' NaClSrpcError retval;\n'
377 s += ' retval = NaClSrpcInvokeBySignature%s;\n' % FormatCall(rpc)
378 if header_name.startswith('trusted'):
379 s += DeadNexeHandling(rpc, 'retval')
380 s += ' return retval;\n'
381 s += '}\n\n'
382 print >>output, s
383
384 def MakePath(name):
385 paths = name.split(os.sep)
386 path = os.sep.join(paths[:-1])
387 try:
388 os.makedirs(path)
389 except OSError:
390 return
391
392
393 def main(argv):
394 usage = 'Usage: srpcgen.py <-c | -s> [--include=<name>] [--ppapi]'
395 usage = usage + ' <iname> <gname> <.h> <.cc> <specs>'
396
397 mode = None
398 ppapi = False
399 thread_check = False
400 try:
401 long_opts = ['include=', 'ppapi', 'thread-check']
402 opts, pargs = getopt.getopt(argv[1:], 'cs', long_opts)
403 except getopt.error, e:
404 print >>sys.stderr, 'Illegal option:', str(e)
405 print >>sys.stderr, usage
406 return 1
407
408 # Get the class name for the interface.
409 interface_name = pargs[0]
410 # Get the name for the token used as a multiple inclusion guard in the header.
411 include_guard_name = pargs[1]
412 # Get the name of the header file to be generated.
413 h_file_name = pargs[2]
414 MakePath(h_file_name)
415 h_file = open(h_file_name, 'w')
416 # Get the name of the source file to be generated. Depending upon whether
417 # -c or -s is generated, this file contains either client or server methods.
418 cc_file_name = pargs[3]
419 MakePath(cc_file_name)
420 cc_file = open(cc_file_name, 'w')
421 # The remaining arguments are the spec files to be compiled.
422 spec_files = pargs[4:]
423
424 for opt, val in opts:
425 if opt == '-c':
426 mode = 'client'
427 elif opt == '-s':
428 mode = 'server'
429 elif opt == '--include':
430 h_file_name = val
431 elif opt == '--ppapi':
432 ppapi = True
433 elif opt == '--thread-check':
434 thread_check = True
435
436 if ppapi:
437 AddInclude("ppapi/c/pp_instance.h")
438 AddInclude("ppapi/c/pp_module.h")
439 AddInclude("ppapi/c/pp_resource.h")
440
441 # Convert to forward slash paths if needed
442 h_file_name = "/".join(h_file_name.split("\\"))
443
444 # Verify we picked server or client mode
445 if not mode:
446 print >>sys.stderr, 'Neither -c nor -s specified'
447 usage()
448 return 1
449
450 # Combine the rpc specs from spec_files into rpcs.
451 specs = []
452 for spec_file in spec_files:
453 code_obj = compile(open(spec_file, 'r').read(), 'file', 'eval')
454 specs.append(eval(code_obj))
455 # Print out the requested files.
456 if mode == 'client':
457 PrintHeaderFile(h_file, False, include_guard_name, interface_name, specs)
458 PrintClientFile(cc_file, h_file_name, specs, thread_check)
459 elif mode == 'server':
460 PrintHeaderFile(h_file, True, include_guard_name, interface_name, specs)
461 PrintServerFile(cc_file, h_file_name, interface_name, specs)
462
463 return 0
464
465
466 if __name__ == '__main__':
467 sys.exit(main(sys.argv))
OLDNEW
« no previous file with comments | « ppapi/native_client/src/shared/ppapi/nacl.scons ('k') | ppapi/native_client/tests/earth/README.txt » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698