AtomicUtils.h

См. документацию.
00001 /*
00002  * CntmLib - Подсчет ссылок, потоки, синхронизация, асинхронные процедуры, события
00003  * Copyright (c) 2005, Овсеевич Роман, CntmLib@mail.ru
00004  * _______________________________________________________________________________
00005  * Разрешено свободное использование, копирование, распространение, изменение
00006  * (изменение сведений об авторских правах запрещено). Запрещена продажа и 
00007  * включение всей библиотеки или ее частей в другие библиотеки. В сведениях об
00008  * авторских правах на программу (или сведениях о программе, об авторах, 
00009  * использованных средствах разработки и т.д.) должна быть указана информация
00010  * о библиотеке CntmLib, ее авторе и, возможно, сайте или email'е.
00011  * Библиотека поставляется "как есть", без каких-либо гарантий со стороны автора.
00012  */ 
00013 
00014 #ifndef CNTM_ATOMICUTILS_H
00015 #define CNTM_ATOMICUTILS_H
00016 #include <cstddef>
00017 #include <Cntm/Utils/IntTypes.h>
00018 
00019 #if !defined(__linux__)
00020 #error Atomic operations not support this OS.
00021 #endif
00022 
00023 #if !defined(__GNUC__)
00024 #error Atomic operations not support this compiler.
00025 #endif
00026 
00027 #if !(defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__arm))
00028 #error Atomic operations not support this processor.
00029 #endif
00030 
00031 namespace Cntm
00032 {
00033         namespace SpecUtils
00034         {
00035 
00036 #if defined(__i386__)
00037 
00038                 /**
00039                  * Тип целой атомарной переменной.
00040                  */
00041                 typedef int AtomicIntType;
00042                 
00043                 /**
00044                  * Устанавливает новое значение, возвращает старое. Операция чтения старого значения и записи нового выполняется атомарно.
00045                  */
00046                 template <typename T>
00047                 static inline T* AtomicSwapPtr(T*volatile* Variable, T* NewValue)
00048                 {
00049                         asm volatile(
00050                                 "xchgl %0,%1"
00051                                         :"=r" (NewValue)
00052                                         :"m" (*Variable), "0" (NewValue)
00053                                         :"memory");
00054                         return NewValue;
00055                 }
00056 
00057                 /**
00058                  * Считать значение переменной.
00059                  */
00060                 static inline AtomicIntType AtomicGet(volatile const AtomicIntType* Variable)
00061                 {
00062                         return *Variable;
00063                 }
00064                 
00065                 /**
00066                  * Установить значение переменной.
00067                  */
00068                 static inline void AtomicSet(volatile AtomicIntType* Variable, AtomicIntType val)
00069                 {
00070                         *Variable = val;
00071                 }
00072                 
00073                 /**
00074                  * Прибавить к переменной v значение 1.
00075                  */
00076                 static inline void AtomicInc(volatile AtomicIntType* Variable)
00077                 {
00078                         asm volatile(
00079                                 "lock ; " "incl %0"
00080                                         :"=m" (*Variable)
00081                                         :"m" (*Variable));
00082                 }
00083 
00084                 /**
00085                  * Отнять от переменной v значение 1.
00086                  */
00087                 static inline void AtomicDec(volatile AtomicIntType* Variable)
00088                 {
00089                         asm volatile(
00090                                 "lock ; " "decl %0"
00091                                         :"=m" (*Variable)
00092                                         :"m" (*Variable));
00093                 }
00094 
00095                 /**
00096                  * Прибавить к переменной значение 1. Возвращает true, если при сложении текущее значение установилось в 0, иначе - false.
00097                  */
00098                 static inline bool AtomicIncAndTest(volatile AtomicIntType* Variable)
00099                 {
00100                         unsigned char res;
00101                 
00102                         asm volatile(
00103                                 "lock ; " "incl %0; sete %1"
00104                                         :"=m" (*Variable), "=qm" (res)
00105                                         :"m" (*Variable) : "memory");
00106                         return res != 0;
00107                 }
00108 
00109                 /**
00110                  * Отнять от переменной значение 1. Возвращает true, если при вычитании текущее значение установилось в 0, иначе - false.
00111                  */
00112                 static inline bool AtomicDecAndTest(volatile AtomicIntType* Variable)
00113                 {
00114                         unsigned char res;
00115 
00116                         asm volatile(
00117                                 "lock ; " "decl %0; sete %1"
00118                                         :"=m" (*Variable), "=qm" (res)
00119                                         :"m" (*Variable) : "memory");
00120                         return res != 0;
00121                 }
00122                 
00123 #endif // defined(__i386__)
00124                 
00125 #if defined(__x86_64__)
00126 
00127                 /**
00128                  * Тип целой атомарной переменной.
00129                  */
00130                 typedef int AtomicIntType;
00131                 
00132                 /**
00133                  * Устанавливает новое значение, возвращает старое. Операция чтения старого значения и записи нового выполняется атомарно.
00134                  */
00135                 template <typename T>
00136                 static inline T* AtomicSwapPtr(T*volatile* Variable, T* NewValue)
00137                 {
00138                         asm volatile(
00139                                 "xchgq %0,%1"
00140                                         :"=r" (NewValue)
00141                                         :"m" (*Variable), "0" (NewValue)
00142                                         :"memory");
00143                         return NewValue;
00144                 }
00145 
00146                 /**
00147                  * Считать значение переменной.
00148                  */
00149                 static inline AtomicIntType AtomicGet(volatile const AtomicIntType* Variable)
00150                 {
00151                         return *Variable;
00152                 }
00153                 
00154                 /**
00155                  * Установить значение переменной.
00156                  */
00157                 static inline void AtomicSet(volatile AtomicIntType* Variable, AtomicIntType val)
00158                 {
00159                         *Variable = val;
00160                 }
00161                 
00162                 /**
00163                  * Прибавить к переменной v значение 1.
00164                  */
00165                 static inline void AtomicInc(volatile AtomicIntType* Variable)
00166                 {
00167                         asm volatile(
00168                                 "lock ; " "incl %0"
00169                                         :"=m" (*Variable)
00170                                         :"m" (*Variable));
00171                 }
00172 
00173                 /**
00174                  * Отнять от переменной v значение 1.
00175                  */
00176                 static inline void AtomicDec(volatile AtomicIntType* Variable)
00177                 {
00178                         asm volatile(
00179                                 "lock ; " "decl %0"
00180                                         :"=m" (*Variable)
00181                                         :"m" (*Variable));
00182                 }
00183 
00184                 /**
00185                  * Прибавить к переменной значение 1. Возвращает true, если при сложении текущее значение установилось в 0, иначе - false.
00186                  */
00187                 static inline bool AtomicIncAndTest(volatile AtomicIntType* Variable)
00188                 {
00189                         unsigned char res;
00190                 
00191                         asm volatile(
00192                                 "lock ; " "incl %0; sete %1"
00193                                         :"=m" (*Variable), "=qm" (res)
00194                                         :"m" (*Variable) : "memory");
00195                         return res != 0;
00196                 }
00197 
00198                 /**
00199                  * Отнять от переменной значение 1. Возвращает true, если при вычитании текущее значение установилось в 0, иначе - false.
00200                  */
00201                 static inline bool AtomicDecAndTest(volatile AtomicIntType* Variable)
00202                 {
00203                         unsigned char res;
00204 
00205                         asm volatile(
00206                                 "lock ; " "decl %0; sete %1"
00207                                         :"=m" (*Variable), "=qm" (res)
00208                                         :"m" (*Variable) : "memory");
00209                         return res != 0;
00210                 }
00211                 
00212 #endif // defined(__x86_64__)
00213                 
00214 #if defined(__arm__) || defined(__arm)
00215 
00216                 /**
00217                  * Тип целой атомарной переменной.
00218                  */
00219                 typedef int AtomicIntType;
00220                 
00221                 /**
00222                  * Устанавливает новое значение, возвращает старое. Операция чтения старого значения и записи нового выполняется атомарно.
00223                  */
00224                 template < typename T >
00225                 static inline T* AtomicSwapPtr(T*volatile* Variable, T* NewValue)
00226                 {
00227                         T* res;
00228                         asm volatile(
00229                                 "swp %0, %2, [%1]"
00230                                         : "=&r" (res)
00231                                         : "r" (Variable), "r" (NewValue));
00232                         return res;
00233                 }
00234         
00235                 /**
00236                  * Считать значение переменной.
00237                  */
00238                 static inline AtomicIntType AtomicGet(volatile const AtomicIntType* Variable)
00239                 {
00240                         return *Variable;
00241                 }
00242                 
00243                 /**
00244                  * Установить значение переменной.
00245                  */
00246                 static inline void AtomicSet(volatile AtomicIntType* Variable, AtomicIntType val)
00247                 {
00248                         *Variable = val;
00249                 }
00250 
00251                 /**
00252                  * Прибавить к переменной значение 1. Возвращает true, если при сложении текущее значение установилось в 0, иначе - false.
00253                  */
00254                 static inline bool AtomicIncAndTest(volatile AtomicIntType* Variable)
00255                 {
00256                 int a, b, c;
00257 
00258                 asm volatile (
00259                                 "0:\n"
00260                                 "ldr %0, [%3]\n"
00261                                 "add %1, %0, %4\n"
00262                                 "swp %2, %1, [%3]\n"
00263                                 "cmp %0, %2\n"
00264                                 "swpne %1, %2, [%3]\n"
00265                                 "bne 0b"
00266                                 : "=&r" (a), "=&r" (b), "=&r" (c)
00267                                 : "r" (Variable), "r" (1)
00268                                 : "cc", "memory");
00269 
00270                 return b == 0;
00271                 }
00272                 
00273                 /**
00274                  * Отнять от переменной значение 1. Возвращает true, если при вычитании текущее значение установилось в 0, иначе - false.
00275                  */
00276                 static inline bool AtomicDecAndTest(volatile AtomicIntType* Variable)
00277                 {
00278                         int a, b, c;
00279 
00280                         asm volatile (
00281                                 "0:\n"
00282                                 "ldr %0, [%3]\n"
00283                                 "add %1, %0, %4\n"
00284                                 "swp %2, %1, [%3]\n"
00285                                 "cmp %0, %2\n"
00286                                 "swpne %1, %2, [%3]\n"
00287                                 "bne 0b"
00288                                         : "=&r" (a), "=&r" (b), "=&r" (c)
00289                                         : "r" (Variable), "r" (-1)
00290                                         : "cc", "memory");
00291 
00292                         return b == 0;
00293                 }
00294                 
00295                 /**
00296                  * Прибавить к переменной v значение 1.
00297                  */
00298                 static inline void AtomicInc(volatile AtomicIntType* Variable)
00299                 {
00300                         AtomicIncAndTest(Variable);
00301                 }
00302 
00303                 /**
00304                  * Отнять от переменной v значение 1.
00305                  */
00306                 static inline void AtomicDec(volatile AtomicIntType* Variable)
00307                 {
00308                         AtomicDecAndTest(Variable);
00309                 }
00310 
00311 #endif // defined(__arm__) || defined(__arm)
00312                 
00313                 /**
00314                  * Класс атомарной переменной. Все операции над атомарной переменной выполняются без прерывания другими потоками, т.е они потокобезопасны.
00315                  * 
00316                  * Тип числового значения атомарной переменной - AtomicVariable::Type.
00317                  * \ingroup SystemUtils         
00318                  */
00319                 class AtomicVariable
00320                 {
00321                 public:
00322                 
00323                         typedef AtomicIntType Type;
00324 
00325                         /**
00326                          * Конструктор инициализации.
00327                          */
00328                         AtomicVariable(Type Init = 0) { var = Init; }
00329 
00330                         /**
00331                          * Текущее значение переменной.
00332                          */
00333                         Type Value() volatile const { return AtomicGet(&var); }
00334 
00335                         /**
00336                          * Установить новое значение переменной.
00337                          */
00338                         void SetValue(Type Value) { AtomicSet(&var, Value); }
00339                         
00340                         /**
00341                          * Прибавить к переменной значение 1.
00342                          */
00343                         void Inc() { AtomicInc(&var); }
00344 
00345                         /**
00346                          * Отнять от переменной значение 1.
00347                          */
00348                         void Dec() { AtomicDec(&var); }
00349 
00350                         /**
00351                          * Прибавить к переменной значение 1. Возвращает true, если при сложении текущее значение установилось в 0, иначе - false.
00352                          */
00353                         bool IncAndTest() { return AtomicIncAndTest(&var); }
00354 
00355                         /**
00356                          * Отнять от переменной значение 1. Возвращает true, если при вычитании текущее значение установилось в 0, иначе - false.
00357                          */
00358                         bool DecAndTest() { return AtomicDecAndTest(&var); }
00359 
00360                 private:
00361 
00362                         /**
00363                          * Переменная.
00364                          */
00365                         volatile Type var;
00366                 };
00367 
00368         }
00369 }
00370 
00371 #endif //CNTM_ATOMICUTILS_H

SourceForge.net Logo
© Овсеевич Р.В. Документация по CntmLib 1.1.4 от 28 May 2008. Создано системой  doxygen 1.5.3