/[svn]/linuxsampler/trunk/src/common/SynchronizedConfig.h
ViewVC logotype

Diff of /linuxsampler/trunk/src/common/SynchronizedConfig.h

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 840 by persson, Sun Feb 26 13:00:08 2006 UTC revision 1790 by persson, Sun Nov 2 12:05:00 2008 UTC
# Line 1  Line 1 
1  /***************************************************************************  /***************************************************************************
2   *                                                                         *   *                                                                         *
3   *   Copyright (C) 2006 Andreas Persson                                    *   *   Copyright (C) 2006-2008 Andreas Persson                               *
4   *                                                                         *   *                                                                         *
5   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
6   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 18  Line 18 
18   *   MA  02110-1301  USA                                                   *   *   MA  02110-1301  USA                                                   *
19   ***************************************************************************/   ***************************************************************************/
20    
21  #ifndef __SYNCHRONIZEDCONFIG_H__  #ifndef SYNCHRONIZEDCONFIG_H
22  #define __SYNCHRONIZEDCONFIG_H__  #define SYNCHRONIZEDCONFIG_H
23    
24  #include "atomic.h"  #include <set>
25    #include <unistd.h>
26    #include "lsatomic.h"
27    
28  namespace LinuxSampler {  namespace LinuxSampler {
29    
30      /**      /**
31       * Thread safe management of configuration data, where the data is       * Thread safe management of configuration data, where the data is
32       * updated by a single non real time thread and read by a single       * updated by a single non real time thread and read by a number
33       * real time thread.       * of real time threads.
34       *       *
35       * The synchronization is achieved by using two instances of the       * The synchronization is achieved by using two instances of the
36       * configuration data. The non real time thread gets access to the       * configuration data. The non real time thread gets access to the
37       * instance not currently in use by the real time thread by       * instance not currently in use by the real time threads by
38       * calling GetConfigForUpdate(). After the data is updated, the       * calling GetConfigForUpdate(). After the data is updated, the
39       * non real time thread must call SwitchConfig() and redo the       * non real time thread must call SwitchConfig() and redo the
40       * update on the other instance. SwitchConfig() blocks until it is       * update on the other instance. SwitchConfig() blocks until it is
41       * safe to modify the other instance.       * safe to modify the other instance.
42       *       *
43       * The real time thread calls Lock() to get access to the data,       * The real time threads need one Reader object each to access the
44       * and Unlock() when it is finished reading the data. (Neither       * configuration data. This object must be created outside the
45       * Lock nor Unlock will block the real time thread, or use any       * real time thread. The Lock() function returns a reference to
46       * system calls.)       * the data to be read, and Unlock() must be called when finished
47         * reading the data. (Neither Lock nor Unlock will block the real
48         * time thread, or use any system calls.)
49       */       */
50      template<class T>      template<class T>
51      class SynchronizedConfig {      class SynchronizedConfig {
# Line 50  namespace LinuxSampler { Line 54  namespace LinuxSampler {
54    
55              // methods for the real time thread              // methods for the real time thread
56    
57              /**              class Reader {
58               * Gets the configuration object for use by the real time                  public:
59               * thread. The object is safe to use (read only) until                      /**
60               * Unlock() is called.                       * Gets the configuration object for use by the
61               *                       * real time thread. The object is safe to use
62               * @returns a reference to the configuration object to be                       * (read only) until Unlock() is called.
63               *          read by the real time thread                       *
64               */                       * @returns a reference to the configuration
65              const T& Lock() {                       *          object to be read by the real time
66                  atomic_set(&lock, 1);                       *          thread
67                  return config[atomic_read(&indexAtomic)];                       */
68              }                      const T& Lock() {
69                            lock.store(1, memory_order_relaxed);
70              /**                          atomic_thread_fence(memory_order_seq_cst);
71               * Unlock the configuration object. Unlock() must be                          return parent.config[parent.indexAtomic.load(
72               * called by the real time thread after it has finished                                  memory_order_acquire)];
73               * reading the configuration object. If the non real time                      }
74               * thread is waiting in SwitchConfig() it will be awaken.  
75               */                      /**
76              void Unlock() {                       * Unlock the configuration object. Unlock() must
77                  atomic_set(&lock, 0);                       * be called by the real time thread after it has
78              }                       * finished reading the configuration object. If
79                         * the non real time thread is waiting in
80                         * SwitchConfig() it will be awaken when no real
81                         * time threads are locked anymore.
82                         */
83                        void Unlock() {
84                            atomic_thread_fence(memory_order_release);
85                            lock.store(0, memory_order_relaxed);
86                            flag.store(0, memory_order_relaxed);
87                        }
88    
89                        Reader(SynchronizedConfig& config);
90                        ~Reader();
91                    private:
92                        friend class SynchronizedConfig;
93                        SynchronizedConfig& parent;
94                        atomic<int> lock;
95                        atomic<int> flag;
96                        Reader *next; // only used locally in SwitchConfig
97                };
98    
99    
100              // methods for the non real time thread              // methods for the non real time thread
# Line 103  namespace LinuxSampler { Line 126  namespace LinuxSampler {
126              T& SwitchConfig();              T& SwitchConfig();
127    
128          private:          private:
129              atomic_t lock;              atomic<int> indexAtomic;
             atomic_t indexAtomic;  
130              int updateIndex;              int updateIndex;
131              T config[2];              T config[2];
132                std::set<Reader*> readers;
133      };      };
134    
135      template<class T> SynchronizedConfig<T>::SynchronizedConfig() {      template<class T> SynchronizedConfig<T>::SynchronizedConfig() :
136          atomic_set(&lock, 0);          indexAtomic(0) {
137          atomic_set(&indexAtomic, 0);          updateIndex = 1;
138      }      }
139    
140      template<class T> T& SynchronizedConfig<T>::GetConfigForUpdate() {      template<class T> T& SynchronizedConfig<T>::GetConfigForUpdate() {
         updateIndex = atomic_read(&indexAtomic) ^ 1;  
141          return config[updateIndex];          return config[updateIndex];
142      }      }
143    
144      template<class T> T& SynchronizedConfig<T>::SwitchConfig() {      template<class T> T& SynchronizedConfig<T>::SwitchConfig() {
145          atomic_set(&indexAtomic, updateIndex);          indexAtomic.store(updateIndex, memory_order_release);
146          while (atomic_read(&lock))          atomic_thread_fence(memory_order_seq_cst);
147    
148            // first put all locking readers in a linked list
149            Reader* lockingReaders = 0;
150            for (typename std::set<Reader*>::iterator iter = readers.begin() ;
151                 iter != readers.end() ;
152                 iter++) {
153                (*iter)->flag.store(1, memory_order_relaxed);
154                if ((*iter)->lock.load(memory_order_acquire) &&
155                    (*iter)->flag.load(memory_order_acquire)) {
156                    (*iter)->next = lockingReaders;
157                    lockingReaders = *iter;
158                }
159            }
160    
161            // wait until there are no locking readers left
162            while (lockingReaders) {
163              usleep(50000);              usleep(50000);
164          return config[updateIndex ^ 1];              Reader** prev = &lockingReaders;
165                for (Reader* p = lockingReaders ; p ; p = p->next) {
166                   if (p->lock.load(memory_order_acquire) &&
167                       p->flag.load(memory_order_acquire)) prev = &p->next;
168                    else *prev = p->next; // unlink
169                }
170            }
171    
172            updateIndex ^= 1;
173            return config[updateIndex];
174        }
175    
176    
177        // ----- Reader ----
178    
179        template <class T>
180        SynchronizedConfig<T>::Reader::Reader(SynchronizedConfig& config) :
181            parent(config), lock(0), flag(0) {
182            parent.readers.insert(this);
183        }
184    
185        template <class T>
186        SynchronizedConfig<T>::Reader::~Reader() {
187            parent.readers.erase(this);
188      }      }
189    
190  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.840  
changed lines
  Added in v.1790

  ViewVC Help
Powered by ViewVC