source: EcnlProtoTool/trunk/asp3_dcre/tecsgen/tecslib/plugin/NotifierPlugin.rb@ 321

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

文字コードを設定

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-ruby;charset=UTF-8
File size: 35.9 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2015 by Ushio Laboratory
4# Graduate School of Engineering Science, Osaka Univ., JAPAN
5# Copyright (C) 2015-2016 by Embedded and Real-Time Systems Laboratory
6# Graduate School of Information Science, Nagoya Univ., JAPAN
7#
8
9NotifierPluginArgProc = {
10 "factory" => Proc.new { |obj, rhs| obj.set_factory(rhs) },
11 "output_file" => Proc.new { |obj, rhs| obj.set_factory_output_file(rhs) }
12}
13
14class NotifierPlugin < CelltypePlugin
15
16 # ---------- アダプタ関数の生成 -------------
17 #
18 # siHandlerBodyの受け口関数は,タイムイベント通知の通知先として直接指定する
19 # ことはできない.シグネチャが一致していないことが理由である.このため,アダ
20 # プタとして動作する関数を生成し,カーネルからの呼出しをTECSの呼出しに変換で
21 # きるようにする必要がある.
22 #
23 # 基本的には,受け口毎にアダプタ関数を生成すれば十分である.しかし,これでは
24 # メモリ消費量が不必要に増加してしまう.そこで,通知先関数にintptr_t型の引数
25 # を渡せることに着目し,関数の"一般化"を図る.すなわち受け口のある属性(ここ
26 # では,結合先のセル,添字などを指す)を,アダプタ関数の引数として受け取れる
27 # ようにし,1個のアダプタ関数を2個以上の結合に対し用いることができるように
28 # する.
29 #
30 # アダプタ関数の属性について整理すると,
31 # - 受け口関数 - 一般化を行うと,実行時コストが大きく増大してしまうことが
32 # 確認されている.このため,一般化は行わない.EntryPropertyにも含めない.
33 # - セルインデックス - CELLIDX型で,型の規定はないが,"ポインタ値であったり
34 # 整数値であったりする。" (TECS 5.3.6) より,インデックスかポインタある
35 # ことが分かる.インデックスだとすると,この値はセルCBのアドレッシングに
36 # 使用されるので,intptr_tに収まる筈である.ポインタの場合,当然intptr_t
37 # に収まる.
38 # - 受け口配列の添字 - int_t.同様にintptr_tに収まる筈である.
39 # これらのうち,セルインデックスと受け口配列の添字はパラメータに含めることが
40 # できそうであるが,両方は無理である.
41 # 両方を格納した配列を生成し,その配列の要素へのポインタを渡すようにするとい
42 # う選択肢も可能であるが,実行速度を優先するために,この方法はとらなかった.
43 #
44 # このため,一般化は以下のパターンに分類して行う.
45 #
46 # 1. セルインデックスのみ一般化.セルインデックスのパターン数が受け口配列の
47 # 添字のパターン数より多いか,あるいは受け口が配列でない場合に行われる.
48 # 2. 受け口配列の添字のみ一般化.この場合,セルごとに異なる関数を用いる.
49 #
50 # これより,各受け口関数について,アダプタ関数の生成個数は,
51 # O(min{セルインデックスのパターン数, 添字のパターン数})
52 # となる.
53 #
54 # プラグインでの処理をワンパスで行うために,tecsgen.cfgではアダプタ関数を直
55 # 接指定するのではなく,代わりにアダプタ関数を表すマクロを使用する.この
56 # マクロはアダプタ関数ハンドルと呼ぶことにする.
57 # アダプタ関数ハンドルは,次の2個の要素から成る.
58 # - アダプタ関数へののポインタ
59 # - アダプタ関数の引数
60
61 # @private
62 class AdapterGenerator
63
64 # 結合先に関する属性を含む.セル,受け口配列の添字から成る.
65 # 同一のEntryPropertyとなる結合は,全く同じ方法でその受け口関数を呼び
66 # 出せる.
67 # @private
68 class EntryProperty
69 # @return [Cell] 受け口側のセル.
70 attr_reader :cell
71
72 # @return [Integer, nil] 受け口配列の添字.配列でない場合はnil.
73 attr_reader :subscript
74
75 def initialize(cell, subscript)
76 @cell = cell
77 @subscript = subscript
78 end
79
80 def self.from_join(join)
81 EntryProperty.new(join.get_rhs_cell, join.get_rhs_subscript)
82 end
83
84 # 同値性の定義.Hashのキーとして使用するのに必要.
85 def eql?(o) @cell == o.cell && @subscript == o.subscript end
86 def hash() @cell.hash ^ @subscript.hash end
87 end
88
89 # @private
90 class EntryPort
91 # @param [Port] port 結合先のセルのセルタイプの受け口.
92 def initialize(port, prefix)
93 @port = port
94 @global_name = "#{prefix}_#{@port.get_celltype.get_global_name}_#{@port.get_name}"
95
96 # 受け口関数名.siHandlerBodyを想定しているので,関数名はmainで固定である.
97 @entry_fn_name = "#{@port.get_celltype.get_global_name}_#{@port.get_name}_main"
98
99 @props = [] # Array<EntryProperty>
100 @prop_map = {} # Hash<EntryProperty, Integer>
101 end
102
103 # @return [String] グローバルに一意(なものとして扱えるよう)な識別子.
104 attr_reader :global_name
105
106 # @return [Port]
107 attr_reader :port
108
109 # 指定したEntryPropertyに対応するアダプタ関数ハンドルを取得する.
110 # @param [EntryProperty] ep
111 # @return [String] アダプタ関数ハンドル.
112 # @private
113 def adapter_handle_for_entry_property(ep)
114 index = @prop_map.fetch(ep)
115 return [
116 "#{@global_name}_#{index}_fp",
117 "#{@global_name}_#{index}_arg"
118 ]
119 end
120
121 # 結合先の情報に応じたアダプタ関数をソース・ヘッダーに出力する.
122 # 一般化指定は,`cell`または`subscript`の一方のみ行うことができる.
123 #
124 # @param [AdapterGenerator] context
125 # @param [String] fn_name 関数名.
126 # @param [Cell, Symbol] cell セル.セルについて一般化する場合は `:generic`
127 # @param [Integer, Symbol, nil] subscript 添字.添字について一般化する場合は `:generic`
128 # @private
129 def generate_inner(context, fn_name, cell, subscript)
130 source_file = context.source_file
131 header_file = context.header_file
132
133 source_file.print "void #{fn_name}(intptr_t extinf) {\n"
134
135 params = []
136 ct = @port.get_celltype
137
138 # シングルトンセルタイプ以外では,CELLIDXの指定が必要.
139 unless ct.is_singleton?
140 if cell == :generic
141 params << "(CELLIDX)extinf"
142 else
143 # セルのCELLIDXを得る
144 if ct.has_INIB? || ct.has_CB?
145 params << ct.get_name_array(cell)[7]
146 else
147 params << "0"
148 end
149 end
150 end
151
152 # 受け口配列の添字.
153 if @port.get_array_size
154 if subscript == :generic
155 params << "(int_t)extinf"
156 else
157 params << "#{subscript}"
158 end
159 end
160
161 params_str = params.join(", ")
162
163 source_file.print "\t#{@entry_fn_name}(#{params_str});\n"
164 source_file.print "}\n\n"
165
166 header_file.print "extern void #{fn_name}(intptr_t extinf);\n\n"
167
168 end
169
170 # 指定したJoinに対応するアダプタ関数ハンドルを取得する.
171 # @return [Array] アダプタ関数ハンドル.
172 def make_adapter_handle(join)
173 prop = EntryProperty.from_join(join)
174 unless @prop_map.has_key?(prop)
175 @prop_map[prop] = @props.length
176 @props << prop
177 end
178 return adapter_handle_for_entry_property(prop)
179 end
180
181 # ソース・ヘッダーの記述を生成する.
182 # @param [AdapterGenerator] context
183 def generate(context)
184 header_file = context.header_file
185 return if @props.empty?
186
187 ct = @port.get_celltype
188
189 header_file.print "/*\n * #{@global_name}\n"
190
191 cells = @props.group_by { |prop| prop.cell }
192 subscripts = @props.group_by { |prop| prop.subscript }
193 no_cellidx = false
194 if !(ct.has_INIB? || ct.has_CB?)
195 # CB, INIB最適化により,CB, INIBが両方不要になったケース.
196 # CELLIDXが不要であるので,セルについて一般化しても意味
197 # はないので,添字による一般化を選択する.
198 generalize_by_cell_idx = false
199 no_cellidx = true
200
201 # 全てのセルを同一視する.
202 cells = { @props[0].cell => @props }
203
204 header_file.print " * No INIB & CB: generalized by subscript\n"
205 elsif @port.get_array_size
206 # 一般化パターンの分類を行うために,受け口側セルや添字の
207 # パターン数を分析して,最適な方を選択する.
208 generalize_by_cell_idx = cells.length >= subscripts.length
209 if generalize_by_cell_idx
210 header_file.print " * more cells than subscripts: generalized by cell\n"
211 else
212 header_file.print " * more subscripts than cells: generalized by subscript\n"
213 end
214 else
215 # 常にCELLIDXで一般化
216 generalize_by_cell_idx = true
217 header_file.print " * non-array entry port: generalized by cell\n"
218 end
219
220 header_file.print " */\n\n"
221
222 if generalize_by_cell_idx
223 # CELLIDXについて一般化
224 subscripts.each { |subscript, props|
225 if subscript
226 fn_name = "#{@global_name}_adap_#{subscript}"
227 else
228 # 受け口配列でない場合
229 fn_name = "#{@global_name}_adap"
230 end
231
232 generate_inner context, fn_name,
233 :generic, subscript
234
235 props.each { |prop|
236 handle = adapter_handle_for_entry_property(prop)
237
238 # セルのCELLIDXを得る
239 if ct.has_INIB? || ct.has_CB?
240 idx = ct.get_name_array(prop.cell)[7]
241 else
242 idx = "0"
243 end
244 header_file.print "\#define #{handle[0]} &#{fn_name}\n"
245 header_file.print "\#define #{handle[1]} #{idx}\n\n"
246 }
247 }
248 else
249 # 添字について一般化
250 cells.each { |cell, props|
251 if no_cellidx
252 # CB/INIB なし
253 fn_name = "#{@global_name}_adap"
254 else
255 fn_name = "#{@global_name}_adap_#{cell.get_global_name}"
256 end
257
258 generate_inner context, fn_name,
259 cell, :generic
260
261 props.each { |prop|
262 handle = adapter_handle_for_entry_property(prop)
263
264 header_file.print "\#define #{handle[0]} &#{fn_name}\n"
265 header_file.print "\#define #{handle[1]} #{prop.subscript || 0}\n\n"
266 }
267 }
268 end
269 end
270 end
271
272 # @private
273 attr :source_file
274
275 # @private
276 attr :header_file
277
278 # @param [String] celltype_name ハンドラ関数のセルタイプ.
279 # @param [String] prefix 名前衝突を防ぐためのプレフィックス.
280 def initialize(celltype_name, prefix)
281 @celltype_name = celltype_name
282 @prefix = prefix
283
284 # Hash<Port, EntryPort>
285 @entry_ports = {}
286 end
287
288 # ===AdapterGenerator#make_adapter_handle===
289 # 指定した結合の呼出しを行うためのアダプタ関数ハンドルを生成する.
290 # @return [Array] アダプタ関数ハンドル.
291 def make_adapter_handle(join)
292 entry_port = @entry_ports[join.get_rhs_port]
293 unless entry_port
294 entry_port = EntryPort.new(join.get_rhs_port,
295 "#{@celltype_name}_#{@prefix}")
296 @entry_ports[join.get_rhs_port] = entry_port
297 end
298 return entry_port.make_adapter_handle(join)
299 end
300
301 # ===AdapterGenerator#finish===
302 # 各受け口に対し,アダプタ関数を生成する.
303 def finish
304 @source_file = AppFile.open( "#{$gen}/#{@celltype_name}.c" )
305 @source_file.print "\n/* Generated by #{self.class.name} */\n\n"
306 @source_file.print "\#include \"#{@celltype_name}_aux.h\"\n\n"
307 @source_file.print "\#include \"#{@celltype_name}_tecsgen.h\"\n\n"
308
309 @header_file = AppFile.open( "#{$gen}/#{@celltype_name}.h" )
310 @header_file.print "\n/* Generated by #{self.class.name} */\n\n"
311
312 # NotifierPluginを使用するセルタイプが複数ある場合,それぞれに
313 # 対しAdapterGenerator#finishが呼び出される.tTimeEventHandler.hに
314 # 続けて書き込んでしまうと,ヘッダーガードの関係で2回目以降の記述
315 # が読み込まれなくなってしまう.このため,ファイル名 + セルタイプ名
316 # という少し特殊なヘッダーガードを用いる.
317 header_guard = "#{@celltype_name}_H_#{@prefix}"
318
319 @header_file.print "\#ifndef #{header_guard}\n"
320 @header_file.print "\#define #{header_guard}\n\n"
321
322 # カーネルコンフィギュレータを実行する際,ハンドラ受け口のセルタイプ
323 # のセルCBの定義が必要な場合がある.
324 @header_file.print "\#include \"#{@celltype_name}_aux.h\"\n\n"
325
326 # 結合先のセルタイプの定義は,自分のセルのtecsgen.hよりも先に
327 # 読み込まなければならないが,このプラグインが複数実行されると,
328 # 順序が崩れてしまう.そこで,結合先のセルタイプの定義はもう一つの
329 # ヘッダーファイル(tCelltypeName_aux.h)から読み込むようにする.
330 aux_header_file = AppFile.open( "#{$gen}/#{@celltype_name}_aux.h" )
331 aux_header_file.print "\n/* Generated by #{self.class.name} */\n\n"
332
333 aux_header_guard = "#{@celltype_name}_AUX_H_#{@prefix}"
334
335 aux_header_file.print "\#ifndef #{aux_header_guard}\n"
336 aux_header_file.print "\#define #{aux_header_guard}\n\n"
337
338 cb_type_only_guard = "#{@celltype_name}_AUX_H_#{@prefix}_CB_TYPE_ONLY"
339
340 # 結合先のセルタイプの定義を読み込む
341 aux_header_file.print "#ifndef TOPPERS_CB_TYPE_ONLY\n"
342 aux_header_file.print "#define TOPPERS_CB_TYPE_ONLY\n"
343 aux_header_file.print "#define #{cb_type_only_guard}\n"
344 aux_header_file.print "#endif\n"
345 @entry_ports.values.map { |ep|
346 ep.port.get_celltype
347 }.uniq.each { |ct|
348 hname = "#{ct.get_global_name}_tecsgen.#{$h_suffix}"
349 aux_header_file.print "\#include \"#{hname}\"\n"
350 }
351 aux_header_file.print "#ifdef #{cb_type_only_guard}\n"
352 aux_header_file.print "#undef #{cb_type_only_guard}\n"
353 aux_header_file.print "#undef TOPPERS_CB_TYPE_ONLY\n"
354 aux_header_file.print "#endif\n\n"
355
356 aux_header_file.print "\#endif\n"
357 aux_header_file.close
358
359 @entry_ports.each { |port, entry_port|
360 entry_port.generate self
361 }
362
363 @header_file.print "\#endif\n"
364
365 @source_file.close
366 @header_file.close
367 end
368
369 end
370
371 # ------ 通知のハンドラの種類の定義 -------
372
373 class Handler
374 def initialize(call_port_name)
375 @call_port_name = call_port_name
376 end
377
378 attr :call_port_name
379 end
380
381 # 通常のハンドラ
382 EVENT_HANDLER = Handler::new("ciNotificationHandler")
383
384 # エラーハンドラ (通常のハンドラが失敗した場合に呼び出される)
385 ERROR_HANDLER = Handler::new("ciErrorNotificationHandler")
386
387 HANDLERS = [
388 EVENT_HANDLER,
389 ERROR_HANDLER
390 ]
391
392 class HandlerAttribute
393 def initialize(name, error_name = nil)
394 @name = name
395 @error_name = error_name || (name + 'ForError')
396 end
397
398 def name_for_handler(handler)
399 case handler
400 when EVENT_HANDLER then return @name
401 when ERROR_HANDLER then return @error_name
402 else raise "unknown handler #{handler}"
403 end
404 end
405 end
406
407 # ------ 通知の属性の定義 -------
408 #
409 # ハンドラタイプに合致しない属性が指定された場合に
410 # エラーを出力できるよう、全ての属性をここで列挙する。
411
412 SETVAR_ADDR_ATTR = HandlerAttribute::new("setVariableAddress")
413 SETVAR_VALUE_ATTR = HandlerAttribute::new("setVariableValue")
414 INCVAR_ADDR_ATTR = HandlerAttribute::new("incrementedVariableAddress")
415 SNDDTQ_VALUE_ATTR = HandlerAttribute::new("dataqueueSentValue")
416 SETFLG_FLAG_ATTR = HandlerAttribute::new("flagPattern")
417
418 ATTRS = [
419 SETVAR_ADDR_ATTR,
420 SETVAR_VALUE_ATTR,
421 INCVAR_ADDR_ATTR,
422 SNDDTQ_VALUE_ATTR,
423 SETFLG_FLAG_ATTR
424 ]
425
426 # ------ ハンドラタイプの定義 -------
427
428 class BaseHandlerType
429
430 def initialize()
431 super
432
433 # HandlerAttribute[]
434 @required_attributes = []
435 end
436
437 attr :required_attributes
438
439 #=== NotifierPlugin#BaseHandlerType#validate_join
440 # 指定したセルの結合先が、このハンドラタイプに該当するかを検証
441 # handler:: Handler : ハンドラ
442 # cell:: Cell : セル
443 # join:: Join : 結合 (declarationがPortであるもの)
444 def validate_join(handler, cell, join)
445 return !generate_attr_map(handler, cell).nil?
446 end
447
448 #=== NotifierPlugin#BaseHandlerType#generate_attr_map
449 # 指定したセルの属性と、既知のHandlerAttributeのマッピングを
450 # 生成し、Hash<HandlerAttribute, Join> (各属性とそれに対応する
451 # Join(declarationがDeclのもの)を表すHash)、あるいは、
452 # マッピングが行えない場合(属性の不足、過剰)はnilを返す。
453 #
454 # handler:: Handler : ハンドラ
455 # cell:: Cell : セル
456 def generate_attr_map(handler, cell)
457 map = {}
458
459 join_list = cell.get_join_list
460
461 ATTRS.each { |known_attr|
462 attr_name = known_attr.name_for_handler(handler)
463 join = join_list.get_item(attr_name.to_sym)
464
465 # このセルタイプにおいて必須の属性か?
466 is_required = @required_attributes.include?(known_attr)
467
468 # 属性の指定が不足している? or 過剰?
469 # 注: ハンドラタイプの判別には、セルで値が指定されているか
470 # が考慮される。セルタイプで初期値が指定されていても、
471 # それはハンドラタイプの決定に影響しない。
472 return nil if join.nil? != !is_required
473
474 # 必要のない属性であり、指定もされていないので飛ばす
475 next if join.nil?
476
477 # TODO: attrの結合であることを検証
478
479 map[known_attr] = join
480 }
481
482 return map
483 end
484
485 #=== NotifierPlugin#BaseHandlerType#gen_cfg_handler_type
486 # タイムイベントの通知の種類を表すコンフィギュレータの記述を生成し、Stringまたはnilを返す
487 # handler:: Handler : ハンドラ
488 def gen_cfg_handler_type(handler)
489 raise "called abstract method gen_cfg_handler_type"
490 end
491
492 #=== NotifierPlugin#BaseHandlerType#gen_cfg_handler_parameters
493 # タイムイベントの通知の引数を表すコンフィギュレータの記述を生成し、String[]を返す
494 # handler:: Handler : ハンドラ
495 # join:: Join : 結合 (declarationがPortであるもの)
496 # attrMap:: Hash<HandlerAttribute, Join> :
497 # 各属性とそれに対応するJoin (declarationがDeclのもの)
498 # cell:: Cell : セル
499 # adpt_gen:: AdapterGenerator : アダプタ関数を生成するオブジェクト
500 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
501 return nil
502 end
503
504 #=== NotifierPlugin#BaseHandlerType#might_fail
505 # 通知の際、エラーが発生し、その結果エラー通知を呼ぶ必要が生じる
506 # かどうかを返す。
507 def might_fail
508 return false
509 end
510
511 end
512 class BaseTaskHandlerType < BaseHandlerType
513 def validate_join(handler, cell, join, *args)
514 return super(handler, cell, join, *args) &&
515 join && join.get_rhs_cell.get_celltype.get_name == :tTask
516 end
517 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
518 taskCell = join.get_cell
519 id_attr_join = taskCell.get_join_list.get_item(:id)
520 id_attr = join.get_rhs_cell.get_celltype.find(:id)
521 if id_attr_join
522 # セル生成時に初期化する場合
523 id = id_attr_join.get_rhs.to_s
524 else
525 # セルタイプの初期化値を使う場合
526 id = id_attr.get_initializer.to_s
527 end
528
529 # $id$等の置換
530 name_array = taskCell.get_celltype.get_name_array(taskCell)
531 id = taskCell.get_celltype.subst_name(id, name_array)
532
533 return [id]
534 end
535 def might_fail
536 return true
537 end
538 end
539 class ActivateTaskHandlerType < BaseTaskHandlerType
540 def validate_join(handler, cell, join, *args)
541 return super(handler, cell, join, *args) &&
542 join.get_port_name == :eiActivateNotificationHandler
543 end
544 def gen_cfg_handler_type(handler)
545 case handler
546 when EVENT_HANDLER then return "TNFY_ACTTSK"
547 when ERROR_HANDLER then return "TENFY_ACTTSK"
548 else raise "unknown handler #{handler}"
549 end
550 end
551 end
552 class WakeUpTaskHandlerType < BaseTaskHandlerType
553 def validate_join(handler, cell, join, *args)
554 return super(handler, cell, join, *args) &&
555 join.get_port_name == :eiWakeUpNotificationHandler
556 end
557 def gen_cfg_handler_type(handler)
558 case handler
559 when EVENT_HANDLER then return "TNFY_WUPTSK"
560 when ERROR_HANDLER then return "TENFY_WUPTSK"
561 else raise "unknown handler #{handler}"
562 end
563 end
564 end
565 class SetVariableHandlerType < BaseHandlerType
566 def initialize()
567 super
568 @required_attributes = [
569 SETVAR_ADDR_ATTR,
570 SETVAR_VALUE_ATTR
571 ] # .to_set
572 end
573 def validate_join(handler, cell, join, *args)
574 return super(handler, cell, join, *args) &&
575 join.nil? &&
576 handler == EVENT_HANDLER
577 end
578 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
579 var_addr = attrMap[SETVAR_ADDR_ATTR].get_rhs.to_s
580 var_value = attrMap[SETVAR_VALUE_ATTR].get_rhs.to_s
581
582 # $id$等の置換
583 name_array = cell.get_celltype.get_name_array(cell)
584 var_addr = cell.get_celltype.subst_name(var_addr, name_array)
585 var_value = cell.get_celltype.subst_name(var_value, name_array)
586
587 return [var_addr, var_value]
588 end
589 def gen_cfg_handler_type(handler)
590 case handler
591 when EVENT_HANDLER then return "TNFY_SETVAR"
592 else raise "unknown handler #{handler}"
593 end
594 end
595 end
596 class SetVariableToErrorCodeHandlerType < BaseHandlerType
597 def initialize()
598 super
599 @required_attributes = [
600 SETVAR_ADDR_ATTR
601 ] # .to_set
602 end
603 def validate_join(handler, cell, join, *args)
604 return super(handler, cell, join, *args) &&
605 join.nil? &&
606 handler == ERROR_HANDLER
607 end
608 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
609 var_addr = attrMap[SETVAR_ADDR_ATTR].get_rhs.to_s
610
611 # $id$等の置換
612 name_array = cell.get_celltype.get_name_array(cell)
613 var_addr = cell.get_celltype.subst_name(var_addr, name_array)
614
615 return [var_addr]
616 end
617 def gen_cfg_handler_type(handler)
618 case handler
619 when ERROR_HANDLER then return "TENFY_SETVAR"
620 else raise "unknown handler #{handler}"
621 end
622 end
623 end
624 class IncrementVariableHandlerType < BaseHandlerType
625 def initialize()
626 super
627 @required_attributes = [
628 INCVAR_ADDR_ATTR
629 ] # .to_set
630 end
631 def validate_join(handler, cell, join, *args)
632 return super(handler, cell, join, *args) &&
633 join.nil?
634 end
635 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
636 var_addr = attrMap[INCVAR_ADDR_ATTR].get_rhs.to_s
637
638 # $id$等の置換
639 name_array = cell.get_celltype.get_name_array(cell)
640 var_addr = cell.get_celltype.subst_name(var_addr, name_array)
641
642 return [var_addr]
643 end
644 def gen_cfg_handler_type(handler)
645 case handler
646 when EVENT_HANDLER then return "TNFY_INCVAR"
647 when ERROR_HANDLER then return "TENFY_INCVAR"
648 else raise "unknown handler #{handler}"
649 end
650 end
651 end
652 class SignalSemaphoreHandlerType < BaseHandlerType
653 def validate_join(handler, cell, join, *args)
654 return super(handler, cell, join, *args) &&
655 join && join.get_rhs_cell.get_celltype.get_name == :tSemaphore
656 end
657 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
658 semaphoreCell = join.get_cell
659 id_attr_join = semaphoreCell.get_join_list.get_item(:id)
660 id_attr = join.get_rhs_cell.get_celltype.find(:id)
661 if id_attr_join
662 # セル生成時に初期化する場合
663 id = id_attr_join.get_rhs.to_s
664 else
665 # セルタイプの初期化値を使う場合
666 id = id_attr.get_initializer.to_s
667 end
668
669 # $id$等の置換
670 name_array = semaphoreCell.get_celltype.get_name_array(semaphoreCell)
671 id = semaphoreCell.get_celltype.subst_name(id, name_array)
672
673 return [id]
674 end
675 def might_fail
676 return true
677 end
678 def gen_cfg_handler_type(handler)
679 case handler
680 when EVENT_HANDLER then return "TNFY_SIGSEM"
681 when ERROR_HANDLER then return "TENFY_SIGSEM"
682 else raise "unknown handler #{handler}"
683 end
684 end
685 end
686 class SetEventflagHandlerType < BaseHandlerType
687 def initialize()
688 super
689 @required_attributes = [
690 SETFLG_FLAG_ATTR
691 ] # .to_set
692 end
693 def validate_join(handler, cell, join, *args)
694 return super(handler, cell, join, *args) &&
695 join && join.get_rhs_cell.get_celltype.get_name == :tEventflag
696 end
697 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
698 eventflagCell = join.get_cell
699 id_attr_join = eventflagCell.get_join_list.get_item(:id)
700 id_attr = join.get_rhs_cell.get_celltype.find(:id)
701 if id_attr_join
702 # セル生成時に初期化する場合
703 id = id_attr_join.get_rhs.to_s
704 else
705 # セルタイプの初期化値を使う場合
706 id = id_attr.get_initializer.to_s
707 end
708 flg_pattern = attrMap[SETFLG_FLAG_ATTR].get_rhs.to_s
709
710 # $id$等の置換
711 name_array = eventflagCell.get_celltype.get_name_array(eventflagCell)
712 id = eventflagCell.get_celltype.subst_name(id, name_array)
713
714 name_array = cell.get_celltype.get_name_array(cell)
715 flg_pattern = cell.get_celltype.subst_name(flg_pattern, name_array)
716
717 return [id, flg_pattern]
718 end
719 def might_fail
720 return true
721 end
722 def gen_cfg_handler_type(handler)
723 case handler
724 when EVENT_HANDLER then return "TNFY_SETFLG"
725 when ERROR_HANDLER then return "TENFY_SETFLG"
726 else raise "unknown handler #{handler}"
727 end
728 end
729 end
730 class DataqueueHandlerType < BaseHandlerType
731 def initialize()
732 super
733 end
734 def validate_join(handler, cell, join, *args)
735 return super(handler, cell, join, *args) &&
736 join && join.get_rhs_cell.get_celltype.get_name == :tDataqueue
737 end
738 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
739 dataqueueCell = join.get_cell
740 id_attr_join = dataqueueCell.get_join_list.get_item(:id)
741 id_attr = join.get_rhs_cell.get_celltype.find(:id)
742 if id_attr_join
743 # セル生成時に初期化する場合
744 id = id_attr_join.get_rhs.to_s
745 else
746 # セルタイプの初期化値を使う場合
747 id = id_attr.get_initializer.to_s
748 end
749
750 # $id$等の置換
751 name_array = dataqueueCell.get_celltype.get_name_array(dataqueueCell)
752 id = dataqueueCell.get_celltype.subst_name(id, name_array)
753
754 name_array = cell.get_celltype.get_name_array(cell)
755
756 return [id]
757 end
758 def might_fail
759 return true
760 end
761 end
762 class SendToDataqueueHandlerType < DataqueueHandlerType
763 def initialize()
764 super
765 @required_attributes = [
766 SNDDTQ_VALUE_ATTR
767 ] # .to_set
768 end
769 def validate_join(handler, cell, join, *args)
770 return super(handler, cell, join, *args) && handler == EVENT_HANDLER
771 end
772 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
773 params = super(handler, join, attrMap, cell, adpt_gen)
774
775 sent_value = attrMap[SNDDTQ_VALUE_ATTR].get_rhs.to_s
776
777 # $id$等の置換
778 name_array = cell.get_celltype.get_name_array(cell)
779 sent_value = cell.get_celltype.subst_name(sent_value, name_array)
780
781 params << sent_value
782
783 return params
784 end
785 def gen_cfg_handler_type(handler)
786 case handler
787 when EVENT_HANDLER then return "TNFY_SNDDTQ"
788 else raise "unknown handler #{handler}"
789 end
790 end
791 end
792 class SendErrorCodeToDataqueueHandlerType < DataqueueHandlerType
793 def initialize()
794 super
795 end
796 def validate_join(handler, cell, join, *args)
797 return super(handler, cell, join, *args) && handler == ERROR_HANDLER
798 end
799 def gen_cfg_handler_type(handler)
800 case handler
801 when ERROR_HANDLER then return "TENFY_SNDDTQ"
802 else raise "unknown handler #{handler}"
803 end
804 end
805 end
806 class UserHandlerType < BaseHandlerType
807 def validate_join(handler, cell, join, *args)
808 return super(handler, cell, join, *args) &&
809 handler != ERROR_HANDLER && # invalid for error handler
810 join && join.get_rhs_cell.get_celltype.get_name == :tTimeEventHandler
811 end
812 def gen_cfg_handler_type(handler)
813 case handler
814 when EVENT_HANDLER then return "TNFY_HANDLER"
815 else raise "unknown handler #{handler}"
816 end
817 end
818 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
819 # tTimeEventHandlerの結合先を取得
820 handler_cell = join.get_rhs_cell
821 call_join = handler_cell.get_join_list.get_item(:ciHandlerBody)
822
823 # 結合されていない場合はtecsgenがエラーを出すはずなのでここでは
824 # エラーにせず無視する.
825 return [] unless call_join
826
827 # アダプタ関数ハンドルを取得
828 adapter_handle = adpt_gen.make_adapter_handle(call_join)
829 return [adapter_handle[1], adapter_handle[0]]
830 end
831 end
832 class NullHandlerType < BaseHandlerType
833 def validate_join(handler, cell, join, *args)
834 return super(handler, cell, join, *args) &&
835 join.nil? &&
836 handler != EVENT_HANDLER # handler is mandatory for normal handler!
837 end
838 def gen_cfg_handler_type(handler)
839 case handler
840 when ERROR_HANDLER then return nil
841 else raise "unknown handler #{handler}"
842 end
843 end
844 end
845
846 HANDLER_TYPES = [
847 ActivateTaskHandlerType.new,
848 WakeUpTaskHandlerType.new,
849 SetVariableHandlerType.new,
850 SetVariableToErrorCodeHandlerType.new,
851 IncrementVariableHandlerType.new,
852 SignalSemaphoreHandlerType.new,
853 SetEventflagHandlerType.new,
854 SendToDataqueueHandlerType.new,
855 SendErrorCodeToDataqueueHandlerType.new,
856 UserHandlerType.new,
857 NullHandlerType.new
858 ]
859
860 #@celltype:: Celltype
861 #@option:: String :オプション文字列
862 def initialize( celltype, option )
863 super
864 @plugin_arg_check_proc_tab = NotifierPluginArgProc
865 @plugin_arg_str = option
866 @plugin_arg_str = option.gsub( /\A"(.*)/, '\1' ) # 前後の "" を取り除く
867 @plugin_arg_str.sub!( /(.*)"\z/, '\1' )
868 @factory = nil
869 @output_file = nil
870 parse_plugin_arg
871 unless @factory
872 cdl_error("ASP1003 celltype $1: option factory is not specified",
873 celltype.get_name)
874 end
875 unless @output_file
876 cdl_error("ASP1003 celltype $1: option output_file is not specified",
877 celltype.get_name)
878 end
879 end
880
881 def set_factory(template_string)
882 unless @factory.nil?
883 cdl_error("ASP1003 celltype $1: option factory was specified more than once",
884 celltype.get_name)
885 end
886 @factory = template_string
887 end
888
889 def set_factory_output_file(output_file)
890 unless @output_file.nil?
891 cdl_error("ASP1003 celltype $1: option output_file was specified more than once",
892 celltype.get_name)
893 end
894 @output_file = output_file
895 end
896
897 def gen_factory file
898 puts "===== begin #{@celltype.get_name.to_s} plugin ====="
899
900 kernelCfg = AppFile.open( "#{$gen}/#{@output_file}" )
901 kernelCfg.print "\n/* Generated by #{self.class.name} */\n"
902 kernelCfg.print "\#include \"tTimeEventHandler.h\"\n"
903
904 # アダプタ関数を生成する準備
905 @adpt_gen = AdapterGenerator.new("tTimeEventHandler", @celltype.get_global_name)
906
907 # 属性置換が行えることを検証する。
908 # ここで行うのは、factoryで指定された属性名が
909 # 存在することを確認し、しなければエラーを出力することのみである。
910 # セルごとの処理の最中にエラーを出力することも可能ではあるが、
911 # そうするとセルタイプ側の問題であるのにもかかわらず、セルごとに
912 # エラーが表示されてしまう。
913 # {{attribute_name}} -> attribute_value
914 @factory.scan(/\{\{([a-zA-Z0-9_]*?)\}\}/) { |match|
915 name = $1.to_sym
916
917 # {{_handler_params_}} はハンドラに関する指定。プラグイン内で値が生成される
918 next if name == :_handler_params_
919
920 subst_attr = @celltype.find(name)
921 unless subst_attr
922 cdl_error( "ASP1007 celltype $1: additional_param: attribute $2 does not exist.",
923 @celltype.get_name, name)
924 end
925 }
926
927 @celltype.get_cell_list.each { |cell|
928 gen_factory_for_cell kernelCfg, cell
929 }
930
931 # アダプタ関数の生成を完了させる
932 @adpt_gen.finish
933
934 kernelCfg.close
935 puts "===== end #{@celltype.get_name.to_s} plugin ====="
936 end
937
938 def gen_factory_for_cell(kernelCfg, cell)
939 handler_flags = []
940 handler_args = []
941
942 event_handler_might_fail = true
943 handler_flag = nil
944
945 # ignoreErrorsを取得
946 ignoreErrors_attr_join = cell.get_join_list.get_item(:ignoreErrors)
947 ignoreErrors_attr = cell.get_celltype.find(:ignoreErrors)
948 if ignoreErrors_attr_join
949 # セル生成時に初期化する場合
950 ignoreErrors = ignoreErrors_attr_join.get_rhs.to_s
951 else
952 # セルタイプの初期化値を使う場合
953 ignoreErrors = ignoreErrors_attr.get_initializer.to_s
954 end
955 case ignoreErrors
956 when 'true' then ignoreErrors = true
957 when 'false' then ignoreErrors = false
958 else
959 cdl_warning( "ASP1005 cell $1: unrecognized value '$2' specified for ignoreErrors",
960 cell.get_name, ignoreErrors )
961 ignoreErrors = false
962 end
963
964 [EVENT_HANDLER, ERROR_HANDLER].each { |handler|
965 # 呼び口の結合を取得
966 call_join = cell.get_join_list.get_item(handler.call_port_name.to_sym)
967
968 # ハンドラタイプを判別する
969 matches = HANDLER_TYPES.select { |handler_type|
970 handler_type.validate_join(handler, cell, call_join)
971 }
972
973 if matches.length == 0
974 cdl_error( "ASP1001 cell $1: no matching handler type found for $2", cell.get_name, handler.call_port_name )
975 next
976 end
977
978 # 最初に見つかった有効なハンドラタイプを使用
979 ht = matches[0]
980
981 # 通知ハンドラで「エラーが発生するはずがない」のに「エラーハンドラが指定されている」
982 # もしくはその逆のパターンを検出する。
983 # (handler_flagがnilである場合、ハンドラタイプが不明であり、エラーが発生するか不明
984 # なため、検出は行わない。)
985 if handler == ERROR_HANDLER && !ht.is_a?(NullHandlerType) && !event_handler_might_fail
986 cdl_error( "ASP1004 cell $1: handler type $2 which never raises an error was inferred for the normal notification handler, but an error notification handler was specified.",
987 cell.get_name, handler_flag)
988 end
989 if handler == ERROR_HANDLER && ht.is_a?(NullHandlerType) && event_handler_might_fail && !ignoreErrors
990 cdl_warning( "ASP1006 cell $1: handler type $2 which might raise an error was inferred for the normal notificaton handler, but an error notification handler was not specified.",
991 cell.get_name, handler_flag)
992 end
993
994 # assertion
995 unless ht.validate_join(handler, cell, call_join)
996 raise "!validate_join"
997 end
998
999 # 通知方法の静的API記述を生成する
1000 handler_flag = ht.gen_cfg_handler_type(handler)
1001 handler_flags << handler_flag if handler_flag
1002
1003 attr_map = ht.generate_attr_map(handler, cell)
1004
1005 handler_arg = ht.gen_cfg_handler_parameters(handler, call_join, attr_map, cell, @adpt_gen)
1006 handler_args += handler_arg if handler_arg
1007
1008 if handler == EVENT_HANDLER
1009 event_handler_might_fail = ht.might_fail
1010 end
1011 }
1012
1013 # $id$等の置換
1014 name_array = cell.get_celltype.get_name_array(cell)
1015 handler_args.collect! { |e|
1016 if e == "$cbp$"
1017 cell.get_celltype.subst_name(e, name_array)
1018 else
1019 e
1020 end
1021 }
1022
1023 # tecsgen.cfgの記述を生成する。
1024 # factoryに対し、パラメータ置換を行う。
1025 # {{attribute_name}} -> attribute_value
1026 text = @factory.gsub(/\{\{([a-zA-Z0-9_]*?)\}\}/) { |match|
1027 name = $1.to_sym
1028 subst_attr = cell.get_celltype.find(name)
1029
1030 # {{_handler_params_}} はハンドラの指定に置換する。
1031 if name == :_handler_params_
1032 args_joined = handler_flags.join(' | ')
1033 if handler_args.length > 0
1034 args_joined << ", "
1035 args_joined << handler_args.join(', ')
1036 end
1037 next args_joined
1038 end
1039
1040 unless subst_attr
1041 # 属性が見つからないというエラーはすでに報告されているので
1042 # ここではダミー値を返しておくだけである。
1043 next ""
1044 end
1045
1046 subst_attr_join = cell.get_join_list.get_item(name)
1047 if subst_attr_join
1048 # セル生成時に初期化する場合
1049 subst = subst_attr_join.get_rhs.to_s
1050 else
1051 # セルタイプの初期化値を使う場合
1052 subst = subst_attr.get_initializer.to_s
1053 end
1054
1055 # $id$等の置換
1056 cell.get_celltype.subst_name(subst, name_array)
1057 }
1058
1059 # 出力
1060 kernelCfg.puts text
1061
1062 end
1063 private :gen_factory_for_cell
1064
1065end
Note: See TracBrowser for help on using the repository browser.