• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdecore
 

tdecore

klibloader.cpp

00001 /* This file is part of the KDE libraries
00002    Copyright (C) 1999 Torben Weis <weis@kde.org>
00003    Copyright (C) 2000 Michael Matz <matz@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License version 2 as published by the Free Software Foundation.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017    Boston, MA 02110-1301, USA.
00018 */
00019 #include "config.h"
00020 
00021 #include <config.h>
00022 #include <tqclipboard.h>
00023 #include <tqfile.h>
00024 #include <tqdir.h>
00025 #include <tqtimer.h>
00026 #include <tqobjectdict.h>
00027 
00028 #include "tdeapplication.h"
00029 #include "klibloader.h"
00030 #include "kstandarddirs.h"
00031 #include "kdebug.h"
00032 #include "tdelocale.h"
00033 
00034 #include "ltdl.h"
00035 
00036 LT_SCOPE int lt_dlopen_flag;
00037 
00038 template class TQAsciiDict<KLibrary>;
00039 
00040 #include <stdlib.h> //getenv
00041 
00042 
00043 #if HAVE_DLFCN_H
00044 #  include <dlfcn.h>
00045 #endif
00046 
00047 #ifdef RTLD_GLOBAL
00048 #  define LT_GLOBAL             RTLD_GLOBAL
00049 #else
00050 #  ifdef DL_GLOBAL
00051 #    define LT_GLOBAL           DL_GLOBAL
00052 #  endif
00053 #endif /* !RTLD_GLOBAL */
00054 #ifndef LT_GLOBAL
00055 #  define LT_GLOBAL             0
00056 #endif /* !LT_GLOBAL */
00057 
00058 
00059 class KLibLoaderPrivate
00060 {
00061 public:
00062     TQPtrList<KLibWrapPrivate> loaded_stack;
00063     TQPtrList<KLibWrapPrivate> pending_close;
00064     enum {UNKNOWN, UNLOAD, DONT_UNLOAD} unload_mode;
00065 
00066     TQString errorMessage;
00067 };
00068 
00069 KLibLoader* KLibLoader::s_self = 0;
00070 
00071 // -------------------------------------------------------------------------
00072 
00073 KLibFactory::KLibFactory( TQObject* parent, const char* name )
00074     : TQObject( parent, name )
00075 {
00076 }
00077 
00078 KLibFactory::~KLibFactory()
00079 {
00080 //    kdDebug(150) << "Deleting KLibFactory " << this << endl;
00081 }
00082 
00083 TQObject* KLibFactory::create( TQObject* parent, const char* name, const char* classname, const TQStringList &args )
00084 {
00085     TQObject* obj = createObject( parent, name, classname, args );
00086     if ( obj )
00087     emit objectCreated( obj );
00088     return obj;
00089 }
00090 
00091 
00092 TQObject* KLibFactory::createObject( TQObject*, const char*, const char*, const TQStringList &)
00093 {
00094     return 0;
00095 }
00096 
00097 
00098 // -----------------------------------------------
00099 
00100 KLibrary::KLibrary( const TQString& libname, const TQString& filename, void * handle )
00101 {
00102     /* Make sure, we have a KLibLoader */
00103     (void) KLibLoader::self();
00104     m_libname = libname;
00105     m_filename = filename;
00106     m_handle = handle;
00107     m_factory = 0;
00108     m_timer = 0;
00109 }
00110 
00111 KLibrary::~KLibrary()
00112 {
00113 //    kdDebug(150) << "Deleting KLibrary " << this << "  " << m_libname << endl;
00114     if ( m_timer && m_timer->isActive() )
00115     m_timer->stop();
00116 
00117     // If any object is remaining, delete
00118     if ( m_objs.count() > 0 )
00119     {
00120         TQPtrListIterator<TQObject> it( m_objs );
00121         for ( ; it.current() ; ++it )
00122         {
00123             kdDebug(150) << "Factory still has object " << it.current() << " " << it.current()->name () << " Library = " << m_libname << endl;
00124             disconnect( it.current(), TQT_SIGNAL( destroyed() ),
00125                 this, TQT_SLOT( slotObjectDestroyed() ) );
00126         }
00127         m_objs.setAutoDelete(true);
00128         m_objs.clear();
00129     }
00130 
00131     if ( m_factory ) {
00132 //  kdDebug(150) << " ... deleting the factory " << m_factory << endl;
00133     delete m_factory;
00134         m_factory = 0L;
00135     }
00136 }
00137 
00138 TQString KLibrary::name() const
00139 {
00140     return m_libname;
00141 }
00142 
00143 TQString KLibrary::fileName() const
00144 {
00145     return m_filename;
00146 }
00147 
00148 KLibFactory* KLibrary::factory()
00149 {
00150     if ( m_factory )
00151         return m_factory;
00152 
00153     TQCString symname;
00154     symname.sprintf("init_%s", name().latin1() );
00155 
00156     void* sym = symbol( symname );
00157     if ( !sym )
00158     {
00159         KLibLoader::self()->d->errorMessage = i18n( "The library %1 does not offer an %2 function." ).arg( name(), "init_" + name() );
00160         kdWarning(150) << KLibLoader::self()->d->errorMessage << endl;
00161         return 0;
00162     }
00163 
00164     typedef KLibFactory* (*t_func)();
00165     t_func func = (t_func)sym;
00166     m_factory = func();
00167 
00168     if( !m_factory )
00169     {
00170         KLibLoader::self()->d->errorMessage = i18n( "The library %1 does not offer a TDE compatible factory." ).arg( name() );
00171         kdWarning(150) << KLibLoader::self()->d->errorMessage << endl;
00172         return 0;
00173     }
00174 
00175     connect( m_factory, TQT_SIGNAL( objectCreated( TQObject * ) ),
00176              this, TQT_SLOT( slotObjectCreated( TQObject * ) ) );
00177 
00178     return m_factory;
00179 }
00180 
00181 void* KLibrary::symbol( const char* symname ) const
00182 {
00183     void* sym = lt_dlsym( (lt_dlhandle) m_handle, symname );
00184     if ( !sym )
00185     {
00186         KLibLoader::self()->d->errorMessage = "KLibrary: " + TQString::fromLocal8Bit( lt_dlerror() ) + i18n( " %1 %2" ).arg( name() ).arg( symname );
00187         kdWarning(150) << KLibLoader::self()->d->errorMessage << endl;
00188         return 0;
00189     }
00190 
00191     return sym;
00192 }
00193 
00194 bool KLibrary::hasSymbol( const char* symname ) const
00195 {
00196     void* sym = lt_dlsym( (lt_dlhandle) m_handle, symname );
00197     return (sym != 0L );
00198 }
00199 
00200 void KLibrary::unload() const
00201 {
00202    if (KLibLoader::s_self)
00203       KLibLoader::s_self->unloadLibrary(TQFile::encodeName(name()));
00204 }
00205 
00206 void KLibrary::slotObjectCreated( TQObject *obj )
00207 {
00208   if ( !obj )
00209     return;
00210 
00211   if ( m_timer && m_timer->isActive() )
00212     m_timer->stop();
00213 
00214   if ( m_objs.containsRef( obj ) )
00215       return; // we know this object already
00216 
00217   connect( obj, TQT_SIGNAL( destroyed() ),
00218            this, TQT_SLOT( slotObjectDestroyed() ) );
00219 
00220   m_objs.append( obj );
00221 }
00222 
00223 void KLibrary::slotObjectDestroyed()
00224 {
00225   m_objs.removeRef( TQT_TQOBJECT_CONST(sender()) );
00226 
00227   if ( m_objs.count() == 0 )
00228   {
00229 //    kdDebug(150) << "KLibrary: shutdown timer for " << name() << " started!"
00230 //                 << endl;
00231 
00232     if ( !m_timer )
00233     {
00234       m_timer = new TQTimer( this, "klibrary_shutdown_timer" );
00235       connect( m_timer, TQT_SIGNAL( timeout() ),
00236                this, TQT_SLOT( slotTimeout() ) );
00237     }
00238 
00239     // as long as it's not stable make the timeout short, for debugging
00240     // pleasure (matz)
00241     //m_timer->start( 1000*60, true );
00242     m_timer->start( 1000*10, true );
00243   }
00244 }
00245 
00246 void KLibrary::slotTimeout()
00247 {
00248   if ( m_objs.count() != 0 )
00249     return;
00250 
00251   /* Don't go through KLibLoader::unloadLibrary(), because that uses the
00252      ref counter, but this timeout means to unconditionally close this library
00253      The destroyed() signal will take care to remove us from all lists.
00254   */
00255   delete this;
00256 }
00257 
00258 // -------------------------------------------------
00259 
00260 /* This helper class is needed, because KLibraries can go away without
00261    being unloaded. So we need some info about KLibraries even after its
00262    death. */
00263 class KLibWrapPrivate
00264 {
00265 public:
00266     KLibWrapPrivate(KLibrary *l, lt_dlhandle h);
00267 
00268     KLibrary *lib;
00269     enum {UNKNOWN, UNLOAD, DONT_UNLOAD} unload_mode;
00270     int ref_count;
00271     lt_dlhandle handle;
00272     TQString name;
00273     TQString filename;
00274 };
00275 
00276 KLibWrapPrivate::KLibWrapPrivate(KLibrary *l, lt_dlhandle h)
00277  : lib(l), ref_count(1), handle(h), name(l->name()), filename(l->fileName())
00278 {
00279     unload_mode = UNKNOWN;
00280     if (lt_dlsym(handle, "__kde_do_not_unload") != 0) {
00281 //        kdDebug(150) << "Will not unload " << name << endl;
00282         unload_mode = DONT_UNLOAD;
00283     } else if (lt_dlsym(handle, "__kde_do_unload") != 0) {
00284         unload_mode = UNLOAD;
00285     }
00286 }
00287 
00288 KLibLoader* KLibLoader::self()
00289 {
00290     if ( !s_self )
00291         s_self = new KLibLoader;
00292     return s_self;
00293 }
00294 
00295 void KLibLoader::cleanUp()
00296 {
00297   if ( !s_self )
00298     return;
00299 
00300   delete s_self;
00301   s_self = 0L;
00302 }
00303 
00304 KLibLoader::KLibLoader( TQObject* parent, const char* name )
00305     : TQObject( parent, name )
00306 {
00307     s_self = this;
00308     d = new KLibLoaderPrivate;
00309     lt_dlinit();
00310     d->unload_mode = KLibLoaderPrivate::UNKNOWN;
00311     if (getenv("TDE_NOUNLOAD") != 0)
00312         d->unload_mode = KLibLoaderPrivate::DONT_UNLOAD;
00313     else if (getenv("TDE_DOUNLOAD") != 0)
00314         d->unload_mode = KLibLoaderPrivate::UNLOAD;
00315     d->loaded_stack.setAutoDelete( true );
00316 }
00317 
00318 KLibLoader::~KLibLoader()
00319 {
00320 //    kdDebug(150) << "Deleting KLibLoader " << this << "  " << name() << endl;
00321 
00322     TQAsciiDictIterator<KLibWrapPrivate> it( m_libs );
00323     for (; it.current(); ++it )
00324     {
00325       kdDebug(150) << "The KLibLoader contains the library " << it.current()->name
00326         << " (" << it.current()->lib << ")" << endl;
00327       d->pending_close.append(it.current());
00328     }
00329 
00330     close_pending(0);
00331 
00332     delete d;
00333     d = 0L;
00334 }
00335 
00336 static inline TQCString makeLibName( const char* name )
00337 {
00338     TQCString libname(name);
00339     // only append ".la" if there is no extension
00340     // this allows to load non-libtool libraries as well
00341     // (mhk, 20000228)
00342     int pos = libname.findRev('/');
00343     if (pos < 0)
00344       pos = 0;
00345     if (libname.find('.', pos) < 0)
00346       libname += ".la";
00347     return libname;
00348 }
00349 
00350 //static
00351 TQString KLibLoader::findLibrary( const char * name, const TDEInstance * instance )
00352 {
00353     TQCString libname = makeLibName( name );
00354 
00355     // only look up the file if it is not an absolute filename
00356     // (mhk, 20000228)
00357     TQString libfile;
00358     if (!TQDir::isRelativePath(libname))
00359       libfile = TQFile::decodeName( libname );
00360     else
00361     {
00362       libfile = instance->dirs()->findResource( "module", libname );
00363       if ( libfile.isEmpty() )
00364       {
00365         libfile = instance->dirs()->findResource( "lib", libname );
00366 #ifndef NDEBUG
00367         if ( !libfile.isEmpty() && libname.left(3) == "lib" ) // don't warn for tdeinit modules
00368           kdDebug(150) << "library " << libname << " not found under 'module' but under 'lib'" << endl;
00369 #endif
00370       }
00371     }
00372     return libfile;
00373 }
00374 
00375 
00376 KLibrary* KLibLoader::globalLibrary( const char *name )
00377 {
00378 KLibrary *tmp;
00379 int olt_dlopen_flag = lt_dlopen_flag;
00380 
00381    lt_dlopen_flag |= LT_GLOBAL;
00382    kdDebug(150) << "Loading the next library global with flag "
00383                 << lt_dlopen_flag
00384                 << "." << endl;
00385    tmp = library(name);
00386    lt_dlopen_flag = olt_dlopen_flag;
00387 
00388 return tmp;
00389 }
00390 
00391 
00392 KLibrary* KLibLoader::library( const char *name )
00393 {
00394     if (!name)
00395         return 0;
00396 
00397     KLibWrapPrivate* wrap = m_libs[name];
00398     if (wrap) {
00399       /* Nothing to do to load the library.  */
00400       wrap->ref_count++;
00401       return wrap->lib;
00402     }
00403 
00404     /* Test if this library was loaded at some time, but got
00405        unloaded meanwhile, whithout being dlclose()'ed.  */
00406     TQPtrListIterator<KLibWrapPrivate> it(d->loaded_stack);
00407     for (; it.current(); ++it) {
00408       if (it.current()->name == name)
00409         wrap = it.current();
00410     }
00411 
00412     if (wrap) {
00413       d->pending_close.removeRef(wrap);
00414       if (!wrap->lib) {
00415         /* This lib only was in loaded_stack, but not in m_libs.  */
00416         wrap->lib = new KLibrary( name, wrap->filename, wrap->handle );
00417       }
00418       wrap->ref_count++;
00419     } else {
00420       TQString libfile = findLibrary( name );
00421       if ( libfile.isEmpty() )
00422       {
00423         const TQCString libname = makeLibName( name );
00424 #ifndef NDEBUG
00425         kdDebug(150) << "library=" << name << ": No file named " << libname << " found in paths." << endl;
00426 #endif
00427         d->errorMessage = i18n("Library files for \"%1\" not found in paths.").arg(TQString(libname));
00428         return 0;
00429       }
00430 
00431       lt_dlhandle handle = lt_dlopen( TQFile::encodeName(libfile) );
00432       if ( !handle )
00433       {
00434         const char* errmsg = lt_dlerror();
00435         if(errmsg)
00436             d->errorMessage = TQString::fromLocal8Bit(errmsg);
00437         else
00438             d->errorMessage = TQString::null;
00439         return 0;
00440       }
00441       else
00442         d->errorMessage = TQString::null;
00443 
00444       KLibrary *lib = new KLibrary( name, libfile, handle );
00445       wrap = new KLibWrapPrivate(lib, handle);
00446       d->loaded_stack.prepend(wrap);
00447     }
00448     m_libs.insert( name, wrap );
00449 
00450     connect( wrap->lib, TQT_SIGNAL( destroyed() ),
00451              this, TQT_SLOT( slotLibraryDestroyed() ) );
00452 
00453     return wrap->lib;
00454 }
00455 
00456 TQString KLibLoader::lastErrorMessage() const
00457 {
00458     return d->errorMessage;
00459 }
00460 
00461 void KLibLoader::unloadLibrary( const char *libname )
00462 {
00463   KLibWrapPrivate *wrap = m_libs[ libname ];
00464   if (!wrap)
00465     return;
00466   if (--wrap->ref_count)
00467     return;
00468 
00469 //  kdDebug(150) << "closing library " << libname << endl;
00470 
00471   m_libs.remove( libname );
00472 
00473   disconnect( wrap->lib, TQT_SIGNAL( destroyed() ),
00474               this, TQT_SLOT( slotLibraryDestroyed() ) );
00475   close_pending( wrap );
00476 }
00477 
00478 KLibFactory* KLibLoader::factory( const char* name )
00479 {
00480     KLibrary* lib = library( name );
00481     if ( !lib )
00482         return 0;
00483 
00484     return lib->factory();
00485 }
00486 
00487 void KLibLoader::slotLibraryDestroyed()
00488 {
00489   const KLibrary *lib = static_cast<const KLibrary *>( sender() );
00490 
00491   TQAsciiDictIterator<KLibWrapPrivate> it( m_libs );
00492   for (; it.current(); ++it )
00493     if ( it.current()->lib == lib )
00494     {
00495       KLibWrapPrivate *wrap = it.current();
00496       wrap->lib = 0;  /* the KLibrary object is already away */
00497       m_libs.remove( it.currentKey() );
00498       close_pending( wrap );
00499       return;
00500     }
00501 }
00502 
00503 void KLibLoader::close_pending(KLibWrapPrivate *wrap)
00504 {
00505   if (wrap && !d->pending_close.containsRef( wrap ))
00506     d->pending_close.append( wrap );
00507 
00508   /* First delete all KLibrary objects in pending_close, but _don't_ unload
00509      the DSO behind it.  */
00510   TQPtrListIterator<KLibWrapPrivate> it(d->pending_close);
00511   for (; it.current(); ++it) {
00512     wrap = it.current();
00513     if (wrap->lib) {
00514       disconnect( wrap->lib, TQT_SIGNAL( destroyed() ),
00515                   this, TQT_SLOT( slotLibraryDestroyed() ) );
00516       KLibrary* to_delete = wrap->lib;
00517       wrap->lib = 0L; // unset first, because KLibrary dtor can cause
00518       delete to_delete; // recursive call to close_pending()
00519     }
00520   }
00521 
00522   if (d->unload_mode == KLibLoaderPrivate::DONT_UNLOAD) {
00523     d->pending_close.clear();
00524     return;
00525   }
00526 
00527   bool deleted_one = false;
00528   while ((wrap = d->loaded_stack.first())) {
00529     /* Let's first see, if we want to try to unload this lib.
00530        If the env. var TDE_DOUNLOAD is set, we try to unload every lib.
00531        If not, we look at the lib itself, and unload it only, if it exports
00532        the symbol __kde_do_unload. */
00533     if (d->unload_mode != KLibLoaderPrivate::UNLOAD
00534         && wrap->unload_mode != KLibWrapPrivate::UNLOAD)
00535       break;
00536 
00537     /* Now ensure, that the libs are only unloaded in the reverse direction
00538        they were loaded.  */
00539     if (!d->pending_close.containsRef( wrap )) {
00540       if (!deleted_one)
00541         /* Only diagnose, if we really haven't deleted anything. */
00542 //        kdDebug(150) << "try to dlclose " << wrap->name << ": not yet" << endl;
00543       break;
00544     }
00545 
00546 //    kdDebug(150) << "try to dlclose " << wrap->name << ": yes, done." << endl;
00547 
00548     if ( !deleted_one ) {
00549       /* Only do the hack once in this loop.
00550          WABA: *HACK*
00551          We need to make sure to clear the clipboard before unloading a DSO
00552          because the DSO could have defined an object derived from QMimeSource
00553          and placed that on the clipboard. */
00554       /*kapp->clipboard()->clear();*/
00555 
00556       /* Well.. let's do something more subtle... convert the clipboard context
00557          to text. That should be safe as it only uses objects defined by Qt. */
00558       if( kapp->clipboard()->ownsSelection()) {
00559     kapp->clipboard()->setText(
00560             kapp->clipboard()->text( TQClipboard::Selection ), TQClipboard::Selection );
00561       }
00562       if( kapp->clipboard()->ownsClipboard()) {
00563     kapp->clipboard()->setText(
00564             kapp->clipboard()->text( TQClipboard::Clipboard ), TQClipboard::Clipboard );
00565       }
00566     }
00567 
00568     deleted_one = true;
00569     lt_dlclose(wrap->handle);
00570     d->pending_close.removeRef(wrap);
00571     /* loaded_stack is AutoDelete, so wrap is freed */
00572     d->loaded_stack.remove();
00573   }
00574 }
00575 
00576 void KLibLoader::virtual_hook( int, void* )
00577 { /*BASE::virtual_hook( id, data );*/ }
00578 
00579 void KLibFactory::virtual_hook( int, void* )
00580 { /*BASE::virtual_hook( id, data );*/ }
00581 
00582 #include "klibloader.moc"

tdecore

Skip menu "tdecore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.6.3
This website is maintained by Timothy Pearson.