void KLibLoader::unloadLibrary(const char *libname) { KLibWrapPrivate *wrap = m_libs[libname]; if(!wrap) return; if(--wrap->ref_count) return; // kdDebug(150) << "closing library " << libname << endl; m_libs.remove(libname); disconnect(wrap->lib, SIGNAL(destroyed()), this, SLOT(slotLibraryDestroyed())); close_pending(wrap); }
void KLibLoader::close_pending(KLibWrapPrivate *wrap) { if (wrap && !d->pending_close.containsRef( wrap )) d->pending_close.append( wrap ); /* First delete all KLibrary objects in pending_close, but _don't_ unload the DSO behind it. */ QPtrListIterator<KLibWrapPrivate> it(d->pending_close); for (; it.current(); ++it) { wrap = it.current(); if (wrap->lib) { disconnect( wrap->lib, SIGNAL( destroyed() ), this, SLOT( slotLibraryDestroyed() ) ); KLibrary* to_delete = wrap->lib; wrap->lib = 0L; // unset first, because KLibrary dtor can cause delete to_delete; // recursive call to close_pending() } } if (d->unload_mode == KLibLoaderPrivate::DONT_UNLOAD) { d->pending_close.clear(); return; } bool deleted_one = false; while ((wrap = d->loaded_stack.first())) { /* Let's first see, if we want to try to unload this lib. If the env. var KDE_DOUNLOAD is set, we try to unload every lib. If not, we look at the lib itself, and unload it only, if it exports the symbol __kde_do_unload. */ if (d->unload_mode != KLibLoaderPrivate::UNLOAD && wrap->unload_mode != KLibWrapPrivate::UNLOAD) break; /* Now ensure, that the libs are only unloaded in the reverse direction they were loaded. */ if (!d->pending_close.containsRef( wrap )) { if (!deleted_one) /* Only diagnose, if we really haven't deleted anything. */ // kdDebug(150) << "try to dlclose " << wrap->name << ": not yet" << endl; break; } // kdDebug(150) << "try to dlclose " << wrap->name << ": yes, done." << endl; if ( !deleted_one ) { /* Only do the hack once in this loop. WABA: *HACK* We need to make sure to clear the clipboard before unloading a DSO because the DSO could have defined an object derived from QMimeSource and placed that on the clipboard. */ /*kapp->clipboard()->clear();*/ /* Well.. let's do something more subtle... convert the clipboard context to text. That should be safe as it only uses objects defined by Qt. */ if( kapp->clipboard()->ownsSelection()) { kapp->clipboard()->setText( kapp->clipboard()->text( QClipboard::Selection ), QClipboard::Selection ); } if( kapp->clipboard()->ownsClipboard()) { kapp->clipboard()->setText( kapp->clipboard()->text( QClipboard::Clipboard ), QClipboard::Clipboard ); } } deleted_one = true; lt_dlclose(wrap->handle); d->pending_close.removeRef(wrap); /* loaded_stack is AutoDelete, so wrap is freed */ d->loaded_stack.remove(); } }
KLibrary* KLibLoader::library( const char *name ) { if (!name) return 0; KLibWrapPrivate* wrap = m_libs[name]; if (wrap) { /* Nothing to do to load the library. */ wrap->ref_count++; return wrap->lib; } /* Test if this library was loaded at some time, but got unloaded meanwhile, whithout being dlclose()'ed. */ QPtrListIterator<KLibWrapPrivate> it(d->loaded_stack); for (; it.current(); ++it) { if (it.current()->name == name) wrap = it.current(); } if (wrap) { d->pending_close.removeRef(wrap); if (!wrap->lib) { /* This lib only was in loaded_stack, but not in m_libs. */ wrap->lib = new KLibrary( name, wrap->filename, wrap->handle ); } wrap->ref_count++; } else { QString libfile = findLibrary( name ); if ( libfile.isEmpty() ) { const QCString libname = makeLibName( name ); #ifndef NDEBUG kdDebug(150) << "library=" << name << ": No file named " << libname << " found in paths." << endl; #endif d->errorMessage = i18n("Library files for \"%1\" not found in paths.").arg(libname); return 0; } lt_dlhandle handle = lt_dlopen( QFile::encodeName(libfile) ); if ( !handle ) { const char* errmsg = lt_dlerror(); if(errmsg) d->errorMessage = QString::fromLocal8Bit(errmsg); else d->errorMessage = QString::null; return 0; } else d->errorMessage = QString::null; KLibrary *lib = new KLibrary( name, libfile, handle ); wrap = new KLibWrapPrivate(lib, handle); d->loaded_stack.prepend(wrap); } m_libs.insert( name, wrap ); connect( wrap->lib, SIGNAL( destroyed() ), this, SLOT( slotLibraryDestroyed() ) ); return wrap->lib; }