Changeset 1201

Show
Ignore:
Timestamp:
05/22/08 14:18:19 (16 years ago)
Author:
ppalmers
Message:

fix some deadlock issues on the control code (cfr #114)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/libffado-2.0/src/debugmodule/debugmodule.cpp

    r1188 r1201  
    3232 
    3333#include <time.h> 
    34 #include <execinfo.h> 
     34 
     35#if DEBUG_BACKTRACE_SUPPORT 
     36    #include <execinfo.h> 
     37    #include <cxxabi.h> 
     38    #define GNU_SOURCE 
     39    #include <dlfcn.h> 
     40#endif 
    3541 
    3642#if DEBUG_USE_MESSAGE_BUFFER 
     
    288294        perror("backtrace_symbols"); 
    289295    } else { 
     296        char* outbuf = NULL; 
     297        size_t length; 
     298        int status; 
     299        Dl_info info; 
    290300        for (int j = 0; j < m_backtrace_buffer_nb_seen; j++) { 
    291             fprintf(stderr, " %p => %s\n", m_backtrace_buffer_seen[j], strings[j]); 
     301            if (dladdr(m_backtrace_buffer_seen[j], &info) != 0) { 
     302                outbuf = __cxxabiv1::__cxa_demangle(info.dli_sname, outbuf, &length, &status); 
     303                if(outbuf && status == 0) { 
     304                    fprintf(stderr, " %p => %s\n",  
     305                            m_backtrace_buffer_seen[j], outbuf); 
     306                    free(outbuf); 
     307                    outbuf = NULL; 
     308                } else { 
     309                    fprintf(stderr, " %p => %s (demangle status: %d)\n",  
     310                            m_backtrace_buffer_seen[j], strings[j], status); 
     311                } 
     312            } else { 
     313                fprintf(stderr, " %p => %s\n",  
     314                        m_backtrace_buffer_seen[j], strings[j]); 
     315            } 
    292316        } 
    293317        free(strings); 
     
    646670 
    647671    for (int j = 0; j < nptrs; j++) { 
    648         chars_written += snprintf(m_backtrace_strbuffer + chars_written, MB_BUFFERSIZE-chars_written, "%p ", m_backtrace_buffer[j]); 
     672        char name[64]; 
     673        name[0]=0; 
     674        getFunctionName(m_backtrace_buffer[j], name, 64); 
     675        chars_written += snprintf(m_backtrace_strbuffer + chars_written, MB_BUFFERSIZE-chars_written, "%s ", name); 
    649676    } 
    650677    chars_written += snprintf(m_backtrace_strbuffer + chars_written, MB_BUFFERSIZE-chars_written, "\n"); 
     
    660687        seen = false; 
    661688        int j; 
    662         for (j=0; j<m_backtrace_buffer_nb_seen & j < DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN; j++) { 
     689        for (j=0; j<m_backtrace_buffer_nb_seen && j < DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN; j++) { 
    663690            if(m_backtrace_buffer_seen[j] == m_backtrace_buffer[i]) { 
    664691                seen = true; 
     
    666693            } 
    667694        } 
    668         if (!seen) { 
     695        if (!seen  
     696           && j < DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN) { 
    669697            m_backtrace_buffer_seen[j] = m_backtrace_buffer[i]; 
    670698            m_backtrace_buffer_nb_seen++; 
    671699        } 
    672700    } 
    673      
     701 
    674702    print(m_backtrace_strbuffer); 
    675703 
     
    689717    pthread_mutex_lock(&m_backtrace_lock); 
    690718    nptrs = backtrace(m_backtrace_buffer, id+1); 
    691     if(id<nptrs) { 
    692         retval = m_backtrace_buffer[id]; 
     719    if(id >= nptrs) { 
     720        id = nptrs-1; 
     721    } 
     722    retval = m_backtrace_buffer[id]; 
     723    // save the pointers to the pointers-seen list such that we can 
     724    // dump their info later on 
     725    bool seen = false; 
     726    int j; 
     727    for (j=0; j<m_backtrace_buffer_nb_seen && j < DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN; j++) { 
     728        if(m_backtrace_buffer_seen[j] == m_backtrace_buffer[id]) { 
     729            seen = true; 
     730            break; 
     731        } 
     732    } 
     733    if (!seen 
     734       && j < DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN) { 
     735        m_backtrace_buffer_seen[j] = m_backtrace_buffer[id]; 
     736        m_backtrace_buffer_nb_seen++; 
    693737    } 
    694738    pthread_mutex_unlock(&m_backtrace_lock); 
    695      
     739 
    696740    return retval; 
    697741} 
     742 
     743void 
     744DebugModuleManager::getFunctionName(void *ptr, char *buff, int len) 
     745{ 
     746    char* outbuf = NULL; 
     747    size_t length; 
     748    int status; 
     749    Dl_info info; 
     750    if (dladdr(ptr, &info) != 0) { 
     751        outbuf = abi::__cxa_demangle(info.dli_sname, outbuf, &length, &status); 
     752        if(outbuf && status == 0) { 
     753            if(len < (int)length) { 
     754                strncpy(buff, outbuf, len); 
     755            } else { 
     756                strncpy(buff, outbuf, length); 
     757            } 
     758        } else { 
     759            snprintf(buff, len, "%p (%s)", ptr, info.dli_sname); 
     760        } 
     761    } else { 
     762        snprintf(buff, len, "%p (I-ERR)", ptr); 
     763    } 
     764    if (outbuf) free(outbuf); 
     765} 
     766 
    698767#endif 
    699768 
  • branches/libffado-2.0/src/debugmodule/debugmodule.h

    r1157 r1201  
    252252    #define debugBacktraceGet( _ID_ )                       \ 
    253253        DebugModuleManager::instance()->getBacktracePtr( _ID_ ); 
     254    #define debugGetFunctionNameFromAddr( _ADDR_, _BUFF_, _MAX_SIZE_ )              \ 
     255        DebugModuleManager::instance()->getFunctionName( _ADDR_, _BUFF_, _MAX_SIZE_ ); 
    254256#else 
    255257    #define debugPrintBacktrace( _SIZE_ ) 
    256258    #define debugBacktraceGet( _ID_ )       NULL  
     259    #define debugGetFunctionNameFromAddr( _ADDR_, _BUFF_, _MAX_SIZE_ ) 
    257260#endif 
    258261 
     
    336339    void printBacktrace(int len); 
    337340    void *getBacktracePtr(int id); 
     341    void getFunctionName( void *, char *, int ); 
    338342#endif 
    339343 
  • branches/libffado-2.0/src/libcontrol/Element.cpp

    r1163 r1201  
    7777Element::lockControl() 
    7878{ 
     79    if(!m_parent) { 
     80        debugOutput( DEBUG_LEVEL_VERBOSE, "Locking tree...\n"); 
     81    } 
    7982    getLock().Lock(); 
    8083} 
     
    8386Element::unlockControl() 
    8487{ 
     88    if(!m_parent) { 
     89        debugOutput( DEBUG_LEVEL_VERBOSE, "Unlocking tree...\n"); 
     90    } 
    8591    getLock().Unlock(); 
    8692} 
     
    175181Container::getElementVector() 
    176182{ 
    177     lockControl(); 
     183    if(!getLock().isLocked()) { 
     184        debugWarning("called on unlocked tree!\n"); 
     185    } 
    178186    return m_Children; 
    179 } 
    180  
    181 void 
    182 Container::releaseElementVector() 
    183 { 
    184     unlockControl(); 
    185187} 
    186188 
     
    217219 
    218220bool 
    219 Container::deleteElement(Element *e) 
    220 
    221     Util::MutexLockHelper lock(getLock()); 
     221Container::deleteElementNoLock(Element *e) 
     222
    222223    if(e == NULL) return false; 
    223224    debugOutput( DEBUG_LEVEL_VERBOSE, "Deleting Element %s from %s\n", 
     
    230231        if(*it == e) { 
    231232            m_Children.erase(it); 
    232             // unlock before emitting the signal 
    233             lock.earlyUnlock(); 
    234             emitSignal(eS_Updated, m_Children.size()); 
    235233            return true; 
    236234        } 
     
    242240 
    243241bool 
     242Container::deleteElement(Element *e) 
     243{ 
     244    bool retval; 
     245    Util::MutexLockHelper lock(getLock()); 
     246    retval = deleteElementNoLock(e); 
     247    if(retval) { 
     248        // unlock before emitting the signal 
     249        lock.earlyUnlock(); 
     250        emitSignal(eS_Updated, m_Children.size()); 
     251    } 
     252    return retval; 
     253} 
     254 
     255bool 
    244256Container::clearElements(bool delete_pointers)  
    245257{ 
     
    247259    while(m_Children.size()) { 
    248260        Element *e=m_Children[0]; 
    249         deleteElement(e); 
     261        deleteElementNoLock(e); 
    250262        if (delete_pointers) delete e; 
    251263    } 
     
    275287Container::setVerboseLevel(int l) 
    276288{ 
    277     Util::MutexLockHelper lock(getLock()); 
    278289    setDebugLevel(l); 
    279290    for ( ElementVectorIterator it = m_Children.begin(); 
  • branches/libffado-2.0/src/libcontrol/Element.h

    r1163 r1201  
    150150 
    151151    /** 
    152      * Returns and locks the element vector. No changes will be made to the vector 
    153      * until releaseElementVector is called
     152     * Returns the element vector. be sure to lock the tree while using 
     153     * the return value
    154154     * @return  
    155155     */ 
    156156    const ElementVector & getElementVector(); 
    157  
    158     /** 
    159      * Releases the lock on the element vector. 
    160      */ 
    161     void releaseElementVector(); 
    162157 
    163158    virtual void show(); 
     
    167162        eS_Updated, 
    168163    }; 
     164 
     165private: 
     166    bool deleteElementNoLock(Element *e); 
    169167 
    170168protected: 
  • branches/libffado-2.0/src/libutil/PosixMutex.cpp

    r1184 r1201  
    3333// check whether backtracing is enabled 
    3434#if DEBUG_LOCK_COLLISION_TRACING 
     35    #define DEBUG_LOCK_COLLISION_TRACING_INDEX 2 
     36    #define DEBUG_LOCK_COLLISION_TRACING_NAME_MAXLEN 64 
    3537    #if DEBUG_BACKTRACE_SUPPORT 
    3638    // ok 
     
    7072PosixMutex::Lock() 
    7173{ 
     74    int err; 
    7275    debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE, "(%p) lock\n", this); 
    7376    #if DEBUG_LOCK_COLLISION_TRACING 
    7477    if(TryLock()) { 
    7578        // locking succeeded 
    76         m_locked_by = debugBacktraceGet(1); 
     79        m_locked_by = debugBacktraceGet( DEBUG_LOCK_COLLISION_TRACING_INDEX ); 
     80 
     81        char name[ DEBUG_LOCK_COLLISION_TRACING_NAME_MAXLEN ]; 
     82        name[0] = 0; 
     83        debugGetFunctionNameFromAddr(m_locked_by, name, DEBUG_LOCK_COLLISION_TRACING_NAME_MAXLEN); 
     84 
    7785        debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE, 
    78                     "(%p) %p has lock\n", 
    79                     this, m_locked_by); 
     86                    "(%p) %s obtained lock\n", 
     87                    this, name); 
    8088        return; 
    8189    } else { 
    82         void *lock_try_by = debugBacktraceGet(1); 
    83         debugOutput(DEBUG_LEVEL_VERBOSE, 
    84                     "(%p) lock collision: %p wants lock, %p has lock\n", 
    85                     this, lock_try_by, m_locked_by); 
    86         pthread_mutex_lock(&m_mutex); 
     90        void *lock_try_by = debugBacktraceGet( DEBUG_LOCK_COLLISION_TRACING_INDEX ); 
     91 
     92        char name1[ DEBUG_LOCK_COLLISION_TRACING_NAME_MAXLEN ]; 
     93        name1[0] = 0; 
     94        debugGetFunctionNameFromAddr(lock_try_by, name1, DEBUG_LOCK_COLLISION_TRACING_NAME_MAXLEN); 
     95        char name2[ DEBUG_LOCK_COLLISION_TRACING_NAME_MAXLEN ]; 
     96        name2[0] = 0; 
     97        debugGetFunctionNameFromAddr(m_locked_by, name2, DEBUG_LOCK_COLLISION_TRACING_NAME_MAXLEN); 
     98 
     99        debugWarning("(%p) lock collision: %s wants lock, %s has lock\n", 
     100                    this, name1, name2); 
     101        if((err = pthread_mutex_lock(&m_mutex))) { 
     102            if (err == EDEADLK) { 
     103                debugError("Resource deadlock detected\n"); 
     104                debugPrintBacktrace(10); 
     105            } else { 
     106                debugError("Error locking the mutex: %d\n", err); 
     107            } 
     108        } else { 
     109            debugWarning("(%p) lock collision: %s got lock (from %s?)\n", 
     110                        this, name1, name2); 
     111        } 
     112    } 
     113    #else 
     114    #ifdef DEBUG 
     115    if((err = pthread_mutex_lock(&m_mutex))) { 
     116        if (err == EDEADLK) { 
     117            debugError("Resource deadlock detected\n"); 
     118            debugPrintBacktrace(10); 
     119        } else { 
     120            debugError("Error locking the mutex: %d\n", err); 
     121        } 
     122    } else { 
     123        debugWarning("(%p) lock collision: %s got lock (from %s?)\n", 
     124                    this, name1, name2); 
    87125    } 
    88126    #else 
    89127    pthread_mutex_lock(&m_mutex); 
     128    #endif 
    90129    #endif 
    91130} 
     
    121160    // unlocking 
    122161    m_locked_by = NULL; 
    123     void *unlocker = debugBacktraceGet(1); 
     162    void *unlocker = debugBacktraceGet( DEBUG_LOCK_COLLISION_TRACING_INDEX ); 
     163    char name[ DEBUG_LOCK_COLLISION_TRACING_NAME_MAXLEN ]; 
     164    name[0] = 0; 
     165    debugGetFunctionNameFromAddr(unlocker, name, DEBUG_LOCK_COLLISION_TRACING_NAME_MAXLEN); 
    124166    debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE, 
    125                 "(%p) %p releases lock\n", 
    126                 this, unlocker); 
     167                "(%p) %s releases lock\n", 
     168                this, name); 
    127169    #endif 
    128170 
     171    #ifdef DEBUG 
     172    int err; 
     173    if((err = pthread_mutex_unlock(&m_mutex))) { 
     174        debugError("Error unlocking the mutex: %d\n", err); 
     175    } 
     176    #else 
    129177    pthread_mutex_unlock(&m_mutex); 
     178    #endif 
    130179} 
    131180 
     
    133182PosixMutex::show() 
    134183{ 
    135     debugOutput(DEBUG_LEVEL_NORMAL, "(%p) mutex\n", this); 
     184    debugOutput(DEBUG_LEVEL_NORMAL, "(%p) mutex (%s)\n", this, (isLocked() ? "Locked" : "Unlocked")); 
    136185} 
    137186 
  • branches/libffado-2.0/support/dbus/controlserver.cpp

    r1173 r1201  
    184184    int nbElements=m_Slave.countElements(); 
    185185    if (i<nbElements) { 
     186        m_Slave.lockControl(); 
    186187        const Control::ElementVector elements = m_Slave.getElementVector(); 
    187188        Control::Element *e = elements.at(i); 
    188189        std::string name; 
    189190        if(e) name = e->getName(); 
    190         m_Slave.releaseElementVector(); 
     191        m_Slave.unlockControl(); 
    191192        return name; 
    192193    } else return ""; 
     
    194195//     Util::MutexLockHelper lock(*m_access_lock); 
    195196 
    196 // NOTE: call with access lock held! 
     197// NOTE: call with tree locked 
    197198void 
    198199Container::updateTree() 
     
    263264        to_remove.erase(to_remove.begin()); 
    264265    } 
    265     m_Slave.releaseElementVector(); 
    266266 
    267267    if(something_changed) { 
     
    279279    debugOutput(DEBUG_LEVEL_VERBOSE,  
    280280                "removing handler %p on path %s\n", 
    281                 path().c_str(), e); 
     281                e, path().c_str()); 
    282282    for ( ElementVectorIterator it = m_Children.begin(); 
    283283      it != m_Children.end(); 
     
    313313    // we lock the tree first 
    314314    Lock(); 
     315 
     316    // also lock the slave tree 
     317    m_Slave.lockControl(); 
     318 
    315319    // update our tree 
    316320    updateTree(); 
     321 
     322    // now unlock the slave tree 
     323    m_Slave.unlockControl(); 
     324 
     325    // and unlock the access 
    317326    Unlock(); 
    318327} 
  • branches/libffado-2.0/support/dbus/ffado-dbus-server.cpp

    r1196 r1201  
    300300        conn.request_name("org.ffado.Control"); 
    301301 
     302        // lock the control tree such that it does not get modified while we build our view 
     303        m_deviceManager->lockControl(); 
    302304        container = new DBusControl::Container(conn, "/org/ffado/Control/DeviceManager",  
    303305                                               NULL, *m_deviceManager); 
    304          
     306        // unlock the control tree since the tree is built 
     307        m_deviceManager->unlockControl(); 
     308 
    305309        printMessage("DBUS test service running\n"); 
    306310        printMessage("press ctrl-c to stop it & exit\n"); 
     
    309313            debugOutput( DEBUG_LEVEL_NORMAL, "dispatching...\n"); 
    310314            dispatcher.enter(); 
     315 
    311316            debugOutput( DEBUG_LEVEL_NORMAL, " dispatcher exited...\n"); 
    312317            sem_wait(&run_sem);