source: asp3_tinet_ecnl_rx/trunk/asp3_dcre/tecsgen/tecslib/plugin/lib/GenOpaqueMarshaler.rb@ 374

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

mbed関連を更新
シリアルドライバをmbedのHALを使うよう変更
ファイルディスクリプタの処理を更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-ruby;charset=UTF-8
File size: 40.6 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# TECS Generator
4# Generator for TOPPERS Embedded Component System
5#
6# Copyright (C) 2008-2018 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 if( (ercd_=cLockChannel_wait()) != E_OK )
468 goto error_reset;
469 }
470EOT
471
472 # SOP を送信
473 file.print " /* SOPの送出 */\n"
474 file.print " SET_RPC_STATE( state_, RPCSTATE_CLIENT_SEND_SOP );\n"
475 file.print " if( ( ercd_ = cTDR_sendSOP( true ) ) != E_OK )\n"
476 file.print " goto error_reset;\n"
477
478 # func_id を送信
479 file.print " /* 関数 id の送出 */\n"
480 file.print " if( ( ercd_ = cTDR_putInt16( func_id_ ) ) != E_OK )\n"
481 file.print " goto error_reset;\n"
482
483 # p "celltype_name, sig_name, func_name, func_global_name"
484 # p "#{ct_name}, #{sig_name}, #{func_name}, #{func_global_name}"
485
486 b_get = false # marshal なら put
487 b_marshal = true # marshal
488
489 # in 方向の入出力を出力
490 if func_type.has_inward? then
491 file.print " /* 入力引数送出 */\n"
492 file.print " SET_RPC_STATE( state_, RPCSTATE_CLIENT_SEND_BODY );\n"
493 print_params( params, file, 1, b_marshal, b_get, true, "eClientEntry", func_name )
494 print_params( params, file, 1, b_marshal, b_get, false, "eClientEntry", func_name )
495 end
496 print_out_nullable( params, file, 1, b_marshal );
497
498 if ! func_type.is_oneway? then
499 b_continue = "true"
500 else
501 b_continue = "false"
502 end
503 file.print " /* EOPの送出(パケットの掃きだし) */\n"
504 file.print " SET_RPC_STATE( state_, RPCSTATE_CLIENT_SEND_EOP );\n"
505 file.print " if( (ercd_=cTDR_sendEOP(#{b_continue})) != E_OK )\n"
506 file.print " goto error_reset;\n\n"
507
508 # send のメモリをデアロケート
509 if func_type.has_send? then
510 file.print " /* dealloc send parameter while executing */\n"
511 file.print " SET_RPC_STATE( state_, RPCSTATE_CLIENT_EXEC );\n"
512 dir = :SEND; nest = 1; dealloc_cp = "eClientEntry_#{func_name}"
513 dealloc_for_params( params, file, nest, dir, dealloc_cp )
514 file.print "\n"
515 end
516
517 if ! func_type.is_oneway? then
518
519 file.print " /* パケットの始まりをチェック */\n"
520 file.print " SET_RPC_STATE( state_, RPCSTATE_CLIENT_RECV_SOP );\n"
521 file.print " if( (ercd_=cTDR_receiveSOP( true )) != E_OK )\n"
522 file.print " goto error_reset;\n"
523
524 b_get = true # marshaler は get
525 file.print " /* 戻り値の受け取り */\n"
526 print_param( "retval_", func_type.get_type, file, 1, :RETURN, nil, nil, b_marshal, b_get )
527
528 if func_type.has_outward? then
529 if b_ret_er then
530 indent_level = 2
531 file.print " if( MERCD( retval_ ) != E_RPC ){\n"
532 else
533 indent_level = 1
534 end
535 indent = " " * indent_level
536
537 file.print "#{indent}/* 出力値の受け取り */\n"
538 file.print "#{indent}SET_RPC_STATE( state_, RPCSTATE_CLIENT_RECV_BODY );\n"
539 print_params( params, file, indent_level, b_marshal, b_get, true, "eClientEntry", func_name )
540 print_params( params, file, indent_level, b_marshal, b_get, false, "eClientEntry", func_name )
541
542 if b_ret_er then
543 file.print " }\n"
544 end
545 end
546
547 file.print "\n /* パケットの終わりをチェック */\n"
548 file.print " SET_RPC_STATE( state_, RPCSTATE_CLIENT_RECV_EOP );\n"
549 file.print " if( (ercd_=cTDR_receiveEOP(false)) != E_OK )\n" # b_continue = false
550 file.print " goto error_reset;\n"
551
552 end # ! func_type.is_oneway?
553
554 # channel lock コード
555 file.print <<EOT
556 /* Channel Unlock */
557 SET_RPC_STATE( state_, RPCSTATE_CLIENT_RELEASE_SEM );
558 if( is_cLockChannel_joined() ){
559 if( (ercd_=cLockChannel_signal()) != E_OK )
560 goto error_reset;
561 }
562EOT
563
564 file.print <<EOT
565 /* state_ is not used in normal case */
566 /* below is to avoid 'set but not used' warnning */
567 (void)state_;
568EOT
569
570 if( b_void == false )then
571 # 呼び元に戻り値をリターン
572 file.print( " return retval_;\n" )
573 else
574 file.print( " return;\n" )
575 end
576
577 file.print <<EOT
578
579error_reset:
580EOT
581 # send のメモリをデアロケート
582 if func_type.has_send? then
583 file.print " /* dealloc send parameter */\n"
584 file.print " if( state_ < RPCSTATE_CLIENT_EXEC ){\n"
585 dir = :SEND; nest = 2; dealloc_cp = "eClientEntry_#{func_name}"
586 dealloc_for_params( params, file, nest, dir, dealloc_cp )
587 file.print " }\n"
588 end
589
590 # receive のメモリをデアロケート
591 if func_type.has_receive? then
592 file.print( " /* receive parameter */\n" )
593 dir = :RECEIVE; nest = 1; dealloc_cp = "eClientEntry_#{func_name}"
594 dealloc_for_params( params, file, nest, dir, dealloc_cp, true )
595 end
596
597 file.print <<EOT
598 if( MERCD( ercd_ ) != E_RESET )
599 (void)cTDR_reset();
600EOT
601
602 # channel lock コード
603 file.print <<EOT
604 /* Channel Unlock */
605 if( is_cLockChannel_joined() )
606 cLockChannel_signal();
607
608 if( ercd_ != E_OK && is_cErrorHandler_joined() )
609 cErrorHandler_errorOccured( func_id_, ercd_, state_ );
610EOT
611
612 if( b_ret_er != false )then
613 # 呼び元に戻り値をリターン
614 file.print( " return ERCD( E_RPC, MERCD( ercd_ ) );\n" )
615 else
616 file.print( " return;\n" )
617 end
618
619 end
620
621 #=== unmarshal コードの生成
622 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 )
623
624 b_ret_er = true
625
626 # func_id を得るコードを生成
627 file.print <<EOT
628
629 int16_t func_id_;
630 ER ercd_ = E_OK;
631 int16_t state_;
632
633 #{ct_name}_CB *p_cellcb;
634
635 if( VALID_IDX( idx ) ){
636 p_cellcb = GET_CELLCB(idx);
637EOT
638
639 if b_ret_er then
640 file.print <<EOT
641 }else{
642 return E_ID;
643 }
644EOT
645 else
646 file.print <<EOT
647 }else{
648 /* エラー処理コードをここに記述 */
649 }
650EOT
651 end
652
653 file.print <<EOT
654
655#ifdef RPC_DEBUG
656 syslog(LOG_INFO, "Entering RPC service loop" );
657#endif
658
659 /* SOPのチェック */
660 SET_RPC_STATE( state_, RPCSTATE_SERVER_RECV_SOP );
661 if( (ercd_=cTDR_receiveSOP( false )) != E_OK )
662 goto error_reset;
663 /* func_id の取得 */
664 if( (ercd_=cTDR_getInt16( &func_id_ )) != E_OK )
665 goto error_reset;
666
667#ifdef RPC_DEBUG
668 syslog(LOG_INFO, "unmarshaler task: func_id: %d", func_id_ );
669#endif
670 switch( func_id_ ){
671EOT
672
673 # signature に含まれる すべての関数について
674 @signature.get_function_head_array.each { |f|
675 f_name = f.get_name
676 f_type = f.get_declarator.get_type
677 func_id = "FUNCID_#{@signature.get_global_name}_#{f_name}".upcase
678 fid = @signature.get_id_from_func_name( f_name )
679
680 file.print " case #{func_id}: /* (id of '#{f_name}') = #{fid} */ \n"
681 file.print " ercd_ = tOpaqueUnmarshaler_#{@signature.get_global_name}_#{f_name}( p_cellcb, &state_ );\n"
682 file.print " break;\n"
683
684 } #
685
686 if @PPAllocatorSize then
687 ppallocator_dealloc_str = " /* PPAllocator のすべてを解放 */\n cPPAllocator_dealloc_all();"
688 else
689 ppallocator_dealloc_str = ""
690 end
691
692 file.print <<EOT
693 default:
694 syslog(LOG_INFO, "unmarshaler task: ERROR: unknown func_id: %d", func_id_ );
695 ercd_ = E_ID;
696 };
697error_reset: /* OK cases also come here */
698#{ppallocator_dealloc_str}
699 if( ercd_ == E_OK )
700 return ercd_;
701 if( is_cErrorHandler_joined() )
702 ercd_ = cErrorHandler_errorOccured( func_id_, ercd_, state_ );
703 if( MERCD( ercd_ ) != E_RESET )
704 (void)cTDR_reset();
705 return ercd_;
706EOT
707
708 end
709
710 #=== PREAMBLE 部のコード生成
711 # アンマーシャラセルタイプの場合、アンマーシャラ関数のプロトタイプ宣言を生成
712 def gen_preamble file, b_singleton, ct_name, global_name
713 if ct_name != @unmarshaler_celltype_name.to_sym then
714 return
715 end
716
717 # string.h の include (memset, strlen のため)
718 file.print "/* header file (strlen, memset) */\n"
719 file.print "#include\t<string.h>\n\n"
720
721 file.print "/* アンマーシャラ関数のプロトタイプ宣言 */\n"
722 # signature に含まれる すべての関数について
723 @signature.get_function_head_array.each { |f|
724 f_name = f.get_name
725 f_type = f.get_declarator.get_type
726 id = @signature.get_id_from_func_name( f_name )
727 file.print "static ER tOpaqueUnmarshaler_#{@signature.get_global_name}_#{f_name}(CELLCB *p_cellcb, int16_t *state);\t/* func_id: #{id} */\n"
728 }
729 file.print "\n"
730 end
731
732 #=== POSTAMBLE 部のコード生成
733 # アンマーシャラセルタイプの場合、個々のアンマーシャラ関数の生成
734 def gen_postamble file, b_singleton, ct_name, global_name
735 if ct_name != @unmarshaler_celltype_name.to_sym then
736 return
737 end
738
739 file.print "\n/*** アンマーシャラ関数 ***/\n\n"
740 @signature.get_function_head_array.each { |f|
741 f_name = f.get_name
742 f_type = f.get_declarator.get_type
743 id = @signature.get_id_from_func_name( f_name )
744
745 # 関数は返り値を持つか?
746 b_ret_er = false
747 init_retval = ""
748 if f_type.get_type.is_void? then
749 b_void = true
750 else
751 b_void = false
752 if f_type.get_type.get_type_str == "ER" || f_type.get_type.get_type_str == "ER_INT" then
753 b_ret_er = true
754 init_retval = " = E_OK"
755 end
756 end
757
758 file.print <<EOT
759/*
760 * name: #{f_name}
761 * func_id: #{id}
762 */
763EOT
764 file.print "static ER\n"
765 file.print "tOpaqueUnmarshaler_#{@signature.get_global_name}_#{f_name}(CELLCB *p_cellcb, int16_t *state_)\t\t\n"
766 file.print "{\n"
767 file.print " ER ercd_;\n"
768
769 # 引数を受取る変数の定義
770 params = f.get_declarator.get_type.get_paramlist.get_items
771 # FuncHead-> Decl-> FuncType->ParamList
772 params.each{ |par|
773 name = par.get_name
774 type = par.get_type.get_original_type
775
776 dir = par.get_direction
777 if( dir == :RECEIVE )then
778 # type は PtrType で、それを取り除いた型
779 type = type.get_type
780 end
781 if( dir == :SEND || dir == :RECEIVE )then
782 init = " = 0"
783 else
784 init = ""
785 end
786
787 if type.kind_of? ArrayType then
788 type = type.get_type
789 aster = "(*"
790 aster2 = ")"
791 else
792 aster = ""
793 aster2 = ""
794 end
795
796 type_str = type.get_type_str.gsub( /\bconst\b */, "" ) # "const" を外す
797 file.printf( " %-12s %s%s%s%s%s;\n", type_str, aster, name, aster2, type.get_type_str_post, init )
798
799 if dir == :OUT && type.is_nullable? then
800 file.print( " int8_t\tb_#{name}_null_;\n" )
801 end
802 }
803
804 if ! b_void then
805 file.printf( " %-12s retval_%s%s;\n", f_type.get_type.get_type_str, f_type.get_type.get_type_str_post, init_retval )
806 end
807
808 # in 方向の入出力を入力
809 file.print "\n /* 入力引数受取 */\n"
810 file.print " SET_RPC_STATE( *state_, RPCSTATE_SERVER_RECV_BODY );\n"
811 b_get = true # unmarshal では get
812 b_marshal = false
813 print_params( params, file, 1, b_marshal, b_get, true, "cServerCall", f_name )
814 print_params( params, file, 1, b_marshal, b_get, false, "cServerCall", f_name )
815 print_out_nullable( params, file, 1, b_marshal );
816
817
818 # パケットの受信完了
819 file.print " /* パケット終わりをチェック */\n"
820 file.print " SET_RPC_STATE( *state_, RPCSTATE_SERVER_RECV_EOP );\n"
821 if ! f_type.is_oneway? then
822 b_continue = "true"
823 else
824 b_continue = "false"
825 end
826 file.print " if( (ercd_=cTDR_receiveEOP(#{b_continue})) != E_OK )\n"
827 file.print " goto error_reset;\n\n"
828
829 # out のメモリをアロケート
830 dir = :OUT; alloc_cp = "cPPAllocator_alloc"; alloc_cp_extra = nil; nest = 1
831 alloc_for_out_params( params, file, nest, dir, alloc_cp, alloc_cp_extra )
832
833 # 対象関数を呼出す
834 file.print " /* 対象関数の呼出し */\n"
835 file.print " SET_RPC_STATE( *state_, RPCSTATE_SERVER_EXEC );\n"
836 if b_void then
837 file.print( " cServerCall_#{f_name}(" )
838 else
839 file.print( " retval_ = cServerCall_#{f_name}(" )
840 end
841
842 delim = " "
843 params.each{ |par|
844 file.print delim
845 delim = ", "
846 if par.get_direction == :RECEIVE then
847 file.print "&"
848 end
849 file.print par.get_name
850 }
851 file.print( " );\n" )
852
853 # 戻り値、出力引数の受取コードの生成
854
855 # oneway の場合出力、戻り値が無く、受取を待たない(非同期な呼出し)
856 if ! f.is_oneway? then
857
858 file.print "\n /* SOPの送出 */\n"
859 file.print " SET_RPC_STATE( *state_, RPCSTATE_SERVER_SEND_SOP );\n"
860
861 file.print " if( ( ercd_ = cTDR_sendSOP( false ) ) != E_OK )\n"
862 file.print " goto error_reset;\n"
863
864 b_get = false # unmarshaler は put
865 if( ! b_void )then
866 file.print " /* 戻り値の送出 */\n"
867 print_param( "retval_", f_type.get_type, file, 1, :RETURN, nil, nil, b_marshal, b_get )
868 end
869
870 if f_type.has_outward? then
871 if b_ret_er then
872 indent_level = 2
873 file.print " if( MERCD( retval_ ) != E_RPC ){\n"
874 else
875 indent_level = 1
876 end
877 indent = " " * indent_level
878
879 file.print "#{indent}/* 出力値の送出 */\n"
880 file.print "#{indent}SET_RPC_STATE( *state_, RPCSTATE_SERVER_SEND_BODY );\n"
881 print_params( params, file, indent_level, b_marshal, b_get, true, "cServerCall", f_name )
882 print_params( params, file, indent_level, b_marshal, b_get, false, "cServerCall", f_name )
883
884 # receive のメモリをデアロケート
885 if f_type.has_receive? then
886 file.print "#{indent}/* dealloc receive parameter */\n"
887 dir = :RECEIVE; dealloc_cp = "cServerCall_#{f_name}"
888 dealloc_for_params( params, file, indent_level, dir, dealloc_cp )
889 end
890
891 if b_ret_er then
892 file.print " }\n"
893 end
894 end
895
896 file.print " /* パケットの終わり(掃きだし) */\n"
897 file.print " SET_RPC_STATE( *state_, RPCSTATE_SERVER_SEND_EOP );\n"
898 file.print " if( (ercd_=cTDR_sendEOP(false)) != E_OK )\n" # b_continue = false
899 file.print " goto error_reset;\n"
900 end # ! f.is_oneway?
901
902 file.print " return E_OK;\n"
903 file.print <<EOT
904
905error_reset:
906EOT
907 # send のリセット用デアロケート
908 if f_type.has_send? then
909 file.print " /* dealloc send parameter */\n"
910 file.print " if( *state_ < RPCSTATE_SERVER_EXEC ){\n"
911 dir = :SEND; indent_level = 2; dealloc_cp = "cServerCall_#{f_name}"
912 dealloc_for_params( params, file, indent_level, dir, dealloc_cp, true )
913 file.print " }\n"
914 end
915
916 # receive のメモリをデアロケート
917 if f_type.has_receive? && b_ret_er then
918 file.print " /* dealloc receive parameter */\n"
919 file.print " if( MERCD( retval_ ) != E_RPC ){\n"
920 dir = :RECEIVE; indent_level = 2; dealloc_cp = "cServerCall_#{f_name}"
921 dealloc_for_params( params, file, indent_level, dir, dealloc_cp )
922 file.print " }\n"
923 end
924
925 file.print " return ERCD( E_RPC, MERCD( ercd_ ) );\n"
926 file.print "}\n\n"
927
928 # ここ(個々の関数)ではエラーハンドラーは呼び出さない。呼び元(サーバーのメイン関数)で呼び出す。
929 }
930 end
931
932
933 #b_marshal:: bool
934 #b_get:: bool
935 # b_marshal = true && b_get == false : マーシャラで入力引数送出
936 # b_marshal = true && b_get == true : マーシャラで出力引数受取
937 # b_marshal = false && b_get == false : アンマーシャラで入力引数受取
938 # b_marshal = false && b_get == true : アンマーシャラで出力引数送出
939 #b_referenced:: size_is, count_is, string で参照されているものを出力
940 def print_params( params, file, nest, b_marshal, b_get, b_referenced, port_name, func_name )
941 params.each{ |param|
942# p "#{param.get_name}: b_marshal: #{b_marshal} b_get: #{b_get}"
943 if ! ( b_referenced == param.is_referenced? ) then
944 next
945 end
946
947 dir = param.get_direction
948 if( b_get == false && b_marshal == true || b_get == true && b_marshal == false )then
949 case dir
950 when :IN, :INOUT
951 alloc_cp = "cPPAllocator_alloc"
952 alloc_cp_extra = nil
953 print_param( param.get_name, param.get_type, file, nest, dir, nil, nil, b_marshal, b_get, alloc_cp, alloc_cp_extra )
954 when :SEND
955 alloc_cp = "#{port_name}_#{func_name}_#{param.get_name}_alloc"
956 alloc_cp_extra = nil
957 print_param( param.get_name, param.get_type, file, nest, dir, nil, nil, b_marshal, b_get, alloc_cp, alloc_cp_extra )
958 end
959 else
960 case dir
961 when :OUT, :INOUT
962 alloc_cp = nil # inout の b_get==true&&b_marsha==true のときアロケータコードは不用
963 alloc_cp_extra = nil
964 print_param( param.get_name, param.get_type, file, nest, dir, nil, nil, b_marshal, b_get, alloc_cp, alloc_cp_extra )
965 when :RECEIVE
966 alloc_cp = "#{port_name}_#{func_name}_#{param.get_name}_alloc"
967 alloc_cp_extra = nil
968 if b_get then
969 outer = "(*" # マーシャラ側では、ポインタが (send と比べ) 一つ多い
970 outer2 = ")"
971 else
972 outer = nil # アンマーシャラ側では、ポインタが一つ外されている
973 outer2 = nil
974 end
975 type = param.get_type.get_referto
976 print_param( param.get_name, type, file, nest, dir, outer, outer2, b_marshal, b_get, alloc_cp, alloc_cp_extra )
977 end
978 end
979 }
980 end
981
982 #=== アロケータコードを生成 (out のアンマーシャラ用)
983 def alloc_for_out_params( params, file, nest, dir, alloc_cp, alloc_cp_extra )
984 params.each{ |param|
985 dir = param.get_direction
986 if dir == :OUT then
987 alloc_for_out_param( param.get_name, param.get_type, file, nest, nil, nil, alloc_cp, alloc_cp_extra )
988 end
989 }
990 end
991
992 #=== アロケータコードを生成 (out のアンマーシャラ用個別パラメータの生成)
993 def alloc_for_out_param( name, type, file, nest, outer, outer2, alloc_cp, alloc_cp_extra )
994 org_type = type.get_original_type
995 if org_type.is_nullable? then
996 indent = "\t" * nest
997 file.print "#{indent}if( ! b_#{name}_null_ ){\n"
998 nest += 1
999 end
1000 case org_type
1001 when PtrType
1002 indent = "\t" * nest
1003 count = type.get_count; size = type.get_size; string = type.get_string
1004 if count || size || string then
1005 loop_counter_type = IntType.new(16) # mikan 方を size_is, count_is の引数の型とする
1006 if count then
1007 len = type.get_count.to_s
1008 elsif size then
1009 len = type.get_size.to_s
1010 elsif string then
1011 if type.get_string.instance_of? Expression then
1012 len = type.get_string.to_s
1013 else
1014 raise "unsuscripted string used for out parameter #{name}"
1015 end
1016 end
1017
1018 # size_is に max 指定がある場合、length が max を超えているかチェックするコードを生成
1019 if org_type.get_max != nil && string == nil then
1020 file.print "#{indent}if( #{len} > #{type.get_max} ){\t/* GenOpaqueMarshaler max check 2 */\n"
1021 file.print "#{indent} ercd_ = E_PAR;\n"
1022 file.print "#{indent} goto error_reset;\n"
1023 file.print "#{indent}}\n"
1024 end
1025
1026 file.print <<EOT
1027#{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 */
1028#{indent} goto error_reset;
1029EOT
1030
1031 if type.get_type.kind_of? PtrType then
1032 file.print "#{indent}{\n"
1033 file.print "#{indent} #{loop_counter_type.get_type_str} i__#{nest}, length__#{nest} = #{len};\n"
1034 file.print "#{indent} for( i__#{nest} = 0; i__#{nest} < length__#{nest}; i__#{nest}++ ){\n"
1035 alloc_for_out_param( name, type.get_type, file, nest + 2, outer, "#{outer2}[i__#{nest}]", alloc_cp, alloc_cp_extra )
1036 file.print "#{indent} }\n"
1037 file.print "#{indent}}\n"
1038 end
1039
1040 else
1041 file.print <<EOT
1042#{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 */
1043#{indent} goto error_reset;
1044EOT
1045 end
1046 end
1047 if org_type.is_nullable? then
1048 nest -= 1
1049 indent = "\t" * nest
1050 file.print "#{indent}} else {\n"
1051 file.print "#{indent} #{name} = NULL;\n"
1052 file.print "#{indent}}\n"
1053 nest += 1
1054 end
1055 end
1056
1057 #=== 引数の一括デアロケートコードの生成
1058 # send:マーシャラの最後、receive:アンマーシャラの最後で一括して引数をデアロケートする
1059 def dealloc_for_params( params, file, nest, dir, dealloc_cp, b_reset = false )
1060 if b_reset then
1061 reset_str = "_reset"
1062 else
1063 reset_str = ""
1064 end
1065
1066 params.each{ |param|
1067 if dir == param.get_direction then
1068 indent = "\t" * nest
1069 type = param.get_type.get_original_type
1070 aster = ""
1071 if dir == :RECEIVE then
1072 type = type.get_type.get_original_type # ポインタを一つ外す
1073 if b_reset then
1074 aster = "*"
1075 end
1076 end
1077 count = type.get_count; size = type.get_size
1078 if (size || count) && type.get_type.has_pointer? then
1079 if count then
1080 len = ", #{type.get_count.to_s}"
1081 elsif size then
1082 len = ", #{type.get_size.to_s}"
1083 end
1084 else
1085 len = ""
1086 end
1087 cp = "#{dealloc_cp}_#{param.get_name}_dealloc#{reset_str}".upcase
1088 file.print "#{indent}#{cp}(#{aster}#{param.get_name}#{len});\n"
1089 end
1090 }
1091 end
1092
1093 #== out で nullable な引数の情報を渡す
1094 # out nullable の場合、in, send, receive のように、値を渡す直前ではなく、呼出し時に渡す
1095 def print_out_nullable( params, file, nest, b_marshal );
1096 indent = "\t" * nest
1097 params.each{ |param|
1098 next if param.get_direction != :OUT
1099 next if ! param.is_nullable?
1100 if b_marshal then
1101 file.print "#{indent}if( (ercd_=cTDR_putInt8( (int8_t)(#{param.get_name} == NULL) )) != E_OK )\n"
1102 file.print "#{indent}\tgoto error_reset;\n"
1103 else
1104 # 呼び先は alloc_for_out_param で nullable の対応する
1105 file.print "#{indent}if( (ercd_=cTDR_getInt8( &b_#{param.get_name}_null_)) != E_OK )\n"
1106 file.print "#{indent}\tgoto error_reset;\n"
1107 end
1108 }
1109 end
1110end
Note: See TracBrowser for help on using the repository browser.