チェンジセット 520

差分発生行の前後
無視リスト:
コミット日時:
2008/05/27 14:16:31 (6 ヶ月前)
コミッタ:
yossy
ログメッセージ:

Thread(soumen): 現時点でのテスト(34tests)をパスするように例外周りを実装

ファイル:

凡例:

変更無し
追加
削除
更新
コピー
移動
  • as3/Thread/branches/soumen/src/org/libspark/thread/IMonitor.as

    r509 r520  
    2121                 */ 
    2222                function notifyAll():void; 
     23                 
     24                /** 
     25                 * 待機中に例外が発生した等の理由で、指定されたスレッドがこのモニタの待機セットから抜けることを伝えます。 
     26                 * 通常、このメソッドは内部的にのみ使用され、ユーザーが呼び出す必要はありません。 
     27                 *  
     28                 * @param       thread  待機セットから抜けるスレッド 
     29                 */ 
     30                function leave(thread:Thread):void; 
    2331        } 
    2432} 
  • as3/Thread/branches/soumen/src/org/libspark/thread/Monitor.as

    r514 r520  
    5454                         
    5555                        // スレッドに wait するよう依頼 
    56                         thread.monitorWait(timeout != 0); 
     56                        thread.monitorWait(timeout != 0, this); 
    5757                         
    5858                        // 待機セットに並ばせる 
     
    7979                         
    8080                        // スレッドを起こす 
    81                         thread.monitorWakeup(); 
     81                        thread.monitorWakeup(this); 
    8282                } 
    8383                 
     
    100100                                // ここで try-catch を行うのは確実に全てのスレッドを起こすため 
    101101                                try { 
    102                                         thread.monitorWakeup(); 
     102                                        thread.monitorWakeup(this); 
    103103                                } 
    104104                                catch (e:Object) { 
     
    138138                         
    139139                        // スレッドを起こす 
    140                         thread.monitorTimeout(); 
     140                        thread.monitorTimeout(this); 
     141                } 
     142                 
     143                public function leave(thread:Thread):void 
     144                { 
     145                        // 既に待機セットが空になっていたら何もしない 
     146                        if (_waitors == null || _waitors.length < 1) { 
     147                                return; 
     148                        } 
     149                         
     150                        // 待機セットから該当するスレッドを検索 
     151                        var index:int = _waitors.indexOf(thread); 
     152                         
     153                        // 見つからなければ何もしない 
     154                        if (index == -1) { 
     155                                return; 
     156                        } 
     157                         
     158                        // 待機セットから削除 
     159                        _waitors.splice(index, 1); 
     160                         
     161                        // タイムアウトを解除 
     162                        unregisterTimeout(thread); 
    141163                } 
    142164                 
  • as3/Thread/branches/soumen/src/org/libspark/thread/Thread.as

    r517 r520  
    22{ 
    33        import flash.events.IEventDispatcher; 
     4        import flash.utils.Dictionary; 
     5        import flash.utils.getQualifiedClassName; 
     6        import flash.utils.getQualifiedSuperclassName; 
     7        import flash.utils.getDefinitionByName; 
    48        import org.libspark.thread.errors.CurrentThreadNotFoundError; 
    59        import org.libspark.thread.errors.IllegalThreadStateError; 
     
    1115                private static var _currentThread:Thread = null; 
    1216                private static var _toplevelThreads:Array = []; 
     17                private static var _uncaughtErrorHandler:Function = null; 
    1318                 
    1419                /** 
     
    2126                public static function initialize(executor:IThreadExecutor):void 
    2227                { 
    23                         //_threadIndex = 0; 
     28                        _threadIndex = 0; 
    2429                        _currentThread = null; 
    2530                        _toplevelThreads.length = 0; 
     
    7176                public static function get uncaughtErrorHandler():Function 
    7277                { 
    73                         return null
     78                        return _uncaughtErrorHandler
    7479                } 
    7580                 
     
    7984                public static function set uncaughtErrorHandler(value:Function):void 
    8085                { 
    81                          
     86                        _uncaughtErrorHandler = value; 
     87                } 
     88                 
     89                private static function getUncaughtErrorHandler():Function 
     90                { 
     91                        return uncaughtErrorHandler || defaultUncaughtErrorHandler; 
     92                } 
     93                 
     94                private static function defaultUncaughtErrorHandler(e:Object, t:Thread):void 
     95                { 
     96                        trace((t ? t.toString() + ' ' : '') + (e is Error ? Error(e).getStackTrace() : e.toString())); 
    8297                } 
    8398                 
     
    100115                                        ++i; 
    101116                                } 
     117                                // 伝播すべき例外が発生している場合はキャッチされない例外ハンドラを呼び出す 
     118                                // Note: _errorThread が null の場合、この例外はまだ伝播すべきではないことを示す 
     119                                if (thread._error != null && thread._errorThraed != null) { 
     120                                        try { 
     121                                                getUncaughtErrorHandler()(thread._error, thread._errorThraed); 
     122                                        } 
     123                                        catch (e:Object) { 
     124                                                defaultUncaughtErrorHandler(e, null); 
     125                                        } 
     126                                        thread._error = null; 
     127                                        thread._errorThraed = null; 
     128                                } 
    102129                        } 
    103130                } 
     
    142169                public static function error(klass:Class, func:Function, reset:Boolean = true):void 
    143170                { 
    144                          
     171                        if (func != null) { 
     172                                getCurrentThread().addErrorHandler(klass, func, reset); 
     173                        } 
     174                        else { 
     175                                getCurrentThread().removeErrorHandler(klass); 
     176                        } 
    145177                } 
    146178                 
     
    188220                        _children = null; 
    189221                        _runHandler = null; 
     222                        _savedRunHandler = null; 
    190223                        _timeoutHandler = null; 
     224                        _waitMonitor = null; 
    191225                        _joinMonitor = null; 
     226                        _errorHandlers = null; 
     227                        _error = null; 
     228                        _errorThraed = null; 
    192229                } 
    193230                 
     
    198235                private var _children:Array; 
    199236                private var _runHandler:Function; 
     237                private var _savedRunHandler:Function; 
    200238                private var _timeoutHandler:Function; 
     239                private var _waitMonitor:IMonitor; 
    201240                private var _joinMonitor:IMonitor; 
     241                private var _errorHandlers:Dictionary; 
     242                private var _error:Object; 
     243                private var _errorThraed:Thread; 
    202244                 
    203245                public function get id():uint 
     
    253295                } 
    254296                 
    255                 internal function monitorWait(timeout:Boolean):void 
     297                internal function monitorWait(timeout:Boolean, monitor:IMonitor):void 
    256298                { 
    257299                        // wait できる状態でなければエラー 
    258                         if (_state != ThreadState.RUNNABLE && _state != ThreadState.TERMINATING) { 
     300                        if ((_state != ThreadState.RUNNABLE && _state != ThreadState.TERMINATING) || _waitMonitor != null) { 
    259301                                throw new IllegalThreadStateError('Thread can not wait.'); 
    260302                        } 
     
    262304                        // state を待機状態に切り替える 
    263305                        _state = timeout ? ThreadState.TIMED_WAITING : ThreadState.WAITING; 
    264                 } 
    265                  
    266                 internal function monitorWakeup():void 
     306                         
     307                        // モニタを保存 
     308                        _waitMonitor = monitor; 
     309                } 
     310                 
     311                internal function monitorWakeup(monitor:IMonitor):void 
    267312                { 
    268313                        // 待機状態でなければエラー 
    269                         if (_state != ThreadState.WAITING && _state != ThreadState.TIMED_WAITING) { 
     314                        if ((_state != ThreadState.WAITING && _state != ThreadState.TIMED_WAITING) || _waitMonitor != monitor) { 
    270315                                throw new IllegalThreadStateError('Thread can not wakeup.'); 
    271316                        } 
     
    273318                        // state を実行状態に切り替える 
    274319                        _state = _runningState; 
    275                 } 
    276                  
    277                 internal function monitorTimeout():void 
     320                         
     321                        // 保存されていたモニタを破棄 
     322                        _waitMonitor = null; 
     323                } 
     324                 
     325                internal function monitorTimeout(monitor:IMonitor):void 
    278326                { 
    279327                        // 待機時間付の待機状態でなければエラー 
    280                         if (_state != ThreadState.TIMED_WAITING) { 
     328                        if (_state != ThreadState.TIMED_WAITING || _waitMonitor != monitor) { 
    281329                                throw new IllegalThreadStateError('Thread can not wakeup.'); 
    282330                        } 
     
    284332                        // state を実行状態に切り替える 
    285333                        _state = _runningState; 
     334                         
     335                        // 保存されていたモニタを破棄 
     336                        _waitMonitor = null; 
    286337                         
    287338                        // 次に実行する実行関数をタイムアウト用のものに切り替える 
     
    324375                } 
    325376                 
     377                private function getErrorHandlers():Dictionary 
     378                { 
     379                        return _errorHandlers || (_errorHandlers = new Dictionary()); 
     380                } 
     381                 
     382                private function addErrorHandler(klass:Class, handler:Function, reset:Boolean):void 
     383                { 
     384                        getErrorHandlers()[getQualifiedClassName(klass)] = new ErrorHandler(handler, reset); 
     385                } 
     386                 
     387                private function removeErrorHandler(klass:Class):void 
     388                { 
     389                        // ハンドラマップが存在しなければ何もしない 
     390                        if (_errorHandlers == null) { 
     391                                return; 
     392                        } 
     393                         
     394                        // ハンドラマップから削除 
     395                        delete _errorHandlers[getQualifiedClassName(klass)]; 
     396                } 
     397                 
     398                private function resetErrorHandlers():void 
     399                { 
     400                        // ハンドラマップが存在しなければ何もしない 
     401                        if (_errorHandlers == null) { 
     402                                return; 
     403                        } 
     404                         
     405                        // 登録されているハンドラを巡回 
     406                        for (var key:String in _errorHandlers) { 
     407                                // reset が true であればハンドラを削除する 
     408                                if (ErrorHandler(_errorHandlers[key]).reset) { 
     409                                        delete _errorHandlers[key]; 
     410                                } 
     411                        } 
     412                } 
     413                 
     414                private function getErrorHandler(error:Object):ErrorHandler 
     415                { 
     416                        // ハンドラマップが存在しなければ null を返す 
     417                        if (_errorHandlers == null) { 
     418                                return null; 
     419                        } 
     420                         
     421                        // error のクラス名を取得 
     422                        var className:String = getQualifiedClassName(error); 
     423                         
     424                        // クラス名が取得できる限り回す 
     425                        while (className != null) { 
     426                                // ハンドラマップからクラス名をキーにしてハンドラを検索する 
     427                                var handler:ErrorHandler = _errorHandlers[className]; 
     428                                // 見つかればそれを返す 
     429                                if (handler != null) { 
     430                                        return handler; 
     431                                } 
     432                                // 見つからなければ、スーパークラスを辿る 
     433                                try { 
     434                                        className = getQualifiedSuperclassName(getDefinitionByName(className)); 
     435                                } 
     436                                catch (e:ReferenceError) { 
     437                                        // ここで出る ReferenceError は getDefinitionByName によるもの 
     438                                        // プライベートクラス等の場合に起こりうる 
     439                                        className = null; 
     440                                } 
     441                        } 
     442                         
     443                        return null; 
     444                } 
     445                 
    326446                private function execute():Boolean 
    327447                { 
     
    334454                                return false; 
    335455                        } 
     456                         
     457                        // 発生した例外 
     458                        var error:Object = _error; 
     459                        var errorThread:Thread = _errorThraed || this; 
    336460                         
    337461                        // すべての子スレッドを呼び出す 
     
    349473                                                ++ci; 
    350474                                        } 
    351                                 } 
    352                         } 
    353                          
    354                         // 待機状態であればここでリターン 
     475                                        // 子スレッドで例外が起きていたら一番最初のものを保存 
     476                                        // Note: _errorThread が null の場合、その例外はまだ親に伝播するべきではないことを示す 
     477                                        if (child._error != null && child._errorThraed != null && error == null) { 
     478                                                error = child._error; 
     479                                                errorThread = child._errorThraed; 
     480                                                child._error = null; 
     481                                                child._errorThraed = null; 
     482                                        } 
     483                                } 
     484                        } 
     485                         
    355486                        if (_state == ThreadState.WAITING || _state == ThreadState.TIMED_WAITING) { 
    356                                 return true; 
    357                         } 
    358                          
    359                         // 今回実行する実行関数を保存 
    360                         var runHandler:Function = _runHandler; 
    361                          
    362                         // ハンドラ郡の設定をクリア 
     487                                if (error != null) { 
     488                                        // 待機状態で子スレッドによる例外発生していた場合は無理やり起きる 
     489                                        // モニタに対して待機セットから抜けることを伝える 
     490                                        _waitMonitor.leave(this); 
     491                                        _waitMonitor = null; 
     492                                        // state を切り替える 
     493                                        _state = _runningState; 
     494                                } 
     495                                else { 
     496                                        // 例外が発生していない場合はここでリターン 
     497                                        return true; 
     498                                } 
     499                        } 
     500                         
     501                        // 今回実行する実行関数 
     502                        var runHandler:Function = null; 
     503                        // エラーハンドラ 
     504                        var errorHandler:ErrorHandler = null; 
     505                         
     506                        if (error != null) { 
     507                                 
     508                                // 例外が発生していた場合は例外ハンドラを選択する 
     509                                errorHandler = getErrorHandler(error); 
     510                                 
     511                                if (errorHandler != null) { 
     512                                        // ハンドラが見つかった場合 
     513                                        // 例外が子から伝播してきた場合、割り込まれていると考え実行関数を保存する 
     514                                        if (errorThread != this) { 
     515                                                _savedRunHandler = _runHandler; 
     516                                        } 
     517                                        else { 
     518                                                // 子からの伝播でない場合、自力で処理したということで保存されている例外をクリア 
     519                                                _error = null; 
     520                                        } 
     521                                        // 実行関数をエラーハンドラに設定 
     522                                        runHandler = errorHandler.handler; 
     523                                } 
     524                                else { 
     525                                        // 見つからなかった場合はこのスレッドは終了フェーズに移行し親に例外を伝播する 
     526                                        if (_runningState != ThreadState.TERMINATING) { 
     527                                                // 既に終了フェーズでない場合のみ 
     528                                                // state を終了フェーズに切り替える 
     529                                                _state = ThreadState.TERMINATING; 
     530                                                _runningState = ThreadState.TERMINATING; 
     531                                                // 実行関数を finalize に設定 
     532                                                runHandler = finalize; 
     533                                        } 
     534                                        // 親に伝播するよう例外を保存 
     535                                        _error = error; 
     536                                        _errorThraed = errorThread; 
     537                                } 
     538                        } 
     539                        else { 
     540                                // 子スレッドによる例外が発生していない場合は前回指定された実行関数を設定 
     541                                runHandler = _runHandler; 
     542                        } 
     543                         
     544                        // 実行関数をリセット 
    363545                        _runHandler = null; 
     546                        // タイムアウトハンドラをリセット 
    364547                        _timeoutHandler = null; 
     548                        // エラーハンドラをリセット 
     549                        resetErrorHandlers(); 
     550                         
     551                        // エラーハンドラが実行されようとしている場合、実行終了後に復帰できるように保存しておいた実行関数を設定 
     552                        if (errorHandler != null) { 
     553                                _runHandler = _savedRunHandler; 
     554                        } 
    365555                         
    366556                        // Note: finalize の最後で wait が入って待機状態になった後に起きた等の場合に、 
     
    373563                                try { 
    374564                                        // 実行関数を呼び出す 
    375                                         runHandler.apply(this); 
     565                                        // エラーハンドラである場合は例外と例外の発生元のスレッドを引数として渡す 
     566                                        runHandler.apply(this, errorHandler != null ? [error, errorThread] : null); 
     567                                } 
     568                                catch (e:Object) { 
     569                                        // 例外が発生した場合例外を保存 
     570                                        _error = e; 
     571                                        // エラーハンドラ以外で例外が発生し、かつ該当するエラーハンドラが存在する場合 
     572                                        if (errorHandler == null && getErrorHandler(e) != null) { 
     573                                                // 自力で例外を回復できる可能性があるので強制的に runHandler を非 null にして次に繰り越す 
     574                                                // このとき、エラーハンドラ実行後に復帰するために runHandler を保存しておく 
     575                                                // run はダミーで意味はない 
     576                                                _savedRunHandler = _runHandler; 
     577                                                _runHandler = run; 
     578                                        } 
     579                                        else { 
     580                                                // それ以外の場合は例外を親に伝播する必要がある 
     581                                                // 例外が親に伝播するように発生元スレッドを設定 
     582                                                _errorThraed = this; 
     583                                                // 実行関数の設定をクリアして強制的に終了フェーズに移行させる 
     584                                                _runHandler = null; 
     585                                        } 
     586                                         
    376587                                } 
    377588                                finally { 
     
    379590                                        _currentThread = null; 
    380591                                } 
     592                        } 
     593                         
     594                        // 今エラーハンドラを実行し、かつエラーが発生していない場合、保存しておいた実行関数はもう必要ないので破棄 
     595                        if (errorHandler != null && _error == null) { 
     596                                _savedRunHandler = null; 
    381597                        } 
    382598                         
     
    8141030        } 
    8151031} 
     1032 
     1033class ErrorHandler 
     1034{ 
     1035        public function ErrorHandler(handler:Function, reset:Boolean) 
     1036        { 
     1037                this.handler = handler; 
     1038                this.reset = reset; 
     1039        } 
     1040         
     1041        public var handler:Function; 
     1042        public var reset:Boolean; 
     1043}