Thread-safety

Thread-safty of the classes is provided by the template argument of ltmm::loader, ltmm::handle, and ltmm::backend.

The argument should implement a thread policy of locking shared resources, and storage of thread-specific data.

For single-threaded applications, the thread policy ltmm::single_thread provided should suffice.

A thread-policy should have the following interface:

    class thread_policy { 
    public: 
      thread_policy() 
      void lock();
      void unlock();
      void set_error(const char*);
      const char* get_error() const; 
    };
The member functions should do:
Constructor
The class must be default constructable, as a static object of this class is instantised in the ltmm::loader class.
lock
Must recursively lock a critical section stored with the object.
unlock
Must recursively unlock a critical section stored with the object.
set_error
Must store argument in thread-specific storage.
get_error
Must fetch return value from thread-specific storage.

For example, in a POSIX environment, an implementation, like the following would be appropriate:

    class posix_policy {
    private:
      // Mutex to lock access 
      pthread_mutex_t _mutex; 
      // Thread-specific key
      pthread_key_t   _key;
      // For once intialisation of the key
      volatile bool   _once;
      // How may locks have we got so far. 
      int             _count;
      // Get the thread specific data. 
      std::string*    specific() volatile { 
        if (!_once) {
          lock(); 
          if (!_once) {
             pthread_key_create(&_key, 0);
             _once = true;
          }
          unlock(); 
        }
        std::string* s = 
          static_cast<std::string*>(pthread_getspecific(_key));
        if (!s) {
          s = new std::string();
          pthread_setspecific(_key, (void*)s);
        }
        return s;
      }
    public: 
      // Constructor
      posix_policy() : _once(false), _count(0) {
        pthread_mutex_init(&_mutex, 0); }
      // Recursive lock of mutex
      void lock() { 
        if (_count == 0) pthread_mutex_lock(&_mutex); 
        _count++;
      }
      // Recursive unlock of mutex
      void unlock() { 
        _count--
        if (_count == 0) pthread_mutex_unlock(&_mutex);  
      }
      // Set the error in thread-specific data 
      void set_error(const char* msg) {
        std::string s = specific();
        *s = msg;
      }
      // Get the error from thread specific data. 
      const char get_error() const {
        std::string s = specific();
        return s->c_str();
      }
    };

Notice the use of double-checked locking, to avoid race conditions on initialising the key. Strictly speaking, it may not be needed, but rather safe than sorry :-)

With a class like that, it's easy to make the ltmm classes thread-safe:

    typedef ltmm::loader<posix_policy>  loader;
    typedef ltmm::handle<posix_policy>  handle;
    typedef ltmm::backend<posix_policy> backend;
    typedef ltmm::symbol                symbol
    
    int main () {
      try {
        loader& l = loader::instance();
        handle& h = l.load("libm.so");
        symbol* s = h.find_symbol("cos");
        ((double(*)(double))(s->ptr()))(0);
      }
      catch (...) {
        return 1;
      }
      return 0;
    }
Top of page
Last update Mon Jun 27 13:25:17 2005
Christian Holm
Created by DoxyGen 1.4.3-20050530