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

kdecore

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

kdecore

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

kdecore

Skip menu "kdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kdecore by doxygen 1.8.3.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |