usermode/library/mtm/src/cm.h

00001 /*
00002     Copyright (C) 2011 Computer Sciences Department, 
00003     University of Wisconsin -- Madison
00004 
00005     ----------------------------------------------------------------------
00006 
00007     This file is part of Mnemosyne: Lightweight Persistent Memory, 
00008     originally developed at the University of Wisconsin -- Madison.
00009 
00010     Mnemosyne was originally developed primarily by Haris Volos
00011     with contributions from Andres Jaan Tack.
00012 
00013     ----------------------------------------------------------------------
00014 
00015     Mnemosyne is free software; you can redistribute it and/or
00016     modify it under the terms of the GNU General Public License
00017     as published by the Free Software Foundation, version 2
00018     of the License.
00019  
00020     Mnemosyne is distributed in the hope that it will be useful,
00021     but WITHOUT ANY WARRANTY; without even the implied warranty of
00022     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023     GNU General Public License for more details.
00024 
00025     You should have received a copy of the GNU General Public License
00026     along with this program; if not, write to the Free Software
00027     Foundation, Inc., 51 Franklin Street, Fifth Floor, 
00028     Boston, MA  02110-1301, USA.
00029 
00030 ### END HEADER ###
00031 */
00032 
00033 /*
00034  * Source code is partially derived from TinySTM (license is attached)
00035  *
00036  *
00037  * Author(s):
00038  *   Pascal Felber <pascal.felber@unine.ch>
00039  *
00040  * Copyright (c) 2007-2009.
00041  *
00042  * This program is free software; you can redistribute it and/or
00043  * modify it under the terms of the GNU General Public License
00044  * as published by the Free Software Foundation, version 2
00045  * of the License.
00046  *
00047  * This program is distributed in the hope that it will be useful,
00048  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00049  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00050  * GNU General Public License for more details.
00051  */
00052 
00053 
00054 #ifndef _CM_H
00055 #define _CM_H
00056 
00057 #define CM_RESTART          1
00058 #define CM_RESTART_NO_LOAD  2
00059 #define CM_RESTART_LOCKED   3
00060 
00061 static inline
00062 int 
00063 cm_conflict(mtm_tx_t *tx, volatile mtm_word_t *lock, mtm_word_t *l)
00064 {
00065         mode_data_t *modedata = (mode_data_t *) tx->modedata[tx->mode];
00066         w_entry_t   *w;
00067 
00068 #if CM == CM_PRIORITY
00069         if (tx->retries >= cm_threshold) {
00070                 if (LOCK_GET_PRIORITY(*l) < tx->priority ||
00071                         (LOCK_GET_PRIORITY(*l) == tx->priority &&
00072                         *l < (mtm_word_t)modedata->w_set.entries
00073                         && !LOCK_GET_WAIT(*l))) 
00074                 {
00075                         /* We have higher priority */
00076                         if (ATOMIC_CAS_FULL(lock, *l, LOCK_SET_PRIORITY_WAIT(*l, tx->priority)) == 0) {
00077                                 return CM_RESTART;
00078                         }
00079                         *l = LOCK_SET_PRIORITY_WAIT(*l, tx->priority);
00080                 }
00081                 /* Wait until lock is free or another transaction waits for one of our locks */
00082                 while (1) {
00083                         int        nb;
00084                         mtm_word_t lw;
00085 
00086                         w = modedata->w_set.entries;
00087                         for (nb = modedata->w_set.nb_entries; nb > 0; nb--, w++) {
00088                                 lw = ATOMIC_LOAD(w->lock);
00089                                 if (LOCK_GET_WAIT(lw)) {
00090                                         /* Another transaction waits for one of our locks */
00091                                         goto give_up;
00092                                 }
00093                         }
00094                         /* Did the lock we are waiting for get updated? */
00095                         lw = ATOMIC_LOAD(lock);
00096                         if (*l != lw) {
00097                                 *l = lw;
00098                                 return CM_RESTART_NO_LOAD;
00099                         }
00100                 }
00101 give_up:
00102                         if (tx->priority < PRIORITY_MAX) {
00103                                 tx->priority++;
00104                         } else {
00105                                 PRINT_DEBUG("Reached maximum priority\n");
00106                         }
00107                         tx->c_lock = lock;
00108                 }
00109 #elif CM == CM_DELAY
00110                 tx->c_lock = lock;
00111 #endif /* CM == CM_DELAY */
00112                 return CM_RESTART_LOCKED;
00113 }
00114 
00115 
00116 static inline
00117 int
00118 cm_upgrade_lock(mtm_tx_t *tx)
00119 {
00120 #if CM == CM_PRIORITY
00121         if (tx->visible_reads >= vr_threshold && vr_threshold >= 0) {
00122                 return 1;
00123         } else {
00124                 return 0;
00125         }
00126 #endif /* CM == CM_PRIORITY */
00127         return 0;
00128 }
00129 
00130 
00131 static inline
00132 void
00133 cm_delay(mtm_tx_t *tx)
00134 {
00135 #if CM == CM_BACKOFF
00136         unsigned long wait;
00137         volatile int  j;
00138 
00139         /* Simple RNG (good enough for backoff) */
00140         tx->seed ^= (tx->seed << 17);
00141         tx->seed ^= (tx->seed >> 13);
00142         tx->seed ^= (tx->seed << 5);
00143         wait = tx->seed % tx->backoff;
00144         for (j = 0; j < wait; j++) {
00145                 /* Do nothing */
00146         }
00147         if (tx->backoff < MAX_BACKOFF) {
00148                 tx->backoff <<= 1;
00149         }
00150 #endif /* CM == CM_BACKOFF */
00151 
00152 #if CM == CM_DELAY || CM == CM_PRIORITY
00153         /* Wait until contented lock is free */
00154         if (tx->c_lock != NULL) {
00155                 /* Busy waiting (yielding is expensive) */
00156                 while (LOCK_GET_OWNED(ATOMIC_LOAD(tx->c_lock))) {
00157 # ifdef WAIT_YIELD
00158                         sched_yield();
00159 # endif /* WAIT_YIELD */
00160                 }
00161                 tx->c_lock = NULL;
00162         }
00163 #endif /* CM == CM_DELAY || CM == CM_PRIORITY */
00164 }
00165 
00166 
00167 static inline
00168 void
00169 cm_visible_read(mtm_tx_t *tx)
00170 {
00171 #if CM == CM_PRIORITY
00172         tx->visible_reads++;
00173 #endif /* CM == CM_PRIORITY */
00174 }
00175 
00176 
00177 static inline
00178 void
00179 cm_reset(mtm_tx_t *tx)
00180 {
00181 #if CM == CM_PRIORITY || defined(INTERNAL_STATS)
00182         tx->retries = 0;
00183 #endif /* CM == CM_PRIORITY || defined(INTERNAL_STATS) */
00184 
00185 #if CM == CM_BACKOFF
00186         /* Reset backoff */
00187         tx->backoff = MIN_BACKOFF;
00188 #endif /* CM == CM_BACKOFF */
00189 
00190 #if CM == CM_PRIORITY
00191         /* Reset priority */
00192         tx->priority = 0;
00193         tx->visible_reads = 0;
00194 #endif /* CM == CM_PRIORITY */
00195 }
00196 
00197 
00198 #endif

Generated on Sat Apr 23 11:43:36 2011 for Mnemosyne by  doxygen 1.4.7