Ticket #33: assure_ends_well.diff

File assure_ends_well.diff, 3.5 kB (added by rogerdpack, 5 months ago)

patch and tests

  • ext/em.cpp

    old new  
    463463                //  descriptor is closed anyway. This is different from the case where 
    464464                //  the socket has already been closed but the descriptor in the ED object 
    465465                //  hasn't yet been set to INVALID_SOCKET. 
    466                 int i, j
     466                int i
    467467                int nSockets = Descriptors.size(); 
    468                 for (i=0, j=0; i < nSockets; i++) { 
     468                for (i=0; i < nSockets; i++) { 
    469469                        EventableDescriptor *ed = Descriptors[i]; 
    470470                        assert (ed); 
    471471                        if (ed->ShouldDelete()) { 
     
    482482                                } 
    483483 
    484484                                ModifiedDescriptors.erase (ed); 
     485                                Descriptors[i] = Descriptors[Descriptors.size() - 1]; 
     486                                Descriptors.pop_back(); 
     487                                i--; nSockets--; 
     488                                 
    485489                                delete ed; 
    486490                        } 
    487                         else 
    488                                 Descriptors [j++] = ed; 
    489491                } 
    490                 while ((size_t)j < Descriptors.size()) 
    491                         Descriptors.pop_back(); 
    492492 
    493493        } 
    494494 
     
    556556                // rather than traversing the whole list. 
    557557                // In kqueue, closing a descriptor automatically removes its event filters. 
    558558 
    559                 int i, j
     559                int i
    560560                int nSockets = Descriptors.size(); 
    561                 for (i=0, j=0; i < nSockets; i++) { 
     561                for (i=0; i < nSockets; i++) { 
    562562                        EventableDescriptor *ed = Descriptors[i]; 
    563563                        assert (ed); 
    564564                        if (ed->ShouldDelete()) { 
    565565                                ModifiedDescriptors.erase (ed); 
    566566                                delete ed; 
     567                                Descriptors[i] = Descriptors[Descriptors.size() - 1]; // replace our 'gone' one with a live one 
     568                                i--; nSockets--; 
     569                                Descriptors.pop_back(); 
    567570                        } 
    568                         else 
    569                                 Descriptors [j++] = ed; 
    570571                } 
    571                 while ((size_t)j < Descriptors.size()) 
    572                         Descriptors.pop_back(); 
    573572 
    574573        } 
    575574 
     
    790789 
    791790        { // cleanup dying sockets 
    792791                // vector::pop_back works in constant time. 
    793                 int i, j
     792                int i
    794793                int nSockets = Descriptors.size(); 
    795                 for (i=0, j=0; i < nSockets; i++) { 
     794                for (i=0; i < nSockets; i++) { 
    796795                        EventableDescriptor *ed = Descriptors[i]; 
    797796                        assert (ed); 
    798797                        if (ed->ShouldDelete()) 
     798                        { 
    799799                                delete ed; 
    800                         else 
    801                                 Descriptors [j++] = ed; 
     800                                Descriptors[i] = Descriptors[Descriptors.size() - 1]; 
     801                                Descriptors.pop_back(); 
     802                                i--; nSockets--; 
     803                        } 
    802804                } 
    803                 while ((size_t)j < Descriptors.size()) 
    804                         Descriptors.pop_back(); 
    805805 
    806806        } 
    807807 
  • tests/test_ends_right.rb

    old new  
     1# this error occurs when you have several sockets, like 3 
     2# they are all 'closed' but their descriptors are in the middle of being collected 
     3# THEN the program terminates, which causes the EM thread to jump to its finalizer. 
     4 
     5$:.unshift "../lib" 
     6require 'eventmachine' 
     7require 'test/unit' 
     8 
     9module SlowClosers 
     10  @@total_closed = 0 
     11 
     12  def unbind 
     13    @@total_closed += 1 
     14    raise LocalJumpError.new() if @@total_closed == 2 
     15  end 
     16 
     17end 
     18 
     19class DeathEnd < Test::Unit::TestCase 
     20 
     21   def setup 
     22        SlowClosers.class_eval("@@total_closed = 0") 
     23   end 
     24 
     25   def test_ends_well_multi_thread # note that ideally it should try it with kqueue, epoll, and normal.  I'm not sure if all the tests should just be re-run with those settings or what 
     26      begin 
     27        EM::run { 
     28                3.times {EM::connect '127.0.0.1', 6000, SlowClosers} 
     29        } 
     30      rescue LocalJumpError 
     31        # we should get here--if it errs it will err with a 'HARD' c-style error 
     32      end 
     33   end 
     34 
     35   # another test with possibility would be one that encourage the ConnectionUnbound caused if they 
     36   # do a connection or add_timer or start_server from another thread.  Not sure if we want to care about that one [though we should, really].   
     37 
     38end 
     39