OSDN Git Service

bbdee44187ccb02ff82876b3baa35ce5464b55e8
[trx-305dsp/dsp.git] / trx305 / kernel / cfg / base / garbage.cpp
1 /*
2  *  TOPPERS/JSP Kernel
3  *      Toyohashi Open Platform for Embedded Real-Time Systems/
4  *      Just Standard Profile Kernel
5  * 
6  *  Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory
7  *                              Toyohashi Univ. of Technology, JAPAN
8  * 
9  *  上記著作権者は,以下の (1)〜(4) の条件か,Free Software Foundation 
10  *  によって公表されている GNU General Public License の Version 2 に記
11  *  述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア
12  *  を改変したものを含む.以下同じ)を使用・複製・改変・再配布(以下,
13  *  利用と呼ぶ)することを無償で許諾する.
14  *  (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
15  *      権表示,この利用条件および下記の無保証規定が,そのままの形でソー
16  *      スコード中に含まれていること.
17  *  (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
18  *      用できる形で再配布する場合には,再配布に伴うドキュメント(利用
19  *      者マニュアルなど)に,上記の著作権表示,この利用条件および下記
20  *      の無保証規定を掲載すること.
21  *  (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
22  *      用できない形で再配布する場合には,次のいずれかの条件を満たすこ
23  *      と.
24  *    (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
25  *        作権表示,この利用条件および下記の無保証規定を掲載すること.
26  *    (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
27  *        報告すること.
28  *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
29  *      害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
30  * 
31  *  本ソフトウェアは,無保証で提供されているものである.上記著作権者お
32  *  よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も
33  *  含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直
34  *  接的または間接的に生じたいかなる損害に関しても,その責任を負わない.
35  * 
36  *  @(#) $Id: garbage.cpp,v 1.1 2009/01/31 05:27:37 suikan Exp $
37  */
38
39 // $Header: /cvsroot/toppersjsp4bf/jsp/cfg/base/garbage.cpp,v 1.1 2009/01/31 05:27:37 suikan Exp $
40
41 #include "base/garbage.h"
42
43 #include <stdexcept>
44 #include <algorithm>
45
46 using namespace std;
47
48 TrashBox * TrashBox::current_box = 0;
49
50 //----------------------------------------------------------------
51 // Garbage : ゴミ
52
53     //コンストラクタ
54 Garbage::Garbage(void) throw()
55 {
56         //ゴミ箱に関連付ける
57     assigned_box = TrashBox::getCurrentTrashBox();
58     if(assigned_box->isValid())
59         cookie = assigned_box->addGarbage(this);
60 }
61
62     //デストラクタ
63 Garbage::~Garbage(void) throw()
64 {
65     rescue();
66 }
67
68     //ゴミ救出
69 void Garbage::rescue(void) throw()
70 {
71     if(assigned_box->isValid()) {
72         assigned_box->recoverGarbage(cookie);
73         assigned_box = 0;
74     }
75 }
76
77
78 //----------------------------------------------------------------
79 // TrashBox : ゴミを入れる箱
80
81 TrashBox::TrashBox(void) throw()
82 {
83         //ゴミ箱の差し替え
84     previous_box = current_box;
85     current_box  = this;
86 }
87
88 TrashBox::~TrashBox(void) throw()
89 {
90         //ゴミがなくなるまで削除
91     while(!garbage.empty()) {
92             //ふた
93         try{   cleanup();   }
94         catch(...) {}
95     }
96
97         //ゴミ箱の差し替え
98     current_box = previous_box;
99 }
100
101 /*
102     //ゴミ箱に入れたゴミを取り除く
103 void TrashBox::recoverGarbage(Garbage * _garbage, TrashBox::Cookie cookie) throw()
104 {
105     if(isValid() && _garbage != 0) {
106         bool forward = true;
107         list<Garbage *>::iterator scope;
108
109         if(!garbage.empty()) {
110             scope = garbage.erase(cookie);
111
112                 //自分が始末した
113             if(scope != garbage.end() || garbage.empty())
114                 forward = false;
115         }
116
117             //親ゴミ箱に回送
118         if(forward && previous_box->isValid())
119             previous_box->recoverGarbage(_garbage, cookie);
120     }
121 }
122 */
123     /*  修正時のメモ 
124               関連付けられたゴミ箱が消えることは無い(生成期間はゴミ箱のほうが長いはず)ので、親に回送する必要は無い。よってif(forward...節は不要。
125               自分が始末できないゴミは無いので(cleanupはrecoverGargabeを呼ばない)、eraseの返却値のチェックは不要。
126               個別削除要求はゴミから出されるので、実行された時点でゴミは1つ以上存在するはずなので、emptyチェックは不要.
127               この時点でeraseだけになり、第一引数は不要。
128     */
129
130     //ゴミ箱に入れたゴミを取り除く  
131 void TrashBox::recoverGarbage(TrashBox::Cookie cookie) throw()
132 {   garbage.erase(cookie);  }
133
134     //ゴミ箱を空にする
135 void TrashBox::cleanup(void)
136 {
137         //自分がトップレベルゴミ箱でなかったら失敗
138     if(current_box != this)
139         throw std::runtime_error("TrashBox::cleanup can be performed from the top level trash box only.");
140
141     try {
142         while(!garbage.empty())
143             delete *garbage.begin();        //ゴミリストから要素を外すのは子の役目
144     }
145     catch(...) {
146         garbage.erase(garbage.begin());     //例外を起こした最初の要素を削除
147         throw;                              //再送
148     }
149 }
150
151
152
153 /****************************************** テストスィート ******************************************/
154
155 #ifdef TESTSUITE
156 #include "coverage_undefs.h"
157
158 namespace { int counter = 0; }
159
160 #ifdef _MSC_VER
161     class DummyGarbage : public Garbage
162     {
163     public:
164         int * count;
165         bool throw_exception;
166
167         DummyGarbage(int * _count = 0) : count(_count), throw_exception(false)
168         { TestSuite::check("DummyGarbage::DummyGarbage");  }
169
170         ~DummyGarbage(void) throw(int)
171         {
172             if(count != 0) *count = ++counter;
173             if(throw_exception) throw 0;
174             TestSuite::check("DummyGarbage::~DummyGarbage"); 
175         }
176
177     };
178 #elif __GNUC__
179     class DummyGarbage : public Garbage
180     {
181     public:
182         int * count;
183
184         DummyGarbage(int * _count = 0) : count(_count)
185         { TestSuite::check("DummyGarbage::DummyGarbage");  }
186
187         ~DummyGarbage(void) throw()
188         {
189             if(count != 0) *count = ++counter;
190             TestSuite::check("DummyGarbage::~DummyGarbage"); 
191         }
192     };
193 #endif
194
195 TESTSUITE(main, TrashBox)
196 {
197     BEGIN_CASE("1","ゴミ箱を作ると登録される") {
198         TrashBox mybox;
199         TEST_CASE("1", "作ったゴミ箱が現在のゴミ箱になっている", TrashBox::current_box == &mybox);
200         
201         {
202             TrashBox mybox2;
203             TEST_CASE("2", "作ったゴミ箱が現在のゴミ箱になっている (2)", TrashBox::current_box == &mybox2);
204             TEST_CASE("3", "もともとのゴミ箱が保存されている", mybox2.previous_box == &mybox);
205         }
206
207         TEST_CASE("4", "もとのゴミ箱に戻る", TrashBox::current_box == &mybox);
208     } END_CASE;
209
210     BEGIN_CASE("2","isValid") {
211         TrashBox mybox;
212
213         TEST_CASE("1","作ったゴミ箱は正常", mybox.isValid());
214         TEST_CASE("2","NULL箱は異常", !((TrashBox *)0)->isValid());
215     } END_CASE;
216
217     BEGIN_CASE("3","operator new") {
218         BEGIN_CASE("1","new TrashBoxはbad_alloc例外を返す") {
219             bool result = false;
220
221             try { TrashBox * box = new TrashBox; }
222             catch(bad_alloc) { result = true; }
223
224             if(!result)
225                 TEST_FAIL;
226         } END_CASE;
227
228         BEGIN_CASE("2","new(nothrow) TrashBoxはNULLを返す") {
229             bool result = true;
230             TrashBox * box;
231
232             try { box = new(nothrow) TrashBox; }
233             catch(...) { result = false; }
234
235             TEST_CASE("1", "new(nothrow)は例外を返さない", result);
236             TEST_CASE("2", "new(nothrow)はNULLを返す",   box == 0);
237         } END_CASE;
238     } END_CASE;
239
240     BEGIN_CASE("4","基本的な生成削除") {
241         BEGIN_CASE("1","ちゃんとゴミ箱から外せる") {
242             TrashBox mybox;
243
244             DummyGarbage * garbage = new DummyGarbage;
245
246             TEST_CASE("0","[前提] ゴミが入っている", std::find(mybox.garbage.begin(), mybox.garbage.end(), garbage) != mybox.garbage.end());
247             delete garbage;
248             TEST_CASE("1","ゴミが消えている", std::find(mybox.garbage.begin(), mybox.garbage.end(), garbage) == mybox.garbage.end());
249
250
251         } END_CASE;
252
253         BEGIN_CASE("2","親のゴミ箱に入っているものもゴミ箱から外せる") {
254             TrashBox mybox;
255             DummyGarbage * garbage = new DummyGarbage;
256             TEST_CASE("0","[前提] ゴミが入っている", find(mybox.garbage.begin(), mybox.garbage.end(), garbage) != mybox.garbage.end());
257
258             TrashBox secondbox;
259             delete garbage;
260
261             TEST_CASE("1","ゴミが消えている", find(mybox.garbage.begin(), mybox.garbage.end(), garbage) == mybox.garbage.end());
262            
263         } END_CASE;
264     } END_CASE;
265
266     BEGIN_CASE("5","TrashBox::cleanup") {
267         BEGIN_CASE("1","動的に作ったオブジェクトが破棄できる") {
268             TrashBox mybox;
269             DummyGarbage * garbage;
270
271             TestSuite::clearCheckpoints();
272
273             garbage = new DummyGarbage;
274             TEST_CASE("0","[前提] コンストラクタが起動されている", TestSuite::isReached("DummyGarbage::DummyGarbage"));
275
276             mybox.cleanup();
277             TEST_CASE("1","デストラクタが起動されている", TestSuite::isReached("DummyGarbage::~DummyGarbage"));
278         } END_CASE;
279
280 #ifdef _MSC_VER
281         BEGIN_CASE("2","例外はもれる") {
282             TrashBox mybox;
283             DummyGarbage * garbage;
284
285             TestSuite::clearCheckpoints();
286
287             garbage = new DummyGarbage;
288             garbage->throw_exception = true;
289
290             bool result = false;
291             try { mybox.cleanup(); }
292             catch(...) { result = true; }
293
294             if(!result)
295                 TEST_FAIL;
296         } END_CASE;
297
298         BEGIN_CASE("3","例外を起こしたオブジェクトが破壊されている (2重破棄にならない)") {
299             TrashBox mybox;
300             DummyGarbage * garbage;
301             DummyGarbage * garbage2;
302
303             TestSuite::clearCheckpoints();
304
305             garbage = new DummyGarbage;
306             garbage->throw_exception = true;
307             garbage2 = new DummyGarbage;
308             garbage2->throw_exception = true;
309
310             try { mybox.cleanup(); }
311             catch(...) {}
312             try { mybox.cleanup(); }    //ここでAccessViolationが起こらない
313             catch(...) {}
314
315             if(!mybox.garbage.empty())
316                 TEST_FAIL;
317         } END_CASE;
318 #endif
319
320         BEGIN_CASE("4","削除の順序が正しい") {
321             TrashBox mybox;
322             DummyGarbage * garbage;
323             DummyGarbage * garbage2;
324             DummyGarbage * garbage3;
325             int g  = 0;
326             int g2 = 0;
327             int g3 = 0;
328
329             TestSuite::clearCheckpoints();
330
331             garbage  = new DummyGarbage(&g);
332             garbage2 = new DummyGarbage(&g2);
333             garbage3 = new DummyGarbage(&g3);
334
335             mybox.cleanup();
336
337             TEST_CASE("1","最初に登録されたものは最後に削除",g == 3);
338             TEST_CASE("2","次に登録されたものは2番目に削除",g2 == 2);
339             TEST_CASE("3","次に登録されたものは最初に削除",g3 == 1);
340         } END_CASE;
341
342         BEGIN_CASE("5","トップレベルでないゴミ箱はcleanupできない") {
343             TrashBox outerbox;
344             TrashBox innerbox;
345
346             bool result = false;
347             try {   outerbox.cleanup();   }
348             catch(std::runtime_error)
349             {   result = true;   }
350
351             if(!result)
352                 TEST_FAIL;
353         } END_CASE;
354
355     } END_CASE;
356
357     BEGIN_CASE("6","デストラクタによる破棄") {
358         BEGIN_CASE("1","動的に作ったオブジェクトが破棄できる (TrashBox::~TrashBox)") {
359             {
360                 TrashBox mybox;
361                 DummyGarbage * garbage;
362
363                 TestSuite::clearCheckpoints();
364
365                 garbage = new DummyGarbage;
366                 TEST_CASE("0","[前提] コンストラクタが起動されている", TestSuite::isReached("DummyGarbage::DummyGarbage"));
367             }
368             TEST_CASE("1","デストラクタが起動されている", TestSuite::isReached("DummyGarbage::~DummyGarbage"));
369         } END_CASE;
370
371         BEGIN_CASE("2","例外はもれない") {
372             bool result = true;
373             try{
374                 TrashBox mybox;
375                 DummyGarbage * garbage;
376
377                 TestSuite::clearCheckpoints();
378
379                 garbage = new DummyGarbage;
380                 TEST_CASE("0","[前提] コンストラクタが起動されている", TestSuite::isReached("DummyGarbage::DummyGarbage"));
381             }
382             catch(...)
383             { result = false; }
384             TEST_CASE("1","例外はもれない", result);
385         } END_CASE;
386
387     } END_CASE;
388
389     BEGIN_CASE("7","rescue") {
390         DummyGarbage * garbage;
391         {
392             TrashBox mybox;
393             garbage = new DummyGarbage;
394             garbage->rescue();
395
396             TestSuite::clearCheckpoints();
397         }
398         TEST_CASE("1","rescueしたゴミは削除されない", !TestSuite::isReached("DummyGarbage::~DummyGarbage"));
399         delete garbage;
400     } END_CASE;
401
402     BEGIN_CASE("8","静的なオブジェクトが多重破棄されない") {
403         TrashBox outerbox;
404         {
405             DummyGarbage garbage;
406             TrashBox innerbox;
407             DummyGarbage garbage2;
408
409             TEST_CASE("0","[前提] コンストラクタが起動されている", TestSuite::isReached("DummyGarbage::DummyGarbage"));
410         }   //ここで2重破棄でMACVにならない
411     } END_CASE;
412 }
413
414 #endif
415
416
417