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

tdecore

  • tdecore
klibloader.cpp
1 /* This file is part of the KDE libraries
2  Copyright (C) 1999 Torben Weis <weis@kde.org>
3  Copyright (C) 2000 Michael Matz <matz@kde.org>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License version 2 as published by the Free Software Foundation.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 */
19 #include "config.h"
20 
21 #include <config.h>
22 #include <tqclipboard.h>
23 #include <tqfile.h>
24 #include <tqdir.h>
25 #include <tqtimer.h>
26 #include <tqobjectdict.h>
27 
28 #include "tdeapplication.h"
29 #include "klibloader.h"
30 #include "kstandarddirs.h"
31 #include "kdebug.h"
32 #include "tdelocale.h"
33 
34 #include "ltdl.h"
35 
36 LT_SCOPE int lt_dlopen_flag;
37 
38 template class TQAsciiDict<KLibrary>;
39 
40 #include <stdlib.h> //getenv
41 
42 
43 #if HAVE_DLFCN_H
44 # include <dlfcn.h>
45 #endif
46 
47 #ifdef RTLD_GLOBAL
48 # define LT_GLOBAL RTLD_GLOBAL
49 #else
50 # ifdef DL_GLOBAL
51 # define LT_GLOBAL DL_GLOBAL
52 # endif
53 #endif /* !RTLD_GLOBAL */
54 #ifndef LT_GLOBAL
55 # define LT_GLOBAL 0
56 #endif /* !LT_GLOBAL */
57 
58 
59 class KLibLoaderPrivate
60 {
61 public:
62  TQPtrList<KLibWrapPrivate> loaded_stack;
63  TQPtrList<KLibWrapPrivate> pending_close;
64  enum {UNKNOWN, UNLOAD, DONT_UNLOAD} unload_mode;
65 
66  TQString errorMessage;
67 };
68 
69 KLibLoader* KLibLoader::s_self = 0;
70 
71 // -------------------------------------------------------------------------
72 
73 KLibFactory::KLibFactory( TQObject* parent, const char* name )
74  : TQObject( parent, name )
75 {
76 }
77 
78 KLibFactory::~KLibFactory()
79 {
80 // kdDebug(150) << "Deleting KLibFactory " << this << endl;
81 }
82 
83 TQObject* KLibFactory::create( TQObject* parent, const char* name, const char* classname, const TQStringList &args )
84 {
85  TQObject* obj = createObject( parent, name, classname, args );
86  if ( obj )
87  emit objectCreated( obj );
88  return obj;
89 }
90 
91 
92 TQObject* KLibFactory::createObject( TQObject*, const char*, const char*, const TQStringList &)
93 {
94  return 0;
95 }
96 
97 
98 // -----------------------------------------------
99 
100 KLibrary::KLibrary( const TQString& libname, const TQString& filename, void * handle )
101 {
102  /* Make sure, we have a KLibLoader */
103  (void) KLibLoader::self();
104  m_libname = libname;
105  m_filename = filename;
106  m_handle = handle;
107  m_factory = 0;
108  m_timer = 0;
109 }
110 
111 KLibrary::~KLibrary()
112 {
113 // kdDebug(150) << "Deleting KLibrary " << this << " " << m_libname << endl;
114  if ( m_timer && m_timer->isActive() )
115  m_timer->stop();
116 
117  // If any object is remaining, delete
118  if ( m_objs.count() > 0 )
119  {
120  TQPtrListIterator<TQObject> it( m_objs );
121  for ( ; it.current() ; ++it )
122  {
123  kdDebug(150) << "Factory still has object " << it.current() << " " << it.current()->name () << " Library = " << m_libname << endl;
124  disconnect( it.current(), TQT_SIGNAL( destroyed() ),
125  this, TQT_SLOT( slotObjectDestroyed() ) );
126  }
127  m_objs.setAutoDelete(true);
128  m_objs.clear();
129  }
130 
131  if ( m_factory ) {
132 // kdDebug(150) << " ... deleting the factory " << m_factory << endl;
133  delete m_factory;
134  m_factory = 0L;
135  }
136 }
137 
138 TQString KLibrary::name() const
139 {
140  return m_libname;
141 }
142 
143 TQString KLibrary::fileName() const
144 {
145  return m_filename;
146 }
147 
148 KLibFactory* KLibrary::factory()
149 {
150  if ( m_factory )
151  return m_factory;
152 
153  TQCString symname;
154  symname.sprintf("init_%s", name().latin1() );
155 
156  void* sym = symbol( symname );
157  if ( !sym )
158  {
159  KLibLoader::self()->d->errorMessage = i18n( "The library %1 does not offer an %2 function." ).arg( name(), "init_" + name() );
160  kdWarning(150) << KLibLoader::self()->d->errorMessage << endl;
161  return 0;
162  }
163 
164  typedef KLibFactory* (*t_func)();
165  t_func func = (t_func)sym;
166  m_factory = func();
167 
168  if( !m_factory )
169  {
170  KLibLoader::self()->d->errorMessage = i18n( "The library %1 does not offer a TDE compatible factory." ).arg( name() );
171  kdWarning(150) << KLibLoader::self()->d->errorMessage << endl;
172  return 0;
173  }
174 
175  connect( m_factory, TQT_SIGNAL( objectCreated( TQObject * ) ),
176  this, TQT_SLOT( slotObjectCreated( TQObject * ) ) );
177 
178  return m_factory;
179 }
180 
181 void* KLibrary::symbol( const char* symname ) const
182 {
183  void* sym = lt_dlsym( (lt_dlhandle) m_handle, symname );
184  if ( !sym )
185  {
186  KLibLoader::self()->d->errorMessage = "KLibrary: " + TQString::fromLocal8Bit( lt_dlerror() ) + i18n( " %1 %2" ).arg( name() ).arg( symname );
187  kdWarning(150) << KLibLoader::self()->d->errorMessage << endl;
188  return 0;
189  }
190 
191  return sym;
192 }
193 
194 bool KLibrary::hasSymbol( const char* symname ) const
195 {
196  void* sym = lt_dlsym( (lt_dlhandle) m_handle, symname );
197  return (sym != 0L );
198 }
199 
200 void KLibrary::unload() const
201 {
202  if (KLibLoader::s_self)
203  KLibLoader::s_self->unloadLibrary(TQFile::encodeName(name()));
204 }
205 
206 void KLibrary::slotObjectCreated( TQObject *obj )
207 {
208  if ( !obj )
209  return;
210 
211  if ( m_timer && m_timer->isActive() )
212  m_timer->stop();
213 
214  if ( m_objs.containsRef( obj ) )
215  return; // we know this object already
216 
217  connect( obj, TQT_SIGNAL( destroyed() ),
218  this, TQT_SLOT( slotObjectDestroyed() ) );
219 
220  m_objs.append( obj );
221 }
222 
223 void KLibrary::slotObjectDestroyed()
224 {
225  m_objs.removeRef( TQT_TQOBJECT_CONST(sender()) );
226 
227  if ( m_objs.count() == 0 )
228  {
229 // kdDebug(150) << "KLibrary: shutdown timer for " << name() << " started!"
230 // << endl;
231 
232  if ( !m_timer )
233  {
234  m_timer = new TQTimer( this, "klibrary_shutdown_timer" );
235  connect( m_timer, TQT_SIGNAL( timeout() ),
236  this, TQT_SLOT( slotTimeout() ) );
237  }
238 
239  // as long as it's not stable make the timeout short, for debugging
240  // pleasure (matz)
241  //m_timer->start( 1000*60, true );
242  m_timer->start( 1000*10, true );
243  }
244 }
245 
246 void KLibrary::slotTimeout()
247 {
248  if ( m_objs.count() != 0 )
249  return;
250 
251  /* Don't go through KLibLoader::unloadLibrary(), because that uses the
252  ref counter, but this timeout means to unconditionally close this library
253  The destroyed() signal will take care to remove us from all lists.
254  */
255  delete this;
256 }
257 
258 // -------------------------------------------------
259 
260 /* This helper class is needed, because KLibraries can go away without
261  being unloaded. So we need some info about KLibraries even after its
262  death. */
263 class KLibWrapPrivate
264 {
265 public:
266  KLibWrapPrivate(KLibrary *l, lt_dlhandle h);
267 
268  KLibrary *lib;
269  enum {UNKNOWN, UNLOAD, DONT_UNLOAD} unload_mode;
270  int ref_count;
271  lt_dlhandle handle;
272  TQString name;
273  TQString filename;
274 };
275 
276 KLibWrapPrivate::KLibWrapPrivate(KLibrary *l, lt_dlhandle h)
277  : lib(l), ref_count(1), handle(h), name(l->name()), filename(l->fileName())
278 {
279  unload_mode = UNKNOWN;
280  if (lt_dlsym(handle, "__kde_do_not_unload") != 0) {
281 // kdDebug(150) << "Will not unload " << name << endl;
282  unload_mode = DONT_UNLOAD;
283  } else if (lt_dlsym(handle, "__kde_do_unload") != 0) {
284  unload_mode = UNLOAD;
285  }
286 }
287 
288 KLibLoader* KLibLoader::self()
289 {
290  if ( !s_self )
291  s_self = new KLibLoader;
292  return s_self;
293 }
294 
295 void KLibLoader::cleanUp()
296 {
297  if ( !s_self )
298  return;
299 
300  delete s_self;
301  s_self = 0L;
302 }
303 
304 KLibLoader::KLibLoader( TQObject* parent, const char* name )
305  : TQObject( parent, name )
306 {
307  s_self = this;
308  d = new KLibLoaderPrivate;
309  lt_dlinit();
310  d->unload_mode = KLibLoaderPrivate::UNKNOWN;
311  if (getenv("TDE_NOUNLOAD") != 0)
312  d->unload_mode = KLibLoaderPrivate::DONT_UNLOAD;
313  else if (getenv("TDE_DOUNLOAD") != 0)
314  d->unload_mode = KLibLoaderPrivate::UNLOAD;
315  d->loaded_stack.setAutoDelete( true );
316 }
317 
318 KLibLoader::~KLibLoader()
319 {
320 // kdDebug(150) << "Deleting KLibLoader " << this << " " << name() << endl;
321 
322  TQAsciiDictIterator<KLibWrapPrivate> it( m_libs );
323  for (; it.current(); ++it )
324  {
325  kdDebug(150) << "The KLibLoader contains the library " << it.current()->name
326  << " (" << it.current()->lib << ")" << endl;
327  d->pending_close.append(it.current());
328  }
329 
330  close_pending(0);
331 
332  delete d;
333  d = 0L;
334 }
335 
336 static inline TQCString makeLibName( const char* name )
337 {
338  TQCString libname(name);
339  // only append ".la" if there is no extension
340  // this allows to load non-libtool libraries as well
341  // (mhk, 20000228)
342  int pos = libname.findRev('/');
343  if (pos < 0)
344  pos = 0;
345  if (libname.find('.', pos) < 0)
346  libname += ".la";
347  return libname;
348 }
349 
350 //static
351 TQString KLibLoader::findLibrary( const char * name, const TDEInstance * instance )
352 {
353  TQCString libname = makeLibName( name );
354 
355  // only look up the file if it is not an absolute filename
356  // (mhk, 20000228)
357  TQString libfile;
358  if (!TQDir::isRelativePath(libname))
359  libfile = TQFile::decodeName( libname );
360  else
361  {
362  libfile = instance->dirs()->findResource( "module", libname );
363  if ( libfile.isEmpty() )
364  {
365  libfile = instance->dirs()->findResource( "lib", libname );
366 #ifndef NDEBUG
367  if ( !libfile.isEmpty() && libname.left(3) == "lib" ) // don't warn for tdeinit modules
368  kdDebug(150) << "library " << libname << " not found under 'module' but under 'lib'" << endl;
369 #endif
370  }
371  }
372  return libfile;
373 }
374 
375 
376 KLibrary* KLibLoader::globalLibrary( const char *name )
377 {
378 KLibrary *tmp;
379 int olt_dlopen_flag = lt_dlopen_flag;
380 
381  lt_dlopen_flag |= LT_GLOBAL;
382  kdDebug(150) << "Loading the next library global with flag "
383  << lt_dlopen_flag
384  << "." << endl;
385  tmp = library(name);
386  lt_dlopen_flag = olt_dlopen_flag;
387 
388 return tmp;
389 }
390 
391 
392 KLibrary* KLibLoader::library( const char *name )
393 {
394  if (!name)
395  return 0;
396 
397  KLibWrapPrivate* wrap = m_libs[name];
398  if (wrap) {
399  /* Nothing to do to load the library. */
400  wrap->ref_count++;
401  return wrap->lib;
402  }
403 
404  /* Test if this library was loaded at some time, but got
405  unloaded meanwhile, whithout being dlclose()'ed. */
406  TQPtrListIterator<KLibWrapPrivate> it(d->loaded_stack);
407  for (; it.current(); ++it) {
408  if (it.current()->name == name)
409  wrap = it.current();
410  }
411 
412  if (wrap) {
413  d->pending_close.removeRef(wrap);
414  if (!wrap->lib) {
415  /* This lib only was in loaded_stack, but not in m_libs. */
416  wrap->lib = new KLibrary( name, wrap->filename, wrap->handle );
417  }
418  wrap->ref_count++;
419  } else {
420  TQString libfile = findLibrary( name );
421  if ( libfile.isEmpty() )
422  {
423  const TQCString libname = makeLibName( name );
424 #ifndef NDEBUG
425  kdDebug(150) << "library=" << name << ": No file named " << libname << " found in paths." << endl;
426 #endif
427  d->errorMessage = i18n("Library files for \"%1\" not found in paths.").arg(TQString(libname));
428  return 0;
429  }
430 
431  lt_dlhandle handle = lt_dlopen( TQFile::encodeName(libfile) );
432  if ( !handle )
433  {
434  const char* errmsg = lt_dlerror();
435  if(errmsg)
436  d->errorMessage = TQString::fromLocal8Bit(errmsg);
437  else
438  d->errorMessage = TQString::null;
439  return 0;
440  }
441  else
442  d->errorMessage = TQString::null;
443 
444  KLibrary *lib = new KLibrary( name, libfile, handle );
445  wrap = new KLibWrapPrivate(lib, handle);
446  d->loaded_stack.prepend(wrap);
447  }
448  m_libs.insert( name, wrap );
449 
450  connect( wrap->lib, TQT_SIGNAL( destroyed() ),
451  this, TQT_SLOT( slotLibraryDestroyed() ) );
452 
453  return wrap->lib;
454 }
455 
456 TQString KLibLoader::lastErrorMessage() const
457 {
458  return d->errorMessage;
459 }
460 
461 void KLibLoader::unloadLibrary( const char *libname )
462 {
463  KLibWrapPrivate *wrap = m_libs[ libname ];
464  if (!wrap)
465  return;
466  if (--wrap->ref_count)
467  return;
468 
469 // kdDebug(150) << "closing library " << libname << endl;
470 
471  m_libs.remove( libname );
472 
473  disconnect( wrap->lib, TQT_SIGNAL( destroyed() ),
474  this, TQT_SLOT( slotLibraryDestroyed() ) );
475  close_pending( wrap );
476 }
477 
478 KLibFactory* KLibLoader::factory( const char* name )
479 {
480  KLibrary* lib = library( name );
481  if ( !lib )
482  return 0;
483 
484  return lib->factory();
485 }
486 
487 void KLibLoader::slotLibraryDestroyed()
488 {
489  const KLibrary *lib = static_cast<const KLibrary *>( sender() );
490 
491  TQAsciiDictIterator<KLibWrapPrivate> it( m_libs );
492  for (; it.current(); ++it )
493  if ( it.current()->lib == lib )
494  {
495  KLibWrapPrivate *wrap = it.current();
496  wrap->lib = 0; /* the KLibrary object is already away */
497  m_libs.remove( it.currentKey() );
498  close_pending( wrap );
499  return;
500  }
501 }
502 
503 void KLibLoader::close_pending(KLibWrapPrivate *wrap)
504 {
505  if (wrap && !d->pending_close.containsRef( wrap ))
506  d->pending_close.append( wrap );
507 
508  /* First delete all KLibrary objects in pending_close, but _don't_ unload
509  the DSO behind it. */
510  TQPtrListIterator<KLibWrapPrivate> it(d->pending_close);
511  for (; it.current(); ++it) {
512  wrap = it.current();
513  if (wrap->lib) {
514  disconnect( wrap->lib, TQT_SIGNAL( destroyed() ),
515  this, TQT_SLOT( slotLibraryDestroyed() ) );
516  KLibrary* to_delete = wrap->lib;
517  wrap->lib = 0L; // unset first, because KLibrary dtor can cause
518  delete to_delete; // recursive call to close_pending()
519  }
520  }
521 
522  if (d->unload_mode == KLibLoaderPrivate::DONT_UNLOAD) {
523  d->pending_close.clear();
524  return;
525  }
526 
527  bool deleted_one = false;
528  while ((wrap = d->loaded_stack.first())) {
529  /* Let's first see, if we want to try to unload this lib.
530  If the env. var TDE_DOUNLOAD is set, we try to unload every lib.
531  If not, we look at the lib itself, and unload it only, if it exports
532  the symbol __kde_do_unload. */
533  if (d->unload_mode != KLibLoaderPrivate::UNLOAD
534  && wrap->unload_mode != KLibWrapPrivate::UNLOAD)
535  break;
536 
537  /* Now ensure, that the libs are only unloaded in the reverse direction
538  they were loaded. */
539  if (!d->pending_close.containsRef( wrap )) {
540  if (!deleted_one)
541  /* Only diagnose, if we really haven't deleted anything. */
542 // kdDebug(150) << "try to dlclose " << wrap->name << ": not yet" << endl;
543  break;
544  }
545 
546 // kdDebug(150) << "try to dlclose " << wrap->name << ": yes, done." << endl;
547 
548  if ( !deleted_one ) {
549  /* Only do the hack once in this loop.
550  WABA: *HACK*
551  We need to make sure to clear the clipboard before unloading a DSO
552  because the DSO could have defined an object derived from QMimeSource
553  and placed that on the clipboard. */
554  /*kapp->clipboard()->clear();*/
555 
556  /* Well.. let's do something more subtle... convert the clipboard context
557  to text. That should be safe as it only uses objects defined by Qt. */
558  if( kapp->clipboard()->ownsSelection()) {
559  kapp->clipboard()->setText(
560  kapp->clipboard()->text( TQClipboard::Selection ), TQClipboard::Selection );
561  }
562  if( kapp->clipboard()->ownsClipboard()) {
563  kapp->clipboard()->setText(
564  kapp->clipboard()->text( TQClipboard::Clipboard ), TQClipboard::Clipboard );
565  }
566  }
567 
568  deleted_one = true;
569  lt_dlclose(wrap->handle);
570  d->pending_close.removeRef(wrap);
571  /* loaded_stack is AutoDelete, so wrap is freed */
572  d->loaded_stack.remove();
573  }
574 }
575 
576 void KLibLoader::virtual_hook( int, void* )
577 { /*BASE::virtual_hook( id, data );*/ }
578 
579 void KLibFactory::virtual_hook( int, void* )
580 { /*BASE::virtual_hook( id, data );*/ }
581 
582 #include "klibloader.moc"
KLibLoader::lastErrorMessage
TQString lastErrorMessage() const
Returns an error message that can be useful to debug the problem.
Definition: klibloader.cpp:456
KLibLoader::globalLibrary
KLibrary * globalLibrary(const char *name)
Loads and initializes a library.
Definition: klibloader.cpp:376
KLibFactory
If you develop a library that is to be loaded dynamically at runtime, then you should return a pointe...
Definition: klibloader.h:333
KLibFactory::KLibFactory
KLibFactory(TQObject *parent=0, const char *name=0)
Create a new factory.
Definition: klibloader.cpp:73
KLibFactory::createObject
virtual TQObject * createObject(TQObject *parent=0, const char *name=0, const char *className=TQOBJECT_OBJECT_NAME_STRING, const TQStringList &args=TQStringList())=0
Creates a new object.
Definition: klibloader.cpp:92
KLibrary::name
TQString name() const
Returns the name of the library.
Definition: klibloader.cpp:138
TDEStandardDirs::findResource
TQString findResource(const char *type, const TQString &filename) const
Tries to find a resource in the following order:
Definition: kstandarddirs.cpp:317
TDEInstance::dirs
TDEStandardDirs * dirs() const
Returns the application standard dirs object.
Definition: kinstance.cpp:187
KLibrary::KLibrary
KLibrary(const TQString &libname, const TQString &filename, void *handle)
Don't create KLibrary objects on your own.
Definition: klibloader.cpp:100
KLibrary::fileName
TQString fileName() const
Returns the file name of the library.
Definition: klibloader.cpp:143
KLibFactory::create
TQObject * create(TQObject *parent=0, const char *name=0, const char *classname=TQOBJECT_OBJECT_NAME_STRING, const TQStringList &args=TQStringList())
Creates a new object.
Definition: klibloader.cpp:83
KLibLoader::unloadLibrary
virtual void unloadLibrary(const char *libname)
Unloads the library with the given name.
Definition: klibloader.cpp:461
KLibLoader::~KLibLoader
~KLibLoader()
You should NEVER destruct an instance of KLibLoader until you know what you are doing.
Definition: klibloader.cpp:318
tdelocale.h
KLibrary::unload
void unload() const
Unloads the library.
Definition: klibloader.cpp:200
KLibrary
Represents a dynamically loaded library.
Definition: klibloader.h:50
KLibFactory::objectCreated
void objectCreated(TQObject *obj)
Emitted in create.
KLibrary::factory
KLibFactory * factory()
Returns the factory of the library.
Definition: klibloader.cpp:148
KLibrary::hasSymbol
bool hasSymbol(const char *name) const
Looks up a symbol from the library.
Definition: klibloader.cpp:194
KLibLoader::library
virtual KLibrary * library(const char *libname)
Loads and initializes a library.
Definition: klibloader.cpp:392
KStdAction::name
const char * name(StdAction id)
KLibLoader::self
static KLibLoader * self()
Returns a pointer to the factory.
Definition: klibloader.cpp:288
KLibLoader
The KLibLoader allows you to load libraries dynamically at runtime.
Definition: klibloader.h:142
KLibLoader::findLibrary
static TQString findLibrary(const char *name, const TDEInstance *instance=TDEGlobal::instance())
Helper method which looks for a library in the standard paths ("module" and "lib" resources)...
Definition: klibloader.cpp:351
KLibLoader::factory
KLibFactory * factory(const char *libname)
Loads and initializes a library.
Definition: klibloader.cpp:478
KLibrary::symbol
void * symbol(const char *name) const
Looks up a symbol from the library.
Definition: klibloader.cpp:181
endl
kndbgstream & endl(kndbgstream &s)
Does nothing.
Definition: kdebug.h:583
TDEInstance
Access to KDE global objects for use in shared libraries.
Definition: kinstance.h:47

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
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.8.8
This website is maintained by Timothy Pearson.