source: asp3_tinet_ecnl_arm/trunk/asp3_dcre/tecsgen/tecslib/plugin/lib/GenOpaqueMarshaler.rb@ 352

Last change on this file since 352 was 352, checked in by coas-nagasima, 6 years ago

arm向けASP3版ECNLを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-ruby;charset=UTF-8
File size: 40.3 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# TECS Generator
4# Generator for TOPPERS Embedded Component System
5#
6# Copyright (C) 2008-2014 by TOPPERS Project
7#--
8# 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ
9# ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
10# 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
11# (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
12# 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
13# スコード中に含まれていること.
14# (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
15# 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
16# 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
17# の無保証規定を掲載すること.
18# (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
19# 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
20# と.
21# (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
22# 作権表示,この利用条件および下記の無保証規定を掲載すること.
23# (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
24# 報告すること.
25# (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
26# 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
27# また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
28# 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
29# 免責すること.
30#
31# 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
32# よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
33# に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
34# アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
35# の責任を負わない.
36#
37# $Id$
38#++
39
40#== GenOpaqueMarshaler
41# OpaqueRPCPlugin, sharedOpaqueRPCPlugin 共通の要素を集めたモジュール
42module GenOpaqueMarshaler
43
44 # プラグイン引数名と Proc
45 RPCPluginArgProc = {
46 "clientChannelCelltype" => Proc.new { |obj,rhs| obj.set_clientChannelCelltype rhs },
47 "serverChannelCelltype" => Proc.new { |obj,rhs| obj.set_serverChannelCelltype rhs },
48 "clientChannelCell" => Proc.new { |obj,rhs| obj.set_clientChannelCell rhs },
49 "serverChannelCell" => Proc.new { |obj,rhs| obj.set_serverChannelCell rhs },
50 "clientChannelInitializer" => Proc.new { |obj,rhs| obj.set_clientChannelInitializer rhs },
51 "serverChannelInitializer" => Proc.new { |obj,rhs| obj.set_serverChannelInitializer rhs },
52 "clientSemaphoreCelltype" => Proc.new { |obj,rhs| obj.set_clientSemaphoreCelltype rhs },
53 "clientSemaphoreInitializer" => Proc.new { |obj,rhs| obj.set_clientSemaphoreInitializer rhs },
54 "clientErrorHandler" => Proc.new { |obj,rhs| obj.set_clientErrorHandler rhs },
55 "serverErrorHandler" => Proc.new { |obj,rhs| obj.set_serverErrorHandler rhs },
56 "TDRCelltype" => Proc.new { |obj,rhs| obj.set_TDRCelltype rhs },
57 "PPAllocatorSize" => Proc.new { |obj,rhs| obj.set_PPAllocatorSize rhs },
58 "substituteAllocator" => Proc.new { |obj,rhs| obj.set_substituteAllocator rhs },
59 "noServerChannelOpenerCode" => Proc.new { |obj,rhs| obj.set_noServerChannelOpenerCode rhs },
60 "taskCelltype" => Proc.new { |obj,rhs| obj.set_taskCelltype rhs },
61 "taskPriority" => Proc.new { |obj,rhs| obj.set_taskPriority rhs },
62 "stackSize" => Proc.new { |obj,rhs| obj.set_stackSize rhs },
63 }
64
65 ##### プラグイン引数チェック関数
66
67 #=== プラグイン引数 taskPriority のチェック
68 def set_taskPriority( rhs )
69 @taskPriority = rhs
70 end
71
72 #=== プラグイン引数 serverChannelCelltype のチェック
73 def set_serverChannelCelltype( rhs )
74 @serverChannelCelltype = rhs.to_sym
75 # path = [ "::", @serverChannelCelltype ]
76 # obj = Namespace.find( path )
77 nsp = NamespacePath.analyze( @serverChannelCelltype.to_s )
78 obj = Namespace.find( nsp )
79 if ! obj.instance_of?( Celltype ) && ! obj.instance_of?( CompositeCelltype ) then
80 cdl_error( "RPCPlugin: serverChannelCelltype '#{rhs}' not celltype or not defined" )
81 end
82 end
83
84 #=== プラグイン引数 clientChannelCelltype のチェック
85 def set_clientChannelCelltype( rhs )
86 @clientChannelCelltype = rhs.to_sym
87 # path = [ "::", @clientChannelCelltype ]
88 # obj = Namespace.find( path )
89 nsp = NamespacePath.analyze( @clientChannelCelltype.to_s )
90 obj = Namespace.find( nsp )
91 if ! obj.instance_of?( Celltype ) && ! obj.instance_of?( CompositeCelltype ) then
92 cdl_error( "RPCPlugin: clientChanneclCelltype '#{rhs}' not celltype or not defined" )
93 end
94 end
95
96 #=== プラグイン引数 serverChannelCell のチェック
97 def set_serverChannelCell( rhs )
98 @serverChannelCell = rhs.to_sym
99 # ChannelCell はプラグインで生成されるため、ここではチェックできない
100 # path = [ "::", @serverChannelCell ]
101 # obj = Namespace.find( path )
102 # if ! obj.instance_of?( Cell ) then
103 # cdl_error( "RPCPlugin: serverChanneclCell '#{rhs}' not cell or not defined" )
104 # end
105 end
106
107 #=== プラグイン引数 clientChannelCell のチェック
108 def set_clientChannelCell( rhs )
109 @clientChannelCell = rhs.to_sym
110 # ChannelCell はプラグインで生成されるため、ここではチェックできない
111 # path = [ "::", @clientChannelCell ]
112 # obj = Namespace.find( path )
113 # if ! obj.instance_of?( Cell ) then
114 # cdl_error( "RPCPlugin: clientChanneclCell '#{rhs}' not cell or not defined" )
115 # end
116 end
117
118 #=== プラグイン引数 serverChannelInitializer のチェック
119 def set_serverChannelInitializer( rhs )
120 @serverChannelInitializer = rhs.to_sym
121 end
122
123 #=== プラグイン引数 clientChannelInitializer のチェック
124 def set_clientChannelInitializer( rhs )
125 @clientChannelInitializer = rhs.to_sym
126 end
127
128 #=== タスクタイプ taskCellype のチェック
129 def set_taskCelltype( rhs )
130 @taskCelltype = rhs.to_sym
131 # path = [ "::", @taskCelltype ]
132 # obj = Namespace.find( path )
133 nsp = NamespacePath.analyze( @taskCelltype.to_s )
134 obj = Namespace.find( nsp )
135 if ! obj.instance_of?( Celltype ) && ! obj.instance_of?( CompositeCelltype ) then
136 cdl_error( "RPCPlugin: taskCelltype '#{rhs}' not celltype or not defined" )
137 end
138 end
139
140 #=== タスクタイプ stack\size のチェック
141 def set_stackSize( rhs )
142 @stackSize = rhs
143 end
144
145 #=== プラグイン引数 PPAllocatorSize のチェック
146 def set_PPAllocatorSize( rhs )
147 @PPAllocatorSize = rhs
148 end
149
150 #=== プラグイン引数 TDRCelltype のチェック
151 def set_TDRCelltype( rhs )
152 @TDRCelltype = rhs.to_sym
153 # path = [ "::", @TDRCelltype ]
154 # obj = Namespace.find( path )
155 nsp = NamespacePath.analyze( @TDRCelltype.to_s )
156 obj = Namespace.find( nsp )
157 if ! obj.instance_of?( Celltype ) && ! obj.instance_of?( CompositeCelltype ) then
158 cdl_error( "RPCPlugin: TDRCelltype '#{rhs}' not celltype or not found" )
159 end
160 end
161
162 #=== プラグイン引数 substituteAllocator のチェック
163 # オプション引数が、以下の形式であることをチェック
164 # substituteAllocator(Alloc.eAlloc=>Subst.eAlloc,Alloc2.eAlloc=>Subst2.eAlloc)
165 def set_substituteAllocator( rhs )
166 #str::String : 破壊される(マッチした残りになる)。str.empty? で空になったことをチェックできる
167 #regexp::Regexp : 期待するトークンにマッチする正規表現。 "\A" 出始める
168 #expected::String: 期待するトークン、regexp が出現しなかった場合にエラーメッセージとして表示
169 def optparse (str,regexp,expected)
170 str.strip!
171 token = nil
172 res = str.sub!( regexp ){ |matched| token = matched; "" }
173 if ! token then
174 cdl_error( "syntax error in substituteAllocator option near '#{str}', expected '#{expected}'" )
175 end
176 return token
177 end
178
179 opt = rhs.dup
180 ident_rexpr = /\A(\w[\w\d]*)/
181
182 # "Alloc.eAlloc=>CAlloc.eAlloc" の形式になっていることをチェック
183 while true
184 lhs_alloc_cell = optparse( opt, ident_rexpr, "allocator cell name" )
185 break if ! lhs_alloc_cell
186
187 res = optparse( opt, /\A\./, "." )
188 break if ! res
189
190 lhs_alloc_ent = optparse( opt, ident_rexpr, "allocator cell entry name" )
191 break if ! lhs_alloc_ent
192
193 res = optparse( opt, /\A\=\>/, "=>" )
194 break if ! res
195
196 rhs_alloc_cell = optparse( opt, ident_rexpr, "allocator cell name" )
197 break if ! rhs_alloc_cell
198
199 res = optparse( opt, /\A\./, "." )
200 break if ! res
201
202 rhs_alloc_ent = optparse( opt, ident_rexpr, "allocator cell entry name" )
203 break if ! rhs_alloc_ent
204
205# ここでは、右辺のチェックはできない。右辺のセルは前方参照となる
206# path = [ "::", rhs_alloc_cell.to_sym ] # mikan namespace
207# obj = Namespace.find( path )
208# if ! obj.instance_of?( Cell ) || obj.get_region.get_path_string != @clientRegion then
209# cdl_error( "RPCPlugin: substituteAllocator: '#{rhs_alloc_cell}' not cell or not found in client region" )
210# else
211# ct = obj.get_celltype
212# if ct # nil なら既にエラー
213# ent = ct.find rhs_alloc_ent
214# if ! ent.instance_of? Port || ent.get_port_type != :ENTRY || ent.get_signature == nil || ! ent.get_signature.is_allocator?
215# cdl_error( "RPCPlugin: substituteAllocator: '#{rhs_alloc_cell}.#{rhs_alloc_ent}' not entry port or not have alllocator signature" )
216# end
217# end
218# end
219
220 @substituteAllocator[ "#{lhs_alloc_cell}.#{lhs_alloc_ent}".to_sym ] =
221 [ lhs_alloc_cell, lhs_alloc_ent, rhs_alloc_cell, rhs_alloc_ent ]
222
223# p "substituteAllocator: #{lhs_alloc_cell}.#{lhs_alloc_ent}=>#{rhs_alloc_cell}.#{rhs_alloc_ent}"
224
225 break if opt.empty?
226
227 res = optparse( opt, /\A\,/, "," )
228 break if ! res
229 end
230
231 end
232
233 #=== プラグイン引数 noServerChannelOpenerCode のチェック
234 def set_noServerChannelOpenerCode( rhs )
235 rhs = rhs.to_sym
236 if rhs == :true
237 @noServerChannelOpenerCode = true
238 elsif rhs == :false then
239 @noServerChannelOpenerCode = false
240 else
241 cdl_error( "RPCPlugin: specify true or false for noServerChannelOpenerCode" )
242 end
243 end
244
245 #=== プラグイン引数 clientSemaphoreCelltype のチェック
246 def set_clientSemaphoreCelltype rhs
247 @semaphoreCelltype = rhs.to_sym
248 nsp = NamespacePath.analyze( @semaphoreCelltype.to_s )
249 obj = Namespace.find( nsp )
250 if ! obj.instance_of?( Celltype ) && ! obj.instance_of?( CompositeCelltype ) then
251 cdl_error( "RPCPlugin: clientSemaphoreCelltype '#{rhs}' not celltype or not defined" )
252 end
253 end
254
255 #=== プラグイン引数 clientSemaphoreInitializer のチェック
256 def set_clientSemaphoreInitializer rhs
257 @semaphoreInitializer = rhs.to_sym
258 end
259
260 #=== プラグイン引数 clientErrorHandler のチェック
261 def set_clientErrorHandler rhs
262 @clientErrorHandler = rhs.to_sym
263 end
264
265 #=== プラグイン引数 serverErrorHandler のチェック
266 def set_serverErrorHandler rhs
267 @serverErrorHandler = rhs.to_sym
268 end
269
270
271 #=== セルの名前を得る
272 # ThroughPlugin::get_cell_name plugin.rb をオーバーライド
273 def get_cell_name
274 @cell_name
275 # @clientChannelCell
276 end
277
278 #=== marshaler のセルタイプ名を設定する
279 def initialize_opaque_marshaler
280
281 # オプション設定される変数のデフォルトを設定
282 @taskPriority = 11
283 @stackSize = 4096
284 @serverChannelCelltype = :"tSocketServer"
285 @clientChannelCelltype = :"tSocketClient"
286 @serverChannelCell = :"#{@cell_name}Server"
287 @clientChannelCell = :"#{@cell_name}Client"
288 @serverChannelInitializer = subst_name( "portNo=8931+$count$;" ).to_sym
289 @clientChannelInitializer = subst_name( "portNo=8931+$count$; serverAddr=\"127.0.0.1\"; " ).to_sym
290 @taskCelltype = :"tTask"
291 @PPAllocatorSize = nil
292 # @TDRCelltype = :"tTDR" # "tNBOTDR" に変更の予定
293 @TDRCelltype = :"tNBOTDR"
294 @substituteAllocator = {}
295 @noServerChannelOpenerCode = false
296 @semaphoreCelltype = :"tSemaphore"
297 @semaphoreInitializer = :"count = 1; attribute = C_EXP( \"TA_NULL\" ); ";
298 @clientErrorHandler = nil
299 @serverErrorHandler = nil
300 @b_genOpener = false
301 @taskMainCelltype = :"tRPCDedicatedTaskMain"
302
303 @marshaler_celltype_name = :"tOpaqueMarshaler_#{@signature.get_global_name}"
304 @unmarshaler_celltype_name = :"tOpaqueUnmarshaler_#{@signature.get_global_name}"
305 @marshaler_celltype_file_name = "#{$gen}/#{@marshaler_celltype_name}.cdl"
306
307 # signature で対応できないものをチェック
308 @signature.each_param{ |func_decl, param_decl|
309 if param_decl.get_direction == :OUT then
310 if param_decl.get_count && ! param_decl.get_size then
311 cdl_error( "#{@signature.get_namespace_path}.#{func_decl.get_name}.#{param_decl.get_name}: size_is must be specified for out parameter of Opaque RPC" )
312 end
313 if param_decl.get_string == -1 then
314 cdl_error( "#{@signature.get_namespace_path}.#{func_decl.get_name}.#{param_decl.get_name}: string length must be specified for out parameter of Opaque RPC" )
315 end
316 end
317 }
318 end
319
320 #=== GenOpaqueMarshaler# Opener Code の生成時のチェック
321 def check_opener_code
322 # サーバーチャンネルセルタイプが entry sServerChannelOpener eOpener を持つかどうかをチェック
323 # mikan entry か (call でないか) をチェックしていない
324 # scct = Namespace.find ["::", @serverChannelCelltype] # mikan namespace
325 nsp = NamespacePath.analyze( @serverChannelCelltype.to_s )
326 scct = Namespace.find nsp
327 if scct then
328 obj = scct.find( :"eOpener" )
329 if obj.instance_of? Port then
330 if obj.get_signature.get_name.to_sym == :sServerChannelOpener then
331 if @noServerChannelOpenerCode == false then
332 @b_genOpener = true
333 @taskMainCelltype = :"tRPCDedicatedTaskMainWithOpener"
334 end
335 end
336 end
337 end
338 if @noServerChannelOpenerCode == false && @taskMainCelltype != :"tRPCDedicatedTaskMainWithOpener" then
339 cdl_warning( "O9999 ServerChannelOpener code not generated, not found 'entry sServerChannelOpener eOpener'")
340 end
341 end
342
343 #=== GenOpaqueMarshaler# PPAllocator の必要性をチェックする
344 def check_PPAllocator
345 if @signature.need_PPAllocator?(true) then
346 if @PPAllocatorSize == nil then
347 cdl_error( "PPAllocatorSize must be speicified for size_is array" )
348 end
349 end
350 end
351
352 #####
353
354 def gen_marshaler_celltype
355 f = CFile.open( @marshaler_celltype_file_name, "w" )
356 # 同じ内容を二度書く可能性あり (AppFile は不可)
357
358 if @PPAllocatorSize then
359 alloc_call_port = " call sPPAllocator cPPAllocator;\n"
360 else
361 alloc_call_port = ""
362 end
363
364 f.print <<EOT
365
366celltype #{@marshaler_celltype_name} {
367 entry #{@signature.get_namespace_path} eClientEntry;
368 call sTDR cTDR;
369 [optional]
370 call sSemaphore cLockChannel;
371 [optional]
372 call sRPCErrorHandler cErrorHandler;
373};
374celltype #{@unmarshaler_celltype_name} {
375 call #{@signature.get_namespace_path} cServerCall;
376 call sTDR cTDR;
377 [optional]
378 call sRPCErrorHandler cErrorHandler;
379 entry sUnmarshalerMain eService;
380#{alloc_call_port}};
381EOT
382 f.close
383 end
384
385 #=== 受け口関数の本体コードを生成(頭部と末尾は別途出力)
386 #ct_name:: Symbol (through プラグインで生成された) セルタイプ名 .Symbol として送られてくる(らしい)
387 def gen_ep_func_body( file, b_singleton, ct_name, global_ct_name, sig_name, ep_name, func_name, func_global_name, func_type, params )
388
389 # unmarshaler クラスか?
390 if ct_name == @unmarshaler_celltype_name.to_sym then
391 gen_ep_func_body_unmarshal( file, b_singleton, ct_name, global_ct_name, sig_name, ep_name, func_name, func_global_name, func_type, params )
392 else
393 gen_ep_func_body_marshal( file, b_singleton, ct_name, global_ct_name, sig_name, ep_name, func_name, func_global_name, func_type, params )
394 end
395 end
396
397 #=== marshal コードの生成
398 def gen_ep_func_body_marshal( file, b_singleton, ct_name, global_ct_name, sig_name, ep_name, func_name, func_global_name, func_type, params )
399
400 b_void = false
401 b_ret_er = false
402
403 # 関数の戻り値の元の型を得る(typedef されている場合)
404 type = func_type.get_type.get_original_type
405
406 # 戻り値記憶用の変数を出力(void 型の関数では出力しない)
407 if ! type.is_void? then
408 file.print( "\t#{func_type.get_type.get_type_str}\t\tretval_;\n" )
409 if func_type.get_type.kind_of?( DefinedType ) && ( func_type.get_type.get_type_str == "ER" || func_type.get_type.get_type_str == "ER_INT" ) then
410 b_ret_er = true
411 end
412 else
413 b_void = true
414 end
415
416 file.print( "\tER\t\tercd_;\n" )
417 file.print( "\tint16_t\tstate_;\n" )
418
419 # 関数 ID (整数値)
420 func_id = "FUNCID_#{@signature.get_global_name}_#{func_name}".upcase
421 fid = @signature.get_id_from_func_name( func_name )
422 file.print( "\tint16_t\tfunc_id_ = #{func_id}; /* (id of '#{func_name}') = #{fid}*/\n" )
423
424 # シングルトンでないか?
425 if ! b_singleton then
426
427 # singleton でなければ p_cellcb 取得コードを出力
428 file.print <<EOT
429 #{ct_name}_CB *p_cellcb;
430
431 if( VALID_IDX( idx ) ){
432 p_cellcb = GET_CELLCB(idx);
433EOT
434
435 # エラーを返すか?
436 if b_ret_er then
437 file.print <<EOT
438 }else{
439 return ERCD( E_RPC, E_ID );
440 }
441EOT
442 else
443 file.print <<EOT
444 }else{
445 /* エラー処理コードをここに記述 */
446 }
447
448EOT
449 end
450 end
451
452 if func_type.has_receive? then
453 file.print " /* initialize receive parameters */\n"
454 params.each{ |param|
455 if param.get_direction == :RECEIVE then
456 file.print " *#{param.get_name} = 0;\n"
457 end
458 }
459 end
460
461 # channel lock コード
462 file.print <<EOT
463
464 /* Channel Lock */
465 SET_RPC_STATE( state_, RPCSTATE_CLIENT_GET_SEM );
466 if( is_cLockChannel_joined() )
467 cLockChannel_wait();
468EOT
469
470 # SOP を送信
471 file.print " /* SOPの送出 */\n"
472 file.print " SET_RPC_STATE( state_, RPCSTATE_CLIENT_SEND_SOP );\n"
473 file.print " if( ( ercd_ = cTDR_sendSOP( true ) ) != E_OK )\n"
474 file.print " goto error_reset;\n"
475
476 # func_id を送信
477 file.print " /* 関数 id の送出 */\n"
478 file.print " if( ( ercd_ = cTDR_putInt16( func_id_ ) ) != E_OK )\n"
479 file.print " goto error_reset;\n"
480
481 # p "celltype_name, sig_name, func_name, func_global_name"
482 # p "#{ct_name}, #{sig_name}, #{func_name}, #{func_global_name}"
483
484 b_get = false # marshal なら put
485 b_marshal = true # marshal
486
487 # in 方向の入出力を出力
488 if func_type.has_inward? then
489 file.print " /* 入力引数送出 */\n"
490 file.print " SET_RPC_STATE( state_, RPCSTATE_CLIENT_SEND_BODY );\n"
491 print_params( params, file, 1, b_marshal, b_get, true, "eClientEntry", func_name )
492 print_params( params, file, 1, b_marshal, b_get, false, "eClientEntry", func_name )
493 end
494 print_out_nullable( params, file, 1, b_marshal );
495
496 if ! func_type.is_oneway? then
497 b_continue = "true"
498 else
499 b_continue = "false"
500 end
501 file.print " /* EOPの送出(パケットの掃きだし) */\n"
502 file.print " SET_RPC_STATE( state_, RPCSTATE_CLIENT_SEND_EOP );\n"
503 file.print " if( (ercd_=cTDR_sendEOP(#{b_continue})) != E_OK )\n"
504 file.print " goto error_reset;\n\n"
505
506 # send のメモリをデアロケート
507 if func_type.has_send? then
508 file.print " /* dealloc send parameter while executing */\n"
509 file.print " SET_RPC_STATE( state_, RPCSTATE_CLIENT_EXEC );\n"
510 dir = :SEND; nest = 1; dealloc_cp = "eClientEntry_#{func_name}"
511 dealloc_for_params( params, file, nest, dir, dealloc_cp )
512 file.print "\n"
513 end
514
515 if ! func_type.is_oneway? then
516
517 file.print " /* パケットの始まりをチェック */\n"
518 file.print " SET_RPC_STATE( state_, RPCSTATE_CLIENT_RECV_SOP );\n"
519 file.print " if( (ercd_=cTDR_receiveSOP( true )) != E_OK )\n"
520 file.print " goto error_reset;\n"
521
522 b_get = true # marshaler は get
523 file.print " /* 戻り値の受け取り */\n"
524 print_param( "retval_", func_type.get_type, file, 1, :RETURN, nil, nil, b_marshal, b_get )
525
526 if func_type.has_outward? then
527 if b_ret_er then
528 indent_level = 2
529 file.print " if( MERCD( retval_ ) != E_RPC ){\n"
530 else
531 indent_level = 1
532 end
533 indent = " " * indent_level
534
535 file.print "#{indent}/* 出力値の受け取り */\n"
536 file.print "#{indent}SET_RPC_STATE( state_, RPCSTATE_CLIENT_RECV_BODY );\n"
537 print_params( params, file, indent_level, b_marshal, b_get, true, "eClientEntry", func_name )
538 print_params( params, file, indent_level, b_marshal, b_get, false, "eClientEntry", func_name )
539
540 if b_ret_er then
541 file.print " }\n"
542 end
543 end
544
545 file.print "\n /* パケットの終わりをチェック */\n"
546 file.print " SET_RPC_STATE( state_, RPCSTATE_CLIENT_RECV_EOP );\n"
547 file.print " if( (ercd_=cTDR_receiveEOP(false)) != E_OK )\n" # b_continue = false
548 file.print " goto error_reset;\n"
549
550 end # ! func_type.is_oneway?
551
552 # channel lock コード
553 file.print <<EOT
554 /* Channel Unlock */
555 SET_RPC_STATE( state_, RPCSTATE_CLIENT_RELEASE_SEM );
556 if( is_cLockChannel_joined() )
557 cLockChannel_signal();
558EOT
559
560 if( b_void == false )then
561 # 呼び元に戻り値をリターン
562 file.print( " return retval_;\n" )
563 else
564 file.print( " return;\n" )
565 end
566
567 file.print <<EOT
568
569error_reset:
570EOT
571 # send のメモリをデアロケート
572 if func_type.has_send? then
573 file.print " /* dealloc send parameter */\n"
574 file.print " if( state_ < RPCSTATE_CLIENT_EXEC ){\n"
575 dir = :SEND; nest = 2; dealloc_cp = "eClientEntry_#{func_name}"
576 dealloc_for_params( params, file, nest, dir, dealloc_cp )
577 file.print " }\n"
578 end
579
580 # receive のメモリをデアロケート
581 if func_type.has_receive? then
582 file.print( " /* receive parameter */\n" )
583 dir = :RECEIVE; nest = 1; dealloc_cp = "eClientEntry_#{func_name}"
584 dealloc_for_params( params, file, nest, dir, dealloc_cp, true )
585 end
586
587 file.print <<EOT
588 if( MERCD( ercd_ ) != E_RESET )
589 (void)cTDR_reset();
590EOT
591
592 # channel lock コード
593 file.print <<EOT
594 /* Channel Unlock */
595 if( is_cLockChannel_joined() )
596 cLockChannel_signal();
597
598 if( ercd_ != E_OK && is_cErrorHandler_joined() )
599 cErrorHandler_errorOccured( func_id_, ercd_, state_ );
600EOT
601
602 if( b_ret_er != false )then
603 # 呼び元に戻り値をリターン
604 file.print( " return ERCD( E_RPC, MERCD( ercd_ ) );\n" )
605 else
606 file.print( " return;\n" )
607 end
608
609 end
610
611 #=== unmarshal コードの生成
612 def gen_ep_func_body_unmarshal( file, b_singleton, ct_name, global_ct_name, sig_name, ep_name, func_name, func_global_name, func_type, params )
613
614 b_ret_er = true
615
616 # func_id を得るコードを生成
617 file.print <<EOT
618
619 int16_t func_id_;
620 ER ercd_ = E_OK;
621 int16_t state_;
622
623 #{ct_name}_CB *p_cellcb;
624
625 if( VALID_IDX( idx ) ){
626 p_cellcb = GET_CELLCB(idx);
627EOT
628
629 if b_ret_er then
630 file.print <<EOT
631 }else{
632 return;
633 }
634EOT
635 else
636 file.print <<EOT
637 }else{
638 /* エラー処理コードをここに記述 */
639 }
640EOT
641 end
642
643 file.print <<EOT
644
645#ifdef RPC_DEBUG
646 syslog(LOG_INFO, "Entering RPC service loop" );
647#endif
648
649 /* SOPのチェック */
650 SET_RPC_STATE( state_, RPCSTATE_SERVER_RECV_SOP );
651 if( (ercd_=cTDR_receiveSOP( false )) != E_OK )
652 goto error_reset;
653 /* func_id の取得 */
654 if( (ercd_=cTDR_getInt16( &func_id_ )) != E_OK )
655 goto error_reset;
656
657#ifdef RPC_DEBUG
658 syslog(LOG_INFO, "unmarshaler task: func_id: %d", func_id_ );
659#endif
660 switch( func_id_ ){
661EOT
662
663 # signature に含まれる すべての関数について
664 @signature.get_function_head_array.each { |f|
665 f_name = f.get_name
666 f_type = f.get_declarator.get_type
667 func_id = "FUNCID_#{@signature.get_global_name}_#{f_name}".upcase
668 fid = @signature.get_id_from_func_name( f_name )
669
670 file.print " case #{func_id}: /* (id of '#{f_name}') = #{fid} */ \n"
671 file.print " ercd_ = tOpaqueUnmarshaler_#{@signature.get_global_name}_#{f_name}( p_cellcb, &state_ );\n"
672 file.print " break;\n"
673
674 } #
675
676 if @PPAllocatorSize then
677 ppallocator_dealloc_str = " /* PPAllocator のすべてを解放 */\n cPPAllocator_dealloc_all();"
678 else
679 ppallocator_dealloc_str = ""
680 end
681
682 file.print <<EOT
683 default:
684 syslog(LOG_INFO, "unmarshaler task: ERROR: unknown func_id: %d", func_id_ );
685 ercd_ = E_ID;
686 };
687error_reset: /* OK cases also come here */
688#{ppallocator_dealloc_str}
689 if( ercd_ == E_OK )
690 return ercd_;
691 if( is_cErrorHandler_joined() )
692 ercd_ = cErrorHandler_errorOccured( func_id_, ercd_, state_ );
693 if( MERCD( ercd_ ) != E_RESET )
694 (void)cTDR_reset();
695 return ercd_;
696EOT
697
698 end
699
700 #=== PREAMBLE 部のコード生成
701 # アンマーシャラセルタイプの場合、アンマーシャラ関数のプロトタイプ宣言を生成
702 def gen_preamble file, b_singleton, ct_name, global_name
703 if ct_name != @unmarshaler_celltype_name.to_sym then
704 return
705 end
706
707 # string.h の include (memset, strlen のため)
708 file.print "/* header file (strlen, memset) */\n"
709 file.print "#include\t<string.h>\n\n"
710
711 file.print "/* アンマーシャラ関数のプロトタイプ宣言 */\n"
712 # signature に含まれる すべての関数について
713 @signature.get_function_head_array.each { |f|
714 f_name = f.get_name
715 f_type = f.get_declarator.get_type
716 id = @signature.get_id_from_func_name( f_name )
717 file.print "static ER tOpaqueUnmarshaler_#{@signature.get_global_name}_#{f_name}(CELLCB *p_cellcb, int16_t *state);\t/* func_id: #{id} */\n"
718 }
719 file.print "\n"
720 end
721
722 #=== POSTAMBLE 部のコード生成
723 # アンマーシャラセルタイプの場合、個々のアンマーシャラ関数の生成
724 def gen_postamble file, b_singleton, ct_name, global_name
725 if ct_name != @unmarshaler_celltype_name.to_sym then
726 return
727 end
728
729 file.print "\n/*** アンマーシャラ関数 ***/\n\n"
730 @signature.get_function_head_array.each { |f|
731 f_name = f.get_name
732 f_type = f.get_declarator.get_type
733 id = @signature.get_id_from_func_name( f_name )
734
735 # 関数は返り値を持つか?
736 b_ret_er = false
737 init_retval = ""
738 if f_type.get_type.is_void? then
739 b_void = true
740 else
741 b_void = false
742 if f_type.get_type.get_type_str == "ER" || f_type.get_type.get_type_str == "ER_INT" then
743 b_ret_er = true
744 init_retval = " = E_OK"
745 end
746 end
747
748 file.print <<EOT
749/*
750 * name: #{f_name}
751 * func_id: #{id}
752 */
753EOT
754 file.print "static ER\n"
755 file.print "tOpaqueUnmarshaler_#{@signature.get_global_name}_#{f_name}(CELLCB *p_cellcb, int16_t *state_)\t\t\n"
756 file.print "{\n"
757 file.print " ER ercd_;\n"
758
759 # 引数を受取る変数の定義
760 params = f.get_declarator.get_type.get_paramlist.get_items
761 # FuncHead-> Decl-> FuncType->ParamList
762 params.each{ |par|
763 name = par.get_name
764 type = par.get_type.get_original_type
765
766 dir = par.get_direction
767 if( dir == :RECEIVE )then
768 # type は PtrType で、それを取り除いた型
769 type = type.get_type
770 end
771 if( dir == :SEND || dir == :RECEIVE )then
772 init = " = 0"
773 else
774 init = ""
775 end
776
777 if type.kind_of? ArrayType then
778 type = type.get_type
779 aster = "(*"
780 aster2 = ")"
781 else
782 aster = ""
783 aster2 = ""
784 end
785
786 type_str = type.get_type_str.gsub( /\bconst\b */, "" ) # "const" を外す
787 file.printf( " %-12s %s%s%s%s%s;\n", type_str, aster, name, aster2, type.get_type_str_post, init )
788
789 if dir == :OUT && type.is_nullable? then
790 file.print( " int8_t\tb_#{name}_null_;\n" )
791 end
792 }
793
794 if ! b_void then
795 file.printf( " %-12s retval_%s%s;\n", f_type.get_type.get_type_str, f_type.get_type.get_type_str_post, init_retval )
796 end
797
798 # in 方向の入出力を入力
799 file.print "\n /* 入力引数受取 */\n"
800 file.print " SET_RPC_STATE( *state_, RPCSTATE_SERVER_RECV_BODY );\n"
801 b_get = true # unmarshal では get
802 b_marshal = false
803 print_params( params, file, 1, b_marshal, b_get, true, "cServerCall", f_name )
804 print_params( params, file, 1, b_marshal, b_get, false, "cServerCall", f_name )
805 print_out_nullable( params, file, 1, b_marshal );
806
807
808 # パケットの受信完了
809 file.print " /* パケット終わりをチェック */\n"
810 file.print " SET_RPC_STATE( *state_, RPCSTATE_SERVER_RECV_EOP );\n"
811 if ! f_type.is_oneway? then
812 b_continue = "true"
813 else
814 b_continue = "false"
815 end
816 file.print " if( (ercd_=cTDR_receiveEOP(#{b_continue})) != E_OK )\n"
817 file.print " goto error_reset;\n\n"
818
819 # out のメモリをアロケート
820 dir = :OUT; alloc_cp = "cPPAllocator_alloc"; alloc_cp_extra = nil; nest = 1
821 alloc_for_out_params( params, file, nest, dir, alloc_cp, alloc_cp_extra )
822
823 # 対象関数を呼出す
824 file.print " /* 対象関数の呼出し */\n"
825 file.print " SET_RPC_STATE( *state_, RPCSTATE_SERVER_EXEC );\n"
826 if b_void then
827 file.print( " cServerCall_#{f_name}(" )
828 else
829 file.print( " retval_ = cServerCall_#{f_name}(" )
830 end
831
832 delim = " "
833 params.each{ |par|
834 file.print delim
835 delim = ", "
836 if par.get_direction == :RECEIVE then
837 file.print "&"
838 end
839 file.print par.get_name
840 }
841 file.print( " );\n" )
842
843 # 戻り値、出力引数の受取コードの生成
844
845 # oneway の場合出力、戻り値が無く、受取を待たない(非同期な呼出し)
846 if ! f.is_oneway? then
847
848 file.print "\n /* SOPの送出 */\n"
849 file.print " SET_RPC_STATE( *state_, RPCSTATE_SERVER_SEND_SOP );\n"
850
851 file.print " if( ( ercd_ = cTDR_sendSOP( false ) ) != E_OK )\n"
852 file.print " goto error_reset;\n"
853
854 b_get = false # unmarshaler は put
855 if( ! b_void )then
856 file.print " /* 戻り値の送出 */\n"
857 print_param( "retval_", f_type.get_type, file, 1, :RETURN, nil, nil, b_marshal, b_get )
858 end
859
860 if f_type.has_outward? then
861 if b_ret_er then
862 indent_level = 2
863 file.print " if( MERCD( retval_ ) != E_RPC ){\n"
864 else
865 indent_level = 1
866 end
867 indent = " " * indent_level
868
869 file.print "#{indent}/* 出力値の送出 */\n"
870 file.print "#{indent}SET_RPC_STATE( *state_, RPCSTATE_SERVER_SEND_BODY );\n"
871 print_params( params, file, indent_level, b_marshal, b_get, true, "cServerCall", f_name )
872 print_params( params, file, indent_level, b_marshal, b_get, false, "cServerCall", f_name )
873
874 # receive のメモリをデアロケート
875 if f_type.has_receive? then
876 file.print "#{indent}/* dealloc receive parameter */\n"
877 dir = :RECEIVE; dealloc_cp = "cServerCall_#{f_name}"
878 dealloc_for_params( params, file, indent_level, dir, dealloc_cp )
879 end
880
881 if b_ret_er then
882 file.print " }\n"
883 end
884 end
885
886 file.print " /* パケットの終わり(掃きだし) */\n"
887 file.print " SET_RPC_STATE( *state_, RPCSTATE_SERVER_SEND_EOP );\n"
888 file.print " if( (ercd_=cTDR_sendEOP(false)) != E_OK )\n" # b_continue = false
889 file.print " goto error_reset;\n"
890 end # ! f.is_oneway?
891
892 file.print " return E_OK;\n"
893 file.print <<EOT
894
895error_reset:
896EOT
897 # send のリセット用デアロケート
898 if f_type.has_send? then
899 file.print " /* dealloc send parameter */\n"
900 file.print " if( *state_ < RPCSTATE_SERVER_EXEC ){\n"
901 dir = :SEND; indent_level = 2; dealloc_cp = "cServerCall_#{f_name}"
902 dealloc_for_params( params, file, indent_level, dir, dealloc_cp, true )
903 file.print " }\n"
904 end
905
906 # receive のメモリをデアロケート
907 if f_type.has_receive? && b_ret_er then
908 file.print " /* dealloc receive parameter */\n"
909 file.print " if( MERCD( retval_ ) != E_RPC ){\n"
910 dir = :RECEIVE; indent_level = 2; dealloc_cp = "cServerCall_#{f_name}"
911 dealloc_for_params( params, file, indent_level, dir, dealloc_cp )
912 file.print " }\n"
913 end
914
915 file.print " return ERCD( E_RPC, MERCD( ercd_ ) );\n"
916 file.print "}\n\n"
917
918 # ここ(個々の関数)ではエラーハンドラーは呼び出さない。呼び元(サーバーのメイン関数)で呼び出す。
919 }
920 end
921
922
923 #b_marshal:: bool
924 #b_get:: bool
925 # b_marshal = true && b_get == false : マーシャラで入力引数送出
926 # b_marshal = true && b_get == true : マーシャラで出力引数受取
927 # b_marshal = false && b_get == false : アンマーシャラで入力引数受取
928 # b_marshal = false && b_get == true : アンマーシャラで出力引数送出
929 #b_referenced:: size_is, count_is, string で参照されているものを出力
930 def print_params( params, file, nest, b_marshal, b_get, b_referenced, port_name, func_name )
931 params.each{ |param|
932# p "#{param.get_name}: b_marshal: #{b_marshal} b_get: #{b_get}"
933 if ! ( b_referenced == param.is_referenced? ) then
934 next
935 end
936
937 dir = param.get_direction
938 if( b_get == false && b_marshal == true || b_get == true && b_marshal == false )then
939 case dir
940 when :IN, :INOUT
941 alloc_cp = "cPPAllocator_alloc"
942 alloc_cp_extra = nil
943 print_param( param.get_name, param.get_type, file, nest, dir, nil, nil, b_marshal, b_get, alloc_cp, alloc_cp_extra )
944 when :SEND
945 alloc_cp = "#{port_name}_#{func_name}_#{param.get_name}_alloc"
946 alloc_cp_extra = nil
947 print_param( param.get_name, param.get_type, file, nest, dir, nil, nil, b_marshal, b_get, alloc_cp, alloc_cp_extra )
948 end
949 else
950 case dir
951 when :OUT, :INOUT
952 alloc_cp = nil # inout の b_get==true&&b_marsha==true のときアロケータコードは不用
953 alloc_cp_extra = nil
954 print_param( param.get_name, param.get_type, file, nest, dir, nil, nil, b_marshal, b_get, alloc_cp, alloc_cp_extra )
955 when :RECEIVE
956 alloc_cp = "#{port_name}_#{func_name}_#{param.get_name}_alloc"
957 alloc_cp_extra = nil
958 if b_get then
959 outer = "(*" # マーシャラ側では、ポインタが (send と比べ) 一つ多い
960 outer2 = ")"
961 else
962 outer = nil # アンマーシャラ側では、ポインタが一つ外されている
963 outer2 = nil
964 end
965 type = param.get_type.get_referto
966 print_param( param.get_name, type, file, nest, dir, outer, outer2, b_marshal, b_get, alloc_cp, alloc_cp_extra )
967 end
968 end
969 }
970 end
971
972 #=== アロケータコードを生成 (out のアンマーシャラ用)
973 def alloc_for_out_params( params, file, nest, dir, alloc_cp, alloc_cp_extra )
974 params.each{ |param|
975 dir = param.get_direction
976 if dir == :OUT then
977 alloc_for_out_param( param.get_name, param.get_type, file, nest, nil, nil, alloc_cp, alloc_cp_extra )
978 end
979 }
980 end
981
982 #=== アロケータコードを生成 (out のアンマーシャラ用個別パラメータの生成)
983 def alloc_for_out_param( name, type, file, nest, outer, outer2, alloc_cp, alloc_cp_extra )
984 org_type = type.get_original_type
985 if org_type.is_nullable? then
986 indent = "\t" * nest
987 file.print "#{indent}if( ! b_#{name}_null_ ){\n"
988 nest += 1
989 end
990 case org_type
991 when PtrType
992 indent = "\t" * nest
993 count = type.get_count; size = type.get_size; string = type.get_string
994 if count || size || string then
995 loop_counter_type = IntType.new(16) # mikan 方を size_is, count_is の引数の型とする
996 if count then
997 len = type.get_count.to_s
998 elsif size then
999 len = type.get_size.to_s
1000 elsif string then
1001 if type.get_string.instance_of? Expression then
1002 len = type.get_string.to_s
1003 else
1004 raise "unsuscripted string used for out parameter #{name}"
1005 end
1006 end
1007
1008 # size_is に max 指定がある場合、length が max を超えているかチェックするコードを生成
1009 if org_type.get_max != nil && string == nil then
1010 file.print "#{indent}if( #{len} > #{type.get_max} ){\t/* GenOpaqueMarshaler max check 2 */\n"
1011 file.print "#{indent} ercd_ = E_PAR;\n"
1012 file.print "#{indent} goto error_reset;\n"
1013 file.print "#{indent}}\n"
1014 end
1015
1016 file.print <<EOT
1017#{indent}if((ercd_=#{alloc_cp}(sizeof(#{type.get_type.get_type_str}#{type.get_type.get_type_str_post})*#{len},(void **)&#{outer}#{name}#{outer2}#{alloc_cp_extra}))!=E_OK)\t/* GenOpaqueMarshaler 1 */
1018#{indent} goto error_reset;
1019EOT
1020
1021 if type.get_type.kind_of? PtrType then
1022 file.print "#{indent}{\n"
1023 file.print "#{indent} #{loop_counter_type.get_type_str} i__#{nest}, length__#{nest} = #{len};\n"
1024 file.print "#{indent} for( i__#{nest} = 0; i__#{nest} < length__#{nest}; i__#{nest}++ ){\n"
1025 alloc_for_out_param( name, type.get_type, file, nest + 2, outer, "#{outer2}[i__#{nest}]", alloc_cp, alloc_cp_extra )
1026 file.print "#{indent} }\n"
1027 file.print "#{indent}}\n"
1028 end
1029
1030 else
1031 file.print <<EOT
1032#{indent}if((ercd_=#{alloc_cp}(sizeof(#{type.get_type.get_type_str}#{type.get_type.get_type_str_post}),(void **)&#{outer}#{name}#{outer2}#{alloc_cp_extra}))!=E_OK)\t/* GenOpaqueMarshaler 2 */
1033#{indent} goto error_reset;
1034EOT
1035 end
1036 end
1037 if org_type.is_nullable? then
1038 nest -= 1
1039 indent = "\t" * nest
1040 file.print "#{indent}} else {\n"
1041 file.print "#{indent} #{name} = NULL;\n"
1042 file.print "#{indent}}\n"
1043 nest += 1
1044 end
1045 end
1046
1047 #=== 引数の一括デアロケートコードの生成
1048 # send:マーシャラの最後、receive:アンマーシャラの最後で一括して引数をデアロケートする
1049 def dealloc_for_params( params, file, nest, dir, dealloc_cp, b_reset = false )
1050 if b_reset then
1051 reset_str = "_reset"
1052 else
1053 reset_str = ""
1054 end
1055
1056 params.each{ |param|
1057 if dir == param.get_direction then
1058 indent = "\t" * nest
1059 type = param.get_type.get_original_type
1060 aster = ""
1061 if dir == :RECEIVE then
1062 type = type.get_type.get_original_type # ポインタを一つ外す
1063 if b_reset then
1064 aster = "*"
1065 end
1066 end
1067 count = type.get_count; size = type.get_size
1068 if (size || count) && type.get_type.has_pointer? then
1069 if count then
1070 len = ", #{type.get_count.to_s}"
1071 elsif size then
1072 len = ", #{type.get_size.to_s}"
1073 end
1074 else
1075 len = ""
1076 end
1077 cp = "#{dealloc_cp}_#{param.get_name}_dealloc#{reset_str}".upcase
1078 file.print "#{indent}#{cp}(#{aster}#{param.get_name}#{len});\n"
1079 end
1080 }
1081 end
1082
1083 #== out で nullable な引数の情報を渡す
1084 # out nullable の場合、in, send, receive のように、値を渡す直前ではなく、呼出し時に渡す
1085 def print_out_nullable( params, file, nest, b_marshal );
1086 indent = "\t" * nest
1087 params.each{ |param|
1088 next if param.get_direction != :OUT
1089 next if ! param.is_nullable?
1090 if b_marshal then
1091 file.print "#{indent}if( (ercd_=cTDR_putInt8( (int8_t)(#{param.get_name} == NULL) )) != E_OK )\n"
1092 file.print "#{indent}\tgoto error_reset;\n"
1093 else
1094 # 呼び先は alloc_for_out_param で nullable の対応する
1095 file.print "#{indent}if( (ercd_=cTDR_getInt8( &b_#{param.get_name}_null_)) != E_OK )\n"
1096 file.print "#{indent}\tgoto error_reset;\n"
1097 end
1098 }
1099 end
1100end
Note: See TracBrowser for help on using the repository browser.