usermode/library/mtm/src/mode/pwb-common/barrier-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 
00066 #ifndef _PWB_COMMON_BARRIER_BITS_JKI671_H
00067 #define _PWB_COMMON_BARRIER_BITS_JKI671_H
00068 
00069 
00070 /*
00071  * Extend snapshot range.
00072  */
00073 static inline 
00074 int 
00075 pwb_extend (mtm_tx_t *tx, mode_data_t *modedata)
00076 {
00077         mtm_word_t now;
00078 
00079         PRINT_DEBUG("==> pwb_extend(%p[%lu-%lu])\n", tx, 
00080                     (unsigned long)modedata->start,
00081                     (unsigned long)modedata->end);
00082 
00083         /* Check status */
00084         assert(tx->status == TX_ACTIVE);
00085 
00086         /* Get current time */
00087         now = GET_CLOCK;
00088 #ifdef ROLLOVER_CLOCK
00089         if (now >= VERSION_MAX) {
00090                 /* Clock overflow */
00091                 return 0;
00092         }
00093 #endif /* ROLLOVER_CLOCK */
00094         /* Try to validate read set */
00095         if (mtm_validate(tx, modedata)) {
00096                 /* It works: we can extend until now */
00097                 modedata->end = now;
00098                 return 1;
00099         }
00100         return 0;
00101 }
00102 
00103 
00127 static
00128 w_entry_t* initialize_write_set_entry(w_entry_t* entry,
00129                                       volatile mtm_word_t *address,
00130                                       mtm_word_t value,
00131                                       mtm_word_t mask,
00132                                       volatile mtm_word_t version,
00133                                       volatile mtm_word_t* lock,
00134                                       int is_nonvolatile)
00135 {       
00136         /* Add address to write set */
00137         entry->addr = address;
00138         entry->lock = lock;
00139         entry->mask = 0x0;
00140         mask_new_value(entry, address, value, mask);
00141         entry->version = version;
00142         entry->next = NULL;
00143         entry->next_cache_neighbor = NULL;
00144         entry->is_nonvolatile = is_nonvolatile;
00145         
00146         return entry;
00147 }
00148 
00149 
00164 static
00165 void insert_write_set_entry_after(w_entry_t* new_entry, 
00166                                   w_entry_t* tail, 
00167                                   mtm_tx_t* transaction, 
00168                                   w_entry_t* cache_neighbor)
00169 {
00170         /* Append the entry to the list. */
00171         if (tail != NULL) {
00172                 new_entry->next = tail->next;
00173                 tail->next = new_entry;
00174         } else {
00175                 new_entry->next = NULL;
00176         }
00177         
00178         /* Attach the new entry to others in the same cache block/line. */
00179         if (cache_neighbor != NULL) {
00180                 new_entry->next_cache_neighbor = cache_neighbor->next_cache_neighbor;
00181                 cache_neighbor->next_cache_neighbor = new_entry;
00182         } else {
00183                 new_entry->next_cache_neighbor = NULL;
00184         }
00185         
00186         /* Update the total number of entries. */
00187         mode_data_t* modedata = (mode_data_t *) transaction->modedata[transaction->mode];
00188         modedata->w_set.nb_entries++;
00189 
00190         /* Write the new entry to the persistent TM log as well? */
00191         if (new_entry->is_nonvolatile) {
00192                 M_TMLOG_WRITE(transaction->pcm_storeset, modedata->ptmlog, (uintptr_t) new_entry->addr, new_entry->value, new_entry->mask);
00193         }
00194 }
00195 
00196 
00214 static inline
00215 w_entry_t *
00216 matching_write_set_entry(w_entry_t* const list_head,
00217                          volatile mtm_word_t* address,
00218                          w_entry_t** list_tail,
00219                          w_entry_t** last_cache_neighbor)
00220 {
00221         w_entry_t* this_entry = list_head;  // The entry examined in "this" iteration of the loop.
00222         while (true) {
00223                 if (last_cache_neighbor != NULL  &&  BLOCK_ADDR(address) == BLOCK_ADDR(this_entry->addr))
00224                         *last_cache_neighbor = this_entry;
00225                 
00226                 if (address == this_entry->addr) {
00227                         // Found a matching entry!
00228                         return this_entry;
00229                 }
00230                 else if (this_entry->next == NULL) {
00231                         // EOL: Could not find a matching write-set entry.
00232                         if (list_tail != NULL) {
00233                                 *list_tail = this_entry;
00234                         }
00235                         return NULL;
00236                 }
00237                 else {
00238                         this_entry = this_entry->next;
00239                 }
00240         }
00241 }
00242 
00243 
00270 static inline 
00271 w_entry_t *
00272 pwb_write_internal(mtm_tx_t *tx, 
00273                    volatile mtm_word_t *addr, 
00274                    mtm_word_t value,
00275                    mtm_word_t mask,
00276                            int enable_isolation)
00277 {
00278         assert(tx->mode == MTM_MODE_pwbnl || tx->mode == MTM_MODE_pwbetl);
00279         mode_data_t         *modedata = (mode_data_t *) tx->modedata[tx->mode];
00280         volatile mtm_word_t *lock;
00281         mtm_word_t          l;
00282         mtm_word_t          version;
00283         w_entry_t           *w;
00284         w_entry_t           *write_set_tail = NULL;
00285         int                 ret;
00286         int                 access_is_nonvolatile;
00287 
00288         MTM_DEBUG_PRINT("==> pwb_write(t=%p[%lu-%lu],a=%p,d=%llX-%llu,m=0x%llX)\n", tx,
00289                         (unsigned long)modedata->start,
00290                         (unsigned long)modedata->end, 
00291                         addr, 
00292                         (unsigned long long)value, 
00293                         (unsigned long long)value,
00294                         (unsigned long long)mask);
00295         /* Check status */
00296         //assert(tx->status == TX_ACTIVE);
00297         if (tx->status != TX_ACTIVE) {
00298                 assert(0);
00299         }
00300 
00301 #if 0
00302 /* ENABLES NULL BARRIERS */
00303         {
00304                         mtm_word_t prev_value;
00305                         prev_value = ATOMIC_LOAD(addr);
00306                         if (mask == 0) {
00307                                 return NULL;
00308                         }
00309                         if (mask != ~(mtm_word_t)0) {
00310                                 value = (prev_value & ~mask) | (value & mask);
00311                         }       
00312 
00313                         /* 
00314                          * Do eager version management for stack data because ICC does not
00315                          * like lazy version management for stack.
00316                          *
00317                          * But if there could not be user initiated or concurrency control 
00318                          * aborts then don't need to perform version management.
00319                          */
00320                         ATOMIC_STORE(addr, value);
00321                         return NULL;
00322         }
00323 #endif
00324 
00325         
00326         /* Check whether access is to volatile or non-volatile memory */
00327         if (((uintptr_t) addr >= PSEGMENT_RESERVED_REGION_START &&
00328              (uintptr_t) addr < (PSEGMENT_RESERVED_REGION_START + PSEGMENT_RESERVED_REGION_SIZE)))
00329         {
00330                 access_is_nonvolatile = 1;
00331         } else {
00332                 access_is_nonvolatile = 0;
00333 
00334                 /* Is it a stack access? */
00335                 if ((uintptr_t) addr <= tx->stack_base && 
00336                         (uintptr_t) addr > tx->stack_base - tx->stack_size)
00337                 {
00338                         mtm_word_t prev_value;
00339                         prev_value = ATOMIC_LOAD(addr);
00340                         if (mask == 0) {
00341                                 return NULL;
00342                         }
00343                         if (mask != ~(mtm_word_t)0) {
00344                                 value = (prev_value & ~mask) | (value & mask);
00345                         }       
00346 
00347                         /* 
00348                          * Do eager version management for stack data because ICC does not
00349                          * like lazy version management for stack.
00350                          *
00351                          * But if there could not be user initiated or concurrency control 
00352                          * aborts then don't need to perform version management.
00353                          */
00354                         if (enable_isolation) {
00355                                 mtm_local_LB(tx, (void *) addr, sizeof(mtm_word_t));
00356                         } else {
00357 #ifdef ALLOW_ABORTS
00358                                 mtm_local_LB(tx, (void *) addr, sizeof(mtm_word_t));
00359 #endif
00360                         }
00361                         ATOMIC_STORE(addr, value);
00362                         return NULL;
00363                 }
00364 
00365                 /* 
00366                  * Normal volatile access
00367                  * 
00368                  * If there could not be user initiated or concurrency control aborts. 
00369                  * then don't need to perform version management. However this path
00370                  * cannot be merged into the stack non-version management path because
00371                  * we must write only the bytes covered by the mask. We could use the
00372                  * the same function for writing the stack but writing using a mask
00373                  * is a slower operation that's why we optimized the stack path.
00374                  */
00375                 if (!enable_isolation) {
00376 #if !defined(ALLOW_ABORTS)
00377                         PCM_WB_STORE_MASKED(tx->pcm_storeset, addr, value, mask);
00378                         return NULL;
00379 #endif
00380                 }
00381         }
00382 
00383         
00384 #ifdef _M_STATS_BUILD
00385         m_stats_statset_increment(mtm_statsmgr, tx->statset, XACT, writes, 1);
00386         if (access_is_nonvolatile) {
00387                 m_stats_statset_increment(mtm_statsmgr, tx->statset, XACT, nvwrites, 1);
00388         } else {
00389                 m_stats_statset_increment(mtm_statsmgr, tx->statset, XACT, vwrites, 1);
00390         }
00391 #endif  
00392 
00393         /* Get reference to lock */
00394         if (enable_isolation) {
00395                 lock = GET_LOCK(addr);
00396         } else {
00397                 /* Since isolation is off, go through the private pseudo-lock hash table 
00398                  * instead of the global one. Since it's private, there is no notion of locking
00399                  * so it might be confusing why we assign the hash table entry to a 
00400                  * variable lock. The reason is that besides locking, the logic behind
00401                  * the private table is the same as the global table's logic. So this
00402                  * helps us keep most of the path the same and avoid code changes.
00403                  */
00404                 lock = PRIVATE_GET_LOCK(tx, addr);
00405         }
00406 
00407         /* Try to acquire lock */
00408 restart:
00409         l = ATOMIC_LOAD_ACQ(lock);
00410 restart_no_load:
00411         if (LOCK_GET_OWNED(l)) {
00412                 /* Locked */
00413                 /* Do we own the lock? */
00414                 w_entry_t *write_set_head;
00415                 write_set_head = (w_entry_t *)LOCK_GET_ADDR(l);
00416                 
00417                 /* Simply check if address falls inside our write set (avoids non-faulting load) */
00418                 if (modedata->w_set.entries <= write_set_head &&
00419                     write_set_head < modedata->w_set.entries + modedata->w_set.nb_entries) 
00420                 {
00421                         /* The written address already hashes into our write set. */
00422                         /* Did we previously write the exact same address? */
00423                         w_entry_t* write_set_tail = NULL;
00424                         w_entry_t* last_entry_in_same_cache_block = NULL;
00425                         w_entry_t* matching_entry = matching_write_set_entry(write_set_head, addr, &write_set_tail, &last_entry_in_same_cache_block);
00426                         if (matching_entry != NULL) {
00427                                 if (matching_entry->mask != 0) {
00428                                         mask_new_value(matching_entry, addr, value, mask);
00429                                         /* Write out the entry to the persistent TM log? */
00430                                         if (access_is_nonvolatile) {
00431                                                 M_TMLOG_WRITE(tx->pcm_storeset, modedata->ptmlog, (uintptr_t) matching_entry->addr, matching_entry->value, matching_entry->mask);
00432                                         }       
00433                                 }
00434                                 return matching_entry;
00435                         } else {
00436                                 if (modedata->w_set.nb_entries == modedata->w_set.size) {
00437                                         /* Extend write set (invalidate pointers to write set entries => abort and reallocate) */
00438                                         modedata->w_set.size *= 2;
00439                                         modedata->w_set.reallocate = 1;
00440 #ifdef _M_STATS_BUILD
00441                                         m_stats_statset_increment(mtm_statsmgr, tx->statset, XACT, aborts, 1);
00442 #endif                                  
00443                                         #ifdef INTERNAL_STATS
00444                                                 tx->aborts_reallocate++;
00445                                         #endif
00446                                         
00447                                         mtm_pwb_restart_transaction (tx, RESTART_REALLOCATE);  // Does not return!
00448                                 } else {
00449 #ifdef _M_STATS_BUILD
00450                                         m_stats_statset_increment(mtm_statsmgr, tx->statset, XACT, writes_distinct, 1);
00451                                         if (access_is_nonvolatile) {
00452                                                 m_stats_statset_increment(mtm_statsmgr, tx->statset, XACT, nvwrites_distinct, 1);
00453                                         } else {
00454                                                 m_stats_statset_increment(mtm_statsmgr, tx->statset, XACT, vwrites_distinct, 1);
00455                                         }
00456 #endif                                  
00457                                         // Build a new write set entry
00458                                         w = &modedata->w_set.entries[modedata->w_set.nb_entries];
00459                                         version = write_set_tail->version;  // Get version from previous write set entry (all
00460                                                                             // entries in linked list have same version)
00461                                         w_entry_t* initialized_entry = initialize_write_set_entry(w, addr, value, mask, version, lock, access_is_nonvolatile);
00462 
00463         
00464                                         // Add entry to the write set
00465                                         insert_write_set_entry_after(initialized_entry, write_set_tail, tx, last_entry_in_same_cache_block);                                    
00466                                         return initialized_entry;
00467                                 }
00468                         }
00469                 }
00470                 /* If isolation is off and the pseudo-lock was set then we should have already 
00471                  * found a written-back value entry and never reach here. */
00472                 assert(enable_isolation);
00473 
00474                 /* Conflict: CM kicks in */
00475                 ret = cm_conflict(tx, lock, &l);
00476                 switch (ret) {
00477                         case CM_RESTART:
00478                                 goto restart;
00479                         case CM_RESTART_NO_LOAD:
00480                                 goto restart_no_load;
00481                         case CM_RESTART_LOCKED:
00482                                 /* Abort */
00483 #ifdef _M_STATS_BUILD
00484                                 m_stats_statset_increment(mtm_statsmgr, tx->statset, XACT, aborts, 1);
00485 #endif                                  
00486 #ifdef INTERNAL_STATS
00487                                 tx->aborts_locked_write++;
00488 #endif /* INTERNAL_STATS */
00489                                 mtm_pwb_restart_transaction(tx, RESTART_LOCKED_WRITE);
00490                 }
00491                 /* Should never reach here. */
00492                 assert(0);
00493         } else {
00494                 /* This region has not been locked by this thread. */
00495                 if (enable_isolation) {
00496                         /* Handle write after reads (before CAS) */
00497                         version = LOCK_GET_TIMESTAMP(l);
00498 
00499                         if (version > modedata->end) {
00500                                 /* We might have read an older version previously */
00501                                 if (!tx->can_extend || mtm_has_read(tx, modedata, lock) != NULL) {
00502                                         /* Read version must be older (otherwise, tx->end >= version) */
00503                                         /* Not much we can do: abort */
00504                                         /* Abort caused by invisible reads */
00505                                         cm_visible_read(tx);
00506 #ifdef _M_STATS_BUILD
00507                                         m_stats_statset_increment(mtm_statsmgr, tx->statset, XACT, aborts, 1);
00508 #endif                                  
00509 #ifdef INTERNAL_STATS
00510                                         tx->aborts_validate_write++;
00511 #endif /* INTERNAL_STATS */
00512                                         mtm_pwb_restart_transaction(tx, RESTART_VALIDATE_WRITE);
00513                                 }
00514                         }
00515                 }
00516                 
00517                 /* Acquire lock (ETL) */
00518                 if (modedata->w_set.nb_entries == modedata->w_set.size) {
00519                         /* Extend write set (invalidate pointers to write set entries => abort and reallocate) */
00520                         modedata->w_set.size *= 2;
00521                         modedata->w_set.reallocate = 1;
00522 #ifdef _M_STATS_BUILD
00523                         m_stats_statset_increment(mtm_statsmgr, tx->statset, XACT, aborts, 1);
00524 #endif                                  
00525 # ifdef INTERNAL_STATS
00526                         tx->aborts_reallocate++;
00527 # endif /* INTERNAL_STATS */
00528                         mtm_pwb_restart_transaction (tx, RESTART_REALLOCATE);
00529                 }
00530             w = &modedata->w_set.entries[modedata->w_set.nb_entries];
00531                 if (enable_isolation) {
00532 # ifdef READ_LOCKED_DATA
00533                         w->version = version;
00534 # endif /* READ_LOCKED_DATA */
00535 # if CM == CM_PRIORITY
00536                         if (ATOMIC_CAS_FULL(lock, l, LOCK_SET_ADDR((mtm_word_t)w, tx->priority)) == 0) {
00537                                 goto restart;
00538                         }
00539 # else /* CM != CM_PRIORITY */
00540                         if (ATOMIC_CAS_FULL(lock, l, LOCK_SET_ADDR((mtm_word_t)w)) == 0) {
00541                                 goto restart;
00542                         }
00543 # endif /* CM != CM_PRIORITY */
00544                 } else {
00545                         /* Don't need a CAS; just use a regular STORE. */
00546                         /* We also set the lock bit to ensure that the next write will 
00547                          * see the write entry as valid. */
00548                         *lock = LOCK_SET_ADDR((mtm_word_t)w);
00549                 }
00550                 
00551                 w_entry_t* initialized_entry =  initialize_write_set_entry(w, addr, value, mask, version, lock, access_is_nonvolatile);
00552                 insert_write_set_entry_after(initialized_entry, write_set_tail, tx, NULL);                                      
00553 #ifdef _M_STATS_BUILD
00554                 m_stats_statset_increment(mtm_statsmgr, tx->statset, XACT, writes_distinct, 1);
00555                 if (access_is_nonvolatile) {
00556                         m_stats_statset_increment(mtm_statsmgr, tx->statset, XACT, nvwrites_distinct, 1);
00557                 } else {
00558                         m_stats_statset_increment(mtm_statsmgr, tx->statset, XACT, vwrites_distinct, 1);
00559                 }
00560 #endif          
00561                 return w;
00562         }
00563 }
00564 
00565 
00566 static inline
00567 mtm_word_t 
00568 pwb_load_internal(mtm_tx_t *tx, volatile mtm_word_t *addr, int enable_isolation)
00569 {
00570         assert(tx->mode == MTM_MODE_pwbnl || tx->mode == MTM_MODE_pwbetl);
00571         mode_data_t         *modedata = (mode_data_t *) tx->modedata[tx->mode];
00572         volatile mtm_word_t *lock;
00573         mtm_word_t          l;
00574         mtm_word_t          l2;
00575         mtm_word_t          value;
00576         mtm_word_t          version;
00577         r_entry_t           *r;
00578         w_entry_t           *w;
00579         int                 ret;
00580 
00581         MTM_DEBUG_PRINT("==> mtm_pwb_load(t=%p[%lu-%lu],a=%p)\n", tx, 
00582                         (unsigned long)modedata->start,
00583                         (unsigned long)modedata->end, 
00584                         addr);
00585 
00586         /* Check status */
00587         if (tx->status != TX_ACTIVE) {
00588                 printf("%p, tx->status = %d\n", tx, tx->status);
00589         }
00590         assert(tx->status == TX_ACTIVE);
00591 
00592 #if 0
00593 /* ENABLES NULL BARRIERS */
00594 
00595                         value = ATOMIC_LOAD(addr);
00596                         return value;
00597 #endif
00598 
00599         /* Check whether access is to volatile or non-volatile memory */
00600         if (((uintptr_t) addr >= PSEGMENT_RESERVED_REGION_START &&
00601              (uintptr_t) addr < (PSEGMENT_RESERVED_REGION_START + PSEGMENT_RESERVED_REGION_SIZE)))
00602         {
00603                 /* Access is non-volatile */
00604                 /* Fall through */
00605         } else {
00606                 /* Is it a stack access? */
00607                 if ((uintptr_t) addr <= tx->stack_base && 
00608                         (uintptr_t) addr > tx->stack_base - tx->stack_size)
00609                 {
00610                         value = ATOMIC_LOAD(addr);
00611                         return value;
00612                 }
00613 
00614                 /* 
00615                  * Normal volatile access
00616                  *
00617                  * If there could not be user initiated or concurrency control aborts. 
00618                  * then we don't perform version management for volatile data, so we 
00619                  * just read the value directly from memory. 
00620                  */
00621                 if (!enable_isolation) {
00622 #if !defined(ALLOW_ABORTS)
00623                         value = ATOMIC_LOAD(addr);
00624                         return value;
00625 #endif
00626                 }
00627         }
00628 
00629 
00630         if (enable_isolation) {
00631                 /* Check with contention manager whether to upgrade to write lock. */
00632                 if (cm_upgrade_lock(tx)) {
00633                         w = pwb_write_internal(tx, addr, 0, 0, enable_isolation);
00634                         /* Make sure we did not abort */
00635                         if(tx->status != TX_ACTIVE) {
00636                                 return 0;
00637                         }
00638                         assert(w != NULL);
00639                         /* We now own the lock */
00640                         return w->mask == 0 ? ATOMIC_LOAD(addr) : w->value;
00641                 }
00642         }
00643 
00644         /* Get reference to lock */
00645         if (enable_isolation) {
00646                 lock = GET_LOCK(addr);
00647         } else {
00648                 /* See comments under pwb_write. */
00649                 lock = PRIVATE_GET_LOCK(tx, addr);
00650         }
00651 
00652 
00653         /* Note: we could check for duplicate reads and get value from read set */
00654 
00655         /* Read lock, value, lock */
00656 restart:
00657         l = ATOMIC_LOAD_ACQ(lock);
00658 restart_no_load:
00659         if (LOCK_GET_OWNED(l)) {
00660             /* Locked */
00661         /* Do we own the lock? */
00662                 w = (w_entry_t *)LOCK_GET_ADDR(l);
00663                 /* Simply check if address falls inside our write set (avoids non-faulting load) */
00664                 if (modedata->w_set.entries <= w && 
00665                     w < modedata->w_set.entries + modedata->w_set.nb_entries)
00666                 {
00667                         /* Yes: did we previously write the same address? */
00668                         while (1) {
00669                                 if (addr == w->addr) {
00670                                         /* Yes: get value from write set (or from memory if mask was empty) */
00671                                         value = (w->mask == 0 ? ATOMIC_LOAD(addr) : w->value);
00672                                         MTM_DEBUG_PRINT("==> mtm_load[OWN LOCK|READ FROM WSET]");
00673                                         break;
00674                                 }
00675                                 if (w->next == NULL) {
00676                                         /* No: get value from memory */
00677                                         value = ATOMIC_LOAD(addr);
00678                                         MTM_DEBUG_PRINT("==> mtm_load[OWN LOCK|READ FROM MEMORY]");
00679                                         break;
00680                                 }
00681                                 w = w->next;
00682                         }
00683                         /* No need to add to read set (will remain valid) */
00684                         MTM_DEBUG_PRINT("(t=%p[%lu-%lu],a=%p,l=%p,*l=%lu,d=%p-%lu)\n",
00685                                         tx, (unsigned long)modedata->start, 
00686                                         (unsigned long)modedata->end, 
00687                                         addr, 
00688                                         lock, 
00689                                         (unsigned long)l,
00690                                         (void *)value,
00691                                         (unsigned long)value);
00692                         return value;
00693                 }
00694                 /* If isolation is off and the pseudo-lock was set then we should have already 
00695                  * found a written-back value entry and never reach here. */
00696                 assert(enable_isolation);
00697 
00698                 /* Conflict: CM kicks in */
00699                 /* TODO: we could check for duplicate reads and get value from read set (should be rare) */
00700                 ret = cm_conflict(tx, lock, &l);
00701                 switch (ret) {
00702                         case CM_RESTART:
00703                                 goto restart;
00704                         case CM_RESTART_NO_LOAD:
00705                                 goto restart_no_load;
00706                         case CM_RESTART_LOCKED:
00707                                 /* Abort */
00708 #ifdef _M_STATS_BUILD
00709                                 m_stats_statset_increment(mtm_statsmgr, tx->statset, XACT, aborts, 1);
00710 #endif                                  
00711 #ifdef INTERNAL_STATS
00712                                 tx->aborts_locked_write++;
00713 #endif /* INTERNAL_STATS */
00714                                 mtm_pwb_restart_transaction(tx, RESTART_LOCKED_READ);
00715                 }
00716                 /* Should never reach here. */
00717                 assert(0);
00718         } else {
00719                 /* Not locked */
00720                 value = ATOMIC_LOAD_ACQ(addr);
00721                 if (enable_isolation) {
00722                         l2 = ATOMIC_LOAD_ACQ(lock);
00723                         if (l != l2) {
00724                                 l = l2;
00725                                 goto restart_no_load;
00726                         }
00727                         /* Check timestamp */
00728                         version = LOCK_GET_TIMESTAMP(l);
00729                         /* Valid version? */
00730                         if (version > modedata->end) {
00731                                 /* No: try to extend first (except for read-only transactions: no read set) */
00732                                 if (!tx->can_extend || !pwb_extend(tx, modedata)) {
00733                                         /* Not much we can do: abort */
00734                                         /* Abort caused by invisible reads */
00735                                         cm_visible_read(tx);
00736 #ifdef _M_STATS_BUILD
00737                                         m_stats_statset_increment(mtm_statsmgr, tx->statset, XACT, aborts, 1);
00738 #endif                                  
00739 #ifdef INTERNAL_STATS
00740                                         tx->aborts_validate_read++;
00741 #endif /* INTERNAL_STATS */
00742                                         mtm_pwb_restart_transaction (tx, RESTART_VALIDATE_READ);
00743                                 }
00744                                 /* Verify that version has not been overwritten (read value has not
00745                                  * yet been added to read set and may have not been checked during
00746                                  * extend) */
00747                                 l = ATOMIC_LOAD_ACQ(lock);
00748                                 if (l != l2) {
00749                                         l = l2;
00750                                         goto restart_no_load;
00751                                 }
00752                                 /* Worked: we now have a good version (version <= tx->end) */
00753                         }
00754                 }
00755         }
00756 
00757         /* We have a good version: add to read set (update transactions) and return value */
00758         if (enable_isolation) {
00759                 /* Add address and version to read set */
00760                 if (modedata->r_set.nb_entries == modedata->r_set.size) {
00761                         mtm_allocate_rs_entries(tx, modedata, 1);
00762                 }
00763                 r = &modedata->r_set.entries[modedata->r_set.nb_entries++];
00764                 r->version = version;
00765                 r->lock = lock;
00766         }
00767 
00768         MTM_DEBUG_PRINT("==> mtm_pwb_load(t=%p[%lu-%lu],a=%p,l=%p,*l=%lu,d=%p-%lu,v=%lu)\n",
00769                         tx, (unsigned long)modedata->start, 
00770                         (unsigned long)modedata->end, 
00771                         addr,
00772                         lock,
00773                         (unsigned long)l,
00774                         (void *)value,
00775                         (unsigned long)value,
00776                         (unsigned long)version);
00777 
00778         return value;
00779 }
00780 
00781 
00782 #endif /* _PWB_COMMON_BARRIER_BITS_JKI671_H */

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