00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
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
00063
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
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
00084 assert(tx->status == TX_ACTIVE);
00085
00086
00087 if (--tx->nesting > 0) {
00088 return true;
00089 }
00090
00091 if (modedata->w_set.nb_entries > 0) {
00092
00093
00094
00095 t = FETCH_INC_CLOCK + 1;
00096 if (t >= VERSION_MAX) {
00097 #ifdef ROLLOVER_CLOCK
00098
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
00105 return false;
00106 #else
00107 fprintf(stderr, "Exceeded maximum version number: 0x%lx\n", (unsigned long)t);
00108 exit(1);
00109 #endif
00110 }
00111
00112
00113 if (enable_isolation) {
00114 if (modedata->start != t - 1 && !mtm_validate(tx, modedata)) {
00115
00116
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
00124 return false;
00125 }
00126 }
00127
00128 # ifdef READ_LOCKED_DATA
00129
00130 id = tx->id;
00131 assert(id % 2 == 0);
00132 ATOMIC_STORE_REL(&tx->id, id + 1);
00133 # endif
00134
00135
00136 M_TMLOG_COMMIT(tx->pcm_storeset, modedata->ptmlog, t);
00137
00138
00139 PCM_WB_FENCE(tx->pcm_storeset);
00140
00141
00142
00143
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
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
00156 if (w->next_cache_neighbor == NULL) {
00157
00158
00159
00160
00161
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
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
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
00187
00188 # ifdef READ_LOCKED_DATA
00189
00190 ATOMIC_STORE_REL(&tx->id, id + 2);
00191 # endif
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
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
00222
00223 MTM_DEBUG_PRINT("==> pwb_rollback(%p[%lu-%lu])\n", tx,
00224 (unsigned long)modedata->start,
00225 (unsigned long)modedata->end);
00226
00227
00228 assert(tx->status == TX_ACTIVE);
00229
00230
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
00237 i = modedata->w_set.nb_entries;
00238 if (i > 0) {
00239 # ifdef READ_LOCKED_DATA
00240
00241 id = tx->id;
00242 assert(id % 2 == 0);
00243 ATOMIC_STORE_REL(&tx->id, id + 1);
00244 # endif
00245 w = modedata->w_set.entries;
00246 for (; i > 0; i--, w++) {
00247 if (w->next == NULL) {
00248
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
00260 ATOMIC_MB_WRITE;
00261 # ifdef READ_LOCKED_DATA
00262
00263 ATOMIC_STORE_REL(&tx->id, id + 2);
00264 # endif
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
00274
00275
00276 tx->status = TX_ABORTED;
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
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
00313
00314
00315
00316
00317
00318
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
00332 modedata->start = modedata->end = GET_CLOCK;
00333
00334 tx->can_extend = 1;
00335 #ifdef ROLLOVER_CLOCK
00336 if (modedata->start >= VERSION_MAX) {
00337
00338 mtm_overflow(tx);
00339 goto start;
00340 }
00341 #endif
00342
00343
00344
00345
00346
00347
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
00360
00361 tx->nesting = 1;
00362 tx->status = TX_ACTIVE;
00363
00364
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
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
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
00399 return (prop & pr_uninstrumentedCode
00400 ? a_runUninstrumentedCode : a_runInstrumentedCode);
00401 }
00402
00403 if (enable_isolation) {
00404
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
00435 tx->status = TX_COMMITTED;
00436 return true;
00437 }
00438 return false;
00439 }