• 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 "tdestandarddirs.h"
31#include "kdebug.h"
32#include "tdelocale.h"
33
34#include "ltdl.h"
35
36LT_SCOPE int lt_dlopen_flag;
37
38template 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
59class KLibLoaderPrivate
60{
61public:
62 TQPtrList<KLibWrapPrivate> loaded_stack;
63 TQPtrList<KLibWrapPrivate> pending_close;
64 enum {UNKNOWN, UNLOAD, DONT_UNLOAD} unload_mode;
65
66 TQString errorMessage;
67};
68
69KLibLoader* KLibLoader::s_self = 0;
70
71// -------------------------------------------------------------------------
72
73KLibFactory::KLibFactory( TQObject* parent, const char* name )
74 : TQObject( parent, name )
75{
76}
77
78KLibFactory::~KLibFactory()
79{
80// kdDebug(150) << "Deleting KLibFactory " << this << endl;
81}
82
83TQObject* 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
92TQObject* KLibFactory::createObject( TQObject*, const char*, const char*, const TQStringList &)
93{
94 return 0;
95}
96
97
98// -----------------------------------------------
99
100KLibrary::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
111KLibrary::~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(), TQ_SIGNAL( destroyed() ),
125 this, TQ_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
138TQString KLibrary::name() const
139{
140 return m_libname;
141}
142
143TQString KLibrary::fileName() const
144{
145 return m_filename;
146}
147
148KLibFactory* 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, TQ_SIGNAL( objectCreated( TQObject * ) ),
176 this, TQ_SLOT( slotObjectCreated( TQObject * ) ) );
177
178 return m_factory;
179}
180
181void* 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
194bool KLibrary::hasSymbol( const char* symname ) const
195{
196 void* sym = lt_dlsym( (lt_dlhandle) m_handle, symname );
197 return (sym != 0L );
198}
199
200void KLibrary::unload() const
201{
202 if (KLibLoader::s_self)
203 KLibLoader::s_self->unloadLibrary(TQFile::encodeName(name()));
204}
205
206void 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, TQ_SIGNAL( destroyed() ),
218 this, TQ_SLOT( slotObjectDestroyed() ) );
219
220 m_objs.append( obj );
221}
222
223void KLibrary::slotObjectDestroyed()
224{
225 m_objs.removeRef( 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, TQ_SIGNAL( timeout() ),
236 this, TQ_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
246void 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. */
263class KLibWrapPrivate
264{
265public:
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
276KLibWrapPrivate::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
288KLibLoader* KLibLoader::self()
289{
290 if ( !s_self )
291 s_self = new KLibLoader;
292 return s_self;
293}
294
295void KLibLoader::cleanUp()
296{
297 if ( !s_self )
298 return;
299
300 delete s_self;
301 s_self = 0L;
302}
303
304KLibLoader::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
318KLibLoader::~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
336static 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
351TQString 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
376KLibrary* KLibLoader::globalLibrary( const char *name )
377{
378KLibrary *tmp;
379int 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
388return tmp;
389}
390
391
392KLibrary* 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, TQ_SIGNAL( destroyed() ),
451 this, TQ_SLOT( slotLibraryDestroyed() ) );
452
453 return wrap->lib;
454}
455
456TQString KLibLoader::lastErrorMessage() const
457{
458 return d->errorMessage;
459}
460
461void 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, TQ_SIGNAL( destroyed() ),
474 this, TQ_SLOT( slotLibraryDestroyed() ) );
475 close_pending( wrap );
476}
477
478KLibFactory* KLibLoader::factory( const char* name )
479{
480 KLibrary* lib = library( name );
481 if ( !lib )
482 return 0;
483
484 return lib->factory();
485}
486
487void 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
503void 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, TQ_SIGNAL( destroyed() ),
515 this, TQ_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 /*tdeApp->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( tdeApp->clipboard()->ownsSelection()) {
559 tdeApp->clipboard()->setText(
560 tdeApp->clipboard()->text( TQClipboard::Selection ), TQClipboard::Selection );
561 }
562 if( tdeApp->clipboard()->ownsClipboard()) {
563 tdeApp->clipboard()->setText(
564 tdeApp->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
576void KLibLoader::virtual_hook( int, void* )
577{ /*BASE::virtual_hook( id, data );*/ }
578
579void KLibFactory::virtual_hook( int, void* )
580{ /*BASE::virtual_hook( id, data );*/ }
581
582#include "klibloader.moc"
KLibFactory
If you develop a library that is to be loaded dynamically at runtime, then you should return a pointe...
Definition: klibloader.h:334
KLibFactory::create
TQObject * create(TQObject *parent=0, const char *name=0, const char *classname="TQObject", const TQStringList &args=TQStringList())
Creates a new object.
Definition: klibloader.cpp:83
KLibFactory::createObject
virtual TQObject * createObject(TQObject *parent=0, const char *name=0, const char *className="TQObject", const TQStringList &args=TQStringList())=0
Creates a new object.
Definition: klibloader.cpp:92
KLibFactory::objectCreated
void objectCreated(TQObject *obj)
Emitted in create.
KLibFactory::KLibFactory
KLibFactory(TQObject *parent=0, const char *name=0)
Create a new factory.
Definition: klibloader.cpp:73
KLibLoader
The KLibLoader allows you to load libraries dynamically at runtime.
Definition: klibloader.h:143
KLibLoader::self
static KLibLoader * self()
Returns a pointer to the factory.
Definition: klibloader.cpp:288
KLibLoader::globalLibrary
KLibrary * globalLibrary(const char *name)
Loads and initializes a library.
Definition: klibloader.cpp:376
KLibLoader::lastErrorMessage
TQString lastErrorMessage() const
Returns an error message that can be useful to debug the problem.
Definition: klibloader.cpp:456
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::library
virtual KLibrary * library(const char *libname)
Loads and initializes a library.
Definition: klibloader.cpp:392
KLibLoader::~KLibLoader
~KLibLoader()
You should NEVER destruct an instance of KLibLoader until you know what you are doing.
Definition: klibloader.cpp:318
KLibLoader::factory
KLibFactory * factory(const char *libname)
Loads and initializes a library.
Definition: klibloader.cpp:478
KLibLoader::unloadLibrary
virtual void unloadLibrary(const char *libname)
Unloads the library with the given name.
Definition: klibloader.cpp:461
KLibrary
Represents a dynamically loaded library.
Definition: klibloader.h:51
KLibrary::hasSymbol
bool hasSymbol(const char *name) const
Looks up a symbol from the library.
Definition: klibloader.cpp:194
KLibrary::fileName
TQString fileName() const
Returns the file name of the library.
Definition: klibloader.cpp:143
KLibrary::name
TQString name() const
Returns the name of the library.
Definition: klibloader.cpp:138
KLibrary::unload
void unload() const
Unloads the library.
Definition: klibloader.cpp:200
KLibrary::KLibrary
KLibrary(const TQString &libname, const TQString &filename, void *handle)
Don't create KLibrary objects on your own.
Definition: klibloader.cpp:100
KLibrary::factory
KLibFactory * factory()
Returns the factory of the library.
Definition: klibloader.cpp:148
KLibrary::symbol
void * symbol(const char *name) const
Looks up a symbol from the library.
Definition: klibloader.cpp:181
TDEInstance
Access to KDE global objects for use in shared libraries.
Definition: kinstance.h:48
TDEInstance::dirs
TDEStandardDirs * dirs() const
Returns the application standard dirs object.
Definition: kinstance.cpp:189
TDEStandardDirs::findResource
TQString findResource(const char *type, const TQString &filename) const
Tries to find a resource in the following order:
Definition: tdestandarddirs.cpp:317
endl
kndbgstream & endl(kndbgstream &s)
Does nothing.
Definition: kdebug.h:583
KStdAction::name
const char * name(StdAction id)
tdelocale.h

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.9.4
This website is maintained by Timothy Pearson.