usermode/library/mtm/src/mode/pwb-common/beginend-bits.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  * Description:
00040  *   STM functions.
00041  *
00042  * Copyright (c) 2007-2009.
00043  *
00044  * This program is free software; you can redistribute it and/or
00045  * modify it under the terms of the GNU General Public License
00046  * as published by the Free Software Foundation, version 2
00047  * of the License.
00048  *
00049  * This program is distributed in the hope that it will be useful,
00050  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00051  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00052  * GNU General Public License for more details.
00053  */
00054 
00055 
00056 #include "mtm_i.h"
00057 #include "useraction.h"
00058 #include "mode/pwb-common/pwb_i.h"
00059 #include "mode/common/rwset.h"
00060 #include "cm.h" 
00061 
00062 //#define PRINT_DEBUG printf
00063 //#define MTM_DEBUG_PRINT printf
00064 
00065 static inline 
00066 bool
00067 pwb_trycommit (mtm_tx_t *tx, int enable_isolation)
00068 {
00069         assert((tx->mode == MTM_MODE_pwbnl && !enable_isolation) || 
00070                (tx->mode == MTM_MODE_pwbetl && enable_isolation));
00071 
00072         mode_data_t *modedata = (mode_data_t *) tx->modedata[tx->mode];
00073         w_entry_t   *w;
00074         mtm_word_t  t;
00075         int         i;
00076 #ifdef READ_LOCKED_DATA
00077         mtm_word_t  id;
00078 #endif /* READ_LOCKED_DATA */
00079 
00080         PRINT_DEBUG("==> mtm_commit(%p[%lu-%lu] nest_level:%d-->%d)\n", tx, 
00081                     (unsigned long)modedata->start, (unsigned long)modedata->end, tx->nesting, tx->nesting-1);
00082 
00083         /* Check status */
00084         assert(tx->status == TX_ACTIVE);
00085 
00086         /* Decrement nesting level */
00087         if (--tx->nesting > 0) {
00088                 return true;
00089         }       
00090 
00091         if (modedata->w_set.nb_entries > 0) {
00092                 /* Update transaction */
00093 
00094                 /* Get commit timestamp */
00095                 t = FETCH_INC_CLOCK + 1;
00096                 if (t >= VERSION_MAX) {
00097 #ifdef ROLLOVER_CLOCK
00098                         /* Abort: will reset the clock on next transaction start or delete */
00099 #ifdef _M_STATS_BUILD
00100                         m_stats_statset_increment(mtm_statsmgr, tx->statset, XACT, aborts, 1);
00101 #endif                                  
00102 # ifdef INTERNAL_STATS
00103                         tx->aborts_rollover++;
00104 # endif /* INTERNAL_STATS */
00105                         return false;
00106 #else /* ! ROLLOVER_CLOCK */
00107                         fprintf(stderr, "Exceeded maximum version number: 0x%lx\n", (unsigned long)t);
00108                         exit(1);
00109 #endif /* ! ROLLOVER_CLOCK */
00110                 }
00111 
00112                 /* Try to validate (only if a concurrent transaction has committed since tx->start) */
00113                 if (enable_isolation) {
00114                         if (modedata->start != t - 1 && !mtm_validate(tx, modedata)) {
00115                                 /* Cannot commit */
00116                                 /* Abort caused by invisible reads. */
00117                                 cm_visible_read(tx);
00118 #ifdef _M_STATS_BUILD
00119                                 m_stats_statset_increment(mtm_statsmgr, tx->statset, XACT, aborts, 1);
00120 #endif                                  
00121 #ifdef INTERNAL_STATS
00122                                 tx->aborts_validate_commit++;
00123 #endif /* INTERNAL_STATS */
00124                                 return false;
00125                         }
00126                 }
00127 
00128 # ifdef READ_LOCKED_DATA
00129                 /* Update instance number (becomes odd) */
00130                 id = tx->id;
00131                 assert(id % 2 == 0);
00132                 ATOMIC_STORE_REL(&tx->id, id + 1);
00133 # endif /* READ_LOCKED_DATA */
00134 
00135                 /* Make sure the persistent tm log is made stable */
00136                 M_TMLOG_COMMIT(tx->pcm_storeset, modedata->ptmlog, t);
00137 
00138                 /* Make sure previous stores are not reordered with the cl-flushes below */
00139                 PCM_WB_FENCE(tx->pcm_storeset);
00140 
00141                 /* Install new versions, drop locks and set new timestamp */
00142                 /* In the case when isolation is off, the write set contains entries 
00143                  * that point to private pseudo-locks. */
00144                 w = modedata->w_set.entries;
00145                 int wbflush_cnt=0;
00146                 for (i = modedata->w_set.nb_entries; i > 0; i--, w++) {
00147                         MTM_DEBUG_PRINT("==> write(t=%p[%lu-%lu],a=%p,d=%p-%d,m=%llx,v=%d)\n", tx,
00148                                         (unsigned long)modedata->start, (unsigned long)modedata->end,
00149                                         w->addr, (void *)w->value, (int)w->value, (unsigned long long) w->mask, (int)w->version);
00150                         /* Write the value in this entry to memory (it will probably land in the cache; that's okay.) */
00151                         if (w->mask != 0) {
00152                                 PCM_WB_STORE_ALIGNED_MASKED(tx->pcm_storeset, w->addr, w->value, w->mask);
00153                         }       
00154 # ifdef SYNC_TRUNCATION
00155                         /* Flush the cacheline to persistent memory if this is the last entry in this cache line. */
00156                         if (w->next_cache_neighbor == NULL) {
00157                                 /* If isolation is enabled, then the write set may contain non-persistent 
00158                                  * writes as well. Need to filter those out as we don't need to flush them 
00159                                  * out of the cache.
00160                                  * FIXME: Would it be better if we had marked them as non-persistent and
00161                                  *        avoid the bounds checking?
00162                                  */
00163                                 if (enable_isolation) {
00164                                         if (((uintptr_t) w->addr >= PSEGMENT_RESERVED_REGION_START &&
00165                                                  (uintptr_t) w->addr < (PSEGMENT_RESERVED_REGION_START + PSEGMENT_RESERVED_REGION_SIZE)))
00166                                         {
00167                                                 /* access is persistent -- flush */
00168                                                 PCM_WB_FLUSH(tx->pcm_storeset, w->addr);
00169                                                 wbflush_cnt++;
00170                                         }
00171                                 } else {
00172                                         PCM_WB_FLUSH(tx->pcm_storeset, w->addr);
00173                                         wbflush_cnt++;
00174                                 }
00175                         }       
00176 # endif
00177                         /* Only drop lock for last covered address in write set */
00178                         if (w->next == NULL) {
00179                                 ATOMIC_STORE_REL(w->lock, LOCK_SET_TIMESTAMP(t));
00180                         }       
00181                 }
00182                 
00183 #ifdef _M_STATS_BUILD
00184                 m_stats_statset_increment(mtm_statsmgr, tx->statset, XACT, wbflush, wbflush_cnt);
00185 #endif          
00186                 //printf("w_set.nb_entries= %d\n", modedata->w_set.nb_entries);
00187                 //printf("cachelines flushed= %d\n", wbflush_cnt);
00188 # ifdef READ_LOCKED_DATA
00189                 /* Update instance number (becomes even) */
00190                 ATOMIC_STORE_REL(&tx->id, id + 2);
00191 # endif /* READ_LOCKED_DATA */
00192 
00193 # ifdef SYNC_TRUNCATION
00194                         M_TMLOG_TRUNCATE_SYNC(tx->pcm_storeset, modedata->ptmlog);
00195 # endif
00196         }
00197 
00198 #ifdef _M_STATS_BUILD   
00199         m_stats_threadstat_aggregate(tx->threadstat, tx->statset);
00200         assert(m_stats_statset_destroy(&tx->statset) == M_R_SUCCESS);
00201 #endif  
00202 
00203         cm_reset(tx);
00204         return true;
00205 }
00206 
00207 
00208 /*
00209  * Rollback transaction.
00210  */
00211 static inline 
00212 void 
00213 pwb_rollback(mtm_tx_t *tx)
00214 {
00215         assert(tx->mode == MTM_MODE_pwbnl || MTM_MODE_pwbetl);
00216         mode_data_t   *modedata = (mode_data_t *) tx->modedata[tx->mode];
00217         w_entry_t     *w;
00218         int           i;
00219 #ifdef READ_LOCKED_DATA
00220         mtm_word_t    id;
00221 #endif /* READ_LOCKED_DATA */
00222 
00223         MTM_DEBUG_PRINT("==> pwb_rollback(%p[%lu-%lu])\n", tx,
00224                         (unsigned long)modedata->start,
00225                         (unsigned long)modedata->end);
00226 
00227         /* Check status */
00228         assert(tx->status == TX_ACTIVE);
00229 
00230         /* Mark the transaction in the persistent log as aborted. */
00231         M_TMLOG_ABORT(tx->pcm_storeset, modedata->ptmlog, 0);
00232 # ifdef SYNC_TRUNCATION
00233         M_TMLOG_TRUNCATE_SYNC(tx->pcm_storeset, modedata->ptmlog);
00234 # endif
00235 
00236         /* Drop locks */
00237         i = modedata->w_set.nb_entries;
00238         if (i > 0) {
00239 # ifdef READ_LOCKED_DATA
00240                 /* Update instance number (becomes odd) */
00241                 id = tx->id;
00242                 assert(id % 2 == 0);
00243                 ATOMIC_STORE_REL(&tx->id, id + 1);
00244 # endif /* READ_LOCKED_DATA */
00245                 w = modedata->w_set.entries;
00246                 for (; i > 0; i--, w++) {
00247                         if (w->next == NULL) {
00248                                 /* Only drop lock for last covered address in write set */
00249                                 ATOMIC_STORE(w->lock, LOCK_SET_TIMESTAMP(w->version));
00250                         }
00251                         PRINT_DEBUG2("==> discard(t=%p[%lu-%lu],a=%p,d=%p-%lu,v=%lu)\n", tx,
00252                                      (unsigned long)modedata->start, 
00253                                      (unsigned long)modedata->end,
00254                                      w->addr, 
00255                                      (void *)w->value, 
00256                                      (unsigned long)w->value,
00257                                      (unsigned long)w->version);
00258                 }
00259                 /* Make sure that all lock releases become visible */
00260                 ATOMIC_MB_WRITE;
00261 # ifdef READ_LOCKED_DATA
00262                 /* Update instance number (becomes even) */
00263                 ATOMIC_STORE_REL(&tx->id, id + 2);
00264 # endif /* READ_LOCKED_DATA */
00265         }
00266 
00267         tx->retries++;
00268 #ifdef INTERNAL_STATS
00269         tx->aborts++;
00270         if (tx->max_retries < tx->retries) {
00271                 tx->max_retries = tx->retries;
00272         }       
00273 #endif /* INTERNAL_STATS */
00274 
00275         /* Set status (no need for CAS or atomic op) */
00276         tx->status = TX_ABORTED;
00277 
00278         /* 
00279          * Reset nesting level 
00280          * 
00281          * CAUTION!!! Original TinySTM sets nesting to zero because on rollback 
00282          * it restarts the transaction at the begin_transaction call. Intel STM
00283          * does not make a call into begin_transaction call, so we need to be 
00284          * careful to ensure that nesting value equals 1 to represent transactional 
00285          * nesting. We do this later at prepare_transaction which is called before
00286          * restart. We don't do this here because pwb_rollback may also be called 
00287          * due to a user initiated abort.
00288          */
00289         tx->nesting = 0;
00290 
00291 }
00292 
00293 
00294 static void
00295 rollback_transaction (mtm_tx_t *tx)
00296 {
00297         pwb_rollback (tx);
00298         switch (tx->mode) {
00299                 case MTM_MODE_pwbnl:
00300 #if (defined(ALLOW_ABORTS))
00301                         mtm_local_rollback (tx);
00302 #endif
00303                         break;
00304                 case MTM_MODE_pwbetl:
00305                         mtm_local_rollback (tx);
00306                         break;
00307                 default:
00308                         assert(0);
00309         }
00310         mtm_useraction_list_run (tx->undo_action_list, 1);
00311 
00312         //FIXME: revert exceptions
00313         /*
00314         mtm_revert_cpp_exceptions ();
00315         if (tx->eh_in_flight)
00316         {
00317                 _Unwind_DeleteException (tx->eh_in_flight);
00318                 tx->eh_in_flight = NULL;
00319         }
00320         */
00321 }
00322 
00323 
00324 static inline
00325 void pwb_prepare_transaction(mtm_tx_t *tx)
00326 {
00327         assert(tx->mode == MTM_MODE_pwbnl || MTM_MODE_pwbetl);
00328         mode_data_t *modedata = (mode_data_t *) tx->modedata[tx->mode];
00329 
00330 start:
00331         /* Start timestamp */
00332         modedata->start = modedata->end = GET_CLOCK; /* OPT: Could be delayed until first read/write */
00333         /* Allow extensions */
00334         tx->can_extend = 1;
00335 #ifdef ROLLOVER_CLOCK
00336         if (modedata->start >= VERSION_MAX) {
00337                 /* Overflow: we must reset clock */
00338                 mtm_overflow(tx);
00339                 goto start;
00340         }
00341 #endif /* ROLLOVER_CLOCK */
00342         /* Read/write set */
00343         
00344         /* Because of the current state of the recoverable write-set block, reallocation is not
00345            possible. This program cannot be run until the recoverable blocks are
00346            somehow extendable. */
00347            //FIXME: What does the above comment mean?
00348         assert(modedata->w_set.reallocate == 0);
00349         
00350         modedata->w_set.nb_entries = 0;
00351         modedata->r_set.nb_entries = 0;
00352         mtm_useraction_clear (tx->commit_action_list);
00353         mtm_useraction_clear (tx->undo_action_list);
00354 
00355         M_TMLOG_BEGIN(modedata->ptmlog);
00356 
00357 #ifdef EPOCH_GC
00358         gc_set_epoch(modedata->start);
00359 #endif /* EPOCH_GC */
00360 
00361         tx->nesting = 1;
00362         tx->status = TX_ACTIVE; /* Set status (no need for CAS or atomic op) */
00363                                 /* FIXME: TinySTM 1.0.0 uses atomic op when
00364                                  * using the modular contention manager */                                                      
00365 
00366 }
00367 
00368 static inline
00369 uint32_t
00370 beginTransaction_internal (mtm_tx_t *tx, 
00371                            uint32_t prop, 
00372                            _ITM_srcLocation *srcloc,
00373                            int enable_isolation)
00374 {
00375         assert(tx->mode == MTM_MODE_pwbnl || MTM_MODE_pwbetl);
00376 
00377         MTM_DEBUG_PRINT("==> mtm_pwb_beginTransaction(%p) nest_level: %d-->%d\n", tx,
00378                         tx->nesting, tx->nesting+1);
00379 
00380         /* Increment nesting level */
00381         if (tx->nesting++ > 0) {
00382                 return a_runInstrumentedCode | a_saveLiveVariables;
00383         }       
00384 
00385         tx->jb = tx->tmp_jb;
00386         tx->prop = prop;
00387 
00388         /* Initialize transaction descriptor */
00389         pwb_prepare_transaction(tx);
00390 
00391 #ifdef _M_STATS_BUILD   
00392         assert(m_stats_statset_create(&tx->statset) == M_R_SUCCESS);
00393         assert(m_stats_statset_init(tx->statset, srcloc->psource) == M_R_SUCCESS);
00394 #endif  
00395 
00396         if ((prop & pr_doesGoIrrevocable) || !(prop & pr_instrumentedCode))
00397         {
00398                 // TODO: Implement serial mode 
00399                 return (prop & pr_uninstrumentedCode
00400                         ? a_runUninstrumentedCode : a_runInstrumentedCode);
00401         }
00402 
00403         if (enable_isolation) {
00404                 // TODO: Implement serial mode 
00405         }
00406 
00407         return a_runInstrumentedCode | a_saveLiveVariables;
00408 }
00409 
00410 
00411 static 
00412 bool
00413 trycommit_transaction (mtm_tx_t *tx, int enable_isolation)
00414 {
00415         if (pwb_trycommit(tx, enable_isolation)) {
00416                 if (tx->nesting > 0) {
00417                         return true;
00418                 }
00419                 switch (tx->mode) {
00420                         case MTM_MODE_pwbnl:
00421 #if (defined(ALLOW_ABORTS))
00422                                 mtm_local_commit (tx);
00423 #endif
00424                                 break;
00425                         case MTM_MODE_pwbetl:
00426                                 mtm_local_commit (tx);
00427                                 break;
00428                         default:
00429                                 assert(0);
00430                 }
00431 
00432                 mtm_useraction_list_run (tx->commit_action_list, 0);
00433 
00434                 /* Set status (no need for CAS or atomic op) */
00435                 tx->status = TX_COMMITTED;
00436                 return true;
00437         }
00438         return false;
00439 }

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