TransactionalScope::TransactionalScope(spinlock_t &fallback_mutex, bool writeAccess) : // initializaer list spinlock(fallback_mutex) { unsigned int xact_status; threadstate_t &ts = tstate; ts.txCount++; // we are already executing transactionally, continue. if (_xtest()) return; do { xact_status = _xbegin(); if (xact_status == _XBEGIN_STARTED) { if ( *(reinterpret_cast<int*>(&fallback_mutex)) == 0 ) { return; } else { _xabort(0xFF); } } else { /** We have aborted. */ ++ts.totalAborts; ++ts.successiveAborts; // if we xaborted because the lock was held, acquire the lock if ((xact_status & _XABORT_EXPLICIT) && _XABORT_CODE(xact_status) == 0xFF) { ts.maxAborts = 1; ts.maxTxLen = 1; break; } //if xabort:retry or xabort:conflict is set retry if (xact_status & (_XABORT_RETRY | _XABORT_CONFLICT)) { ts.maxTxLen = 1; } // // if we used too much buffer space inside the transaction half the max transaction length if ((xact_status & _XABORT_CAPACITY)) { ts.maxTxLen = 1; } _mm_pause(); } } while (ts.successiveAborts < ts.maxAborts); ts.fallbackTaken++; // Fallback to lock if (writeAccess) { spinlock.lock(); } else { spinlock.lock_read(); } }
int main() { unsigned status; if ((status = _xbegin()) == _XBEGIN_STARTED) { _xend(); } else { _xabort(_XABORT_CONFLICT); } }
int __lll_trylock_elision (int *futex, short *adapt_count) { /* Implement POSIX semantics by forbiding nesting trylock. Sorry. After the abort the code is re-executed non transactional and if the lock was already locked return an error. */ _xabort (_ABORT_NESTED_TRYLOCK); /* Only try a transaction if it's worth it. */ if (*adapt_count <= 0) { unsigned status; if ((status = _xbegin()) == _XBEGIN_STARTED) { if (*futex == 0) return 0; /* Lock was busy. Fall back to normal locking. Could also _xend here but xabort with 0xff code is more visible in the profiler. */ _xabort (_ABORT_LOCK_BUSY); } if (!(status & _XABORT_RETRY)) { /* Internal abort. No chance for retry. For future locks don't try speculation for some time. */ if (*adapt_count != aconf.skip_trylock_internal_abort) *adapt_count = aconf.skip_trylock_internal_abort; } /* Could do some retries here. */ } else { /* Lost updates are possible, but harmless. */ (*adapt_count)--; } return lll_trylock (*futex); }
JNIEXPORT void JNICALL Java_javartm_Transaction_abort__(JNIEnv *env, jclass cls) { if (_xtest()) { _xabort(0); } else { // Tried to abort without active transaction // Throw an exception so that user code after the abort doesn't continue running jclass excClass = (*env)->FindClass(env, "java/lang/IllegalStateException"); if (!excClass) return; (*env)->ThrowNew(env, excClass, "No active transaction to be aborted"); } }
int main(void) { int status; if ((status = _xbegin()) == _XBEGIN_STARTED) { if (_xtest()) _xabort(1); _xend(); } else printf("aborted %x, %d", status, _XABORT_CODE(status)); return 0; }
/* * [lyj] Disable the interpretation of "deleted" field. */ void fraser_insert(sl_intset_t *set, uint32_t v, bool lin) { sl_node_t *NEW, *new_next, *pred, *succ, *succs[LEVELMAX], *preds[LEVELMAX]; uint32_t i; uint32_t status; // uint32_t attempts = 0; NEW = sl_new_simple_node(v, get_rand_level(), lin); retry: fraser_search(set, v, preds, succs); for (i = 0; i < NEW->toplevel; i++) NEW->nexts[i] = succs[i]; /* Node is visible once inserted at lowest level */ if (!ATOMIC_CAS_MB(&preds[0]->nexts[0], succs[0], NEW)) goto retry; //retry_HTM: status = _xbegin(); if(status == _XBEGIN_STARTED) { for (i = 1; i < NEW->toplevel; i++) { if(preds[i]->nexts[i] == succs[i]) preds[i]->nexts[i] = NEW; else _xabort(66); } _xend(); return; }/*else { if ((status & _XABORT_EXPLICIT) && _XABORT_CODE(status) == 66) { } else if (++attempts < MAX_ATTEMPT_NUM) { goto retry_HTM; } }*/ for (i = 1; i < NEW->toplevel; i++) { while (1) { pred = preds[i]; succ = succs[i]; /* Update the forward pointer if it is stale */ new_next = NEW->nexts[i]; if ((new_next != succ) && (!ATOMIC_CAS_MB(&NEW->nexts[i], unset_mark((uint32_t)new_next), succ))) break; /* Give up if pointer is marked */ /* We retry the search if the CAS fails */ if (ATOMIC_CAS_MB(&pred->nexts[i], succ, NEW)) break; fraser_search(set, v, preds, succs); } } }
int BST::addRTM(Node *node) { int state = TRANSACTION; int attempt = 1; int nabort = 0; int res; while (1) { UINT status = _XBEGIN_STARTED; if (state == TRANSACTION) { status = _xbegin(); } else { tatas_lock.acquireOptimistic(); } if (status == _XBEGIN_STARTED) { if (state == TRANSACTION && tatas_lock.getValue()) { _xabort(0xA0); nabort++; } res = add(node); if (state == TRANSACTION) { _xend(); } else { tatas_lock.release(); } break; } else { if (tatas_lock.getValue()) { do { _mm_pause(); } while (tatas_lock.getValue()); } else { volatile UINT64 wait = attempt; while (wait--); } if (++attempt >= MAXATTEMPT) { state = LOCK; } } } return res; }
void spin_lock_rtm(int *lock) { int i; unsigned status; unsigned retry = RETRY_OTHER; for (i = 0; i < retry; i++) { if ((status = _xbegin()) == _XBEGIN_STARTED) { if (lock_is_free(lock)) return; _xabort(0xff); } trace_abort(status); if ((status & _XABORT_EXPLICIT) && _XABORT_CODE(status) == 0xff) { while (!lock_is_free(lock)) pause(); } else if (!(status & _XABORT_RETRY) && !(status & _XABORT_CAPACITY)) break; if (status & _XABORT_CONFLICT) { retry = RETRY_CON; while (!lock_is_free(lock)) pause(); /* Could do various kinds of backoff here. */ } else if (status & _XABORT_CAPACITY) { retry = RETRY_CAP; } else { retry = RETRY_OTHER; } } /* Could do adaptation here */ while (__sync_sub_and_fetch(lock, 1) < 0) { do pause(); while (!lock_is_free(lock)); /* Could do respeculation here */ } }
JNIEXPORT void JNICALL Java_javartm_Transaction_abort__J(JNIEnv *env, jclass cls, jlong reason) { // I don't know why (register clobbering? bug?), but if reason is 32bits, then the returned // result after _xabort is always 0. Having reason as a long seems to work, don't know why. if (_xtest()) { // Supposedly the argument to _xabort must be encoded into the instruction. // To allow the user to specify his reason we must have an xabort for each value. // Welcome to low-level programming :) switch (reason) { case 0: _xabort(0); case 1: _xabort(1); case 2: _xabort(2); case 3: _xabort(3); case 4: _xabort(4); case 5: _xabort(5); case 6: _xabort(6); case 7: _xabort(7); case 8: _xabort(8); case 9: _xabort(9); case 10: _xabort(10); case 11: _xabort(11); case 12: _xabort(12); case 13: _xabort(13); case 14: _xabort(14); case 15: _xabort(15); case 16: _xabort(16); case 17: _xabort(17); case 18: _xabort(18); case 19: _xabort(19); case 20: _xabort(20); case 21: _xabort(21); case 22: _xabort(22); case 23: _xabort(23); case 24: _xabort(24); case 25: _xabort(25); case 26: _xabort(26); case 27: _xabort(27); case 28: _xabort(28); case 29: _xabort(29); case 30: _xabort(30); case 31: _xabort(31); case 32: _xabort(32); case 33: _xabort(33); case 34: _xabort(34); case 35: _xabort(35); case 36: _xabort(36); case 37: _xabort(37); case 38: _xabort(38); case 39: _xabort(39); case 40: _xabort(40); case 41: _xabort(41); case 42: _xabort(42); case 43: _xabort(43); case 44: _xabort(44); case 45: _xabort(45); case 46: _xabort(46); case 47: _xabort(47); case 48: _xabort(48); case 49: _xabort(49); case 50: _xabort(50); case 51: _xabort(51); case 52: _xabort(52); case 53: _xabort(53); case 54: _xabort(54); case 55: _xabort(55); case 56: _xabort(56); case 57: _xabort(57); case 58: _xabort(58); case 59: _xabort(59); case 60: _xabort(60); case 61: _xabort(61); case 62: _xabort(62); case 63: _xabort(63); case 64: _xabort(64); case 65: _xabort(65); case 66: _xabort(66); case 67: _xabort(67); case 68: _xabort(68); case 69: _xabort(69); case 70: _xabort(70); case 71: _xabort(71); case 72: _xabort(72); case 73: _xabort(73); case 74: _xabort(74); case 75: _xabort(75); case 76: _xabort(76); case 77: _xabort(77); case 78: _xabort(78); case 79: _xabort(79); case 80: _xabort(80); case 81: _xabort(81); case 82: _xabort(82); case 83: _xabort(83); case 84: _xabort(84); case 85: _xabort(85); case 86: _xabort(86); case 87: _xabort(87); case 88: _xabort(88); case 89: _xabort(89); case 90: _xabort(90); case 91: _xabort(91); case 92: _xabort(92); case 93: _xabort(93); case 94: _xabort(94); case 95: _xabort(95); case 96: _xabort(96); case 97: _xabort(97); case 98: _xabort(98); case 99: _xabort(99); case 100: _xabort(100); case 101: _xabort(101); case 102: _xabort(102); case 103: _xabort(103); case 104: _xabort(104); case 105: _xabort(105); case 106: _xabort(106); case 107: _xabort(107); case 108: _xabort(108); case 109: _xabort(109); case 110: _xabort(110); case 111: _xabort(111); case 112: _xabort(112); case 113: _xabort(113); case 114: _xabort(114); case 115: _xabort(115); case 116: _xabort(116); case 117: _xabort(117); case 118: _xabort(118); case 119: _xabort(119); case 120: _xabort(120); case 121: _xabort(121); case 122: _xabort(122); case 123: _xabort(123); case 124: _xabort(124); case 125: _xabort(125); case 126: _xabort(126); case 127: _xabort(127); case 128: _xabort(128); case 129: _xabort(129); case 130: _xabort(130); case 131: _xabort(131); case 132: _xabort(132); case 133: _xabort(133); case 134: _xabort(134); case 135: _xabort(135); case 136: _xabort(136); case 137: _xabort(137); case 138: _xabort(138); case 139: _xabort(139); case 140: _xabort(140); case 141: _xabort(141); case 142: _xabort(142); case 143: _xabort(143); case 144: _xabort(144); case 145: _xabort(145); case 146: _xabort(146); case 147: _xabort(147); case 148: _xabort(148); case 149: _xabort(149); case 150: _xabort(150); case 151: _xabort(151); case 152: _xabort(152); case 153: _xabort(153); case 154: _xabort(154); case 155: _xabort(155); case 156: _xabort(156); case 157: _xabort(157); case 158: _xabort(158); case 159: _xabort(159); case 160: _xabort(160); case 161: _xabort(161); case 162: _xabort(162); case 163: _xabort(163); case 164: _xabort(164); case 165: _xabort(165); case 166: _xabort(166); case 167: _xabort(167); case 168: _xabort(168); case 169: _xabort(169); case 170: _xabort(170); case 171: _xabort(171); case 172: _xabort(172); case 173: _xabort(173); case 174: _xabort(174); case 175: _xabort(175); case 176: _xabort(176); case 177: _xabort(177); case 178: _xabort(178); case 179: _xabort(179); case 180: _xabort(180); case 181: _xabort(181); case 182: _xabort(182); case 183: _xabort(183); case 184: _xabort(184); case 185: _xabort(185); case 186: _xabort(186); case 187: _xabort(187); case 188: _xabort(188); case 189: _xabort(189); case 190: _xabort(190); case 191: _xabort(191); case 192: _xabort(192); case 193: _xabort(193); case 194: _xabort(194); case 195: _xabort(195); case 196: _xabort(196); case 197: _xabort(197); case 198: _xabort(198); case 199: _xabort(199); case 200: _xabort(200); case 201: _xabort(201); case 202: _xabort(202); case 203: _xabort(203); case 204: _xabort(204); case 205: _xabort(205); case 206: _xabort(206); case 207: _xabort(207); case 208: _xabort(208); case 209: _xabort(209); case 210: _xabort(210); case 211: _xabort(211); case 212: _xabort(212); case 213: _xabort(213); case 214: _xabort(214); case 215: _xabort(215); case 216: _xabort(216); case 217: _xabort(217); case 218: _xabort(218); case 219: _xabort(219); case 220: _xabort(220); case 221: _xabort(221); case 222: _xabort(222); case 223: _xabort(223); case 224: _xabort(224); case 225: _xabort(225); case 226: _xabort(226); case 227: _xabort(227); case 228: _xabort(228); case 229: _xabort(229); case 230: _xabort(230); case 231: _xabort(231); case 232: _xabort(232); case 233: _xabort(233); case 234: _xabort(234); case 235: _xabort(235); case 236: _xabort(236); case 237: _xabort(237); case 238: _xabort(238); case 239: _xabort(239); case 240: _xabort(240); case 241: _xabort(241); case 242: _xabort(242); case 243: _xabort(243); case 244: _xabort(244); case 245: _xabort(245); case 246: _xabort(246); case 247: _xabort(247); case 248: _xabort(248); case 249: _xabort(249); case 250: _xabort(250); case 251: _xabort(251); case 252: _xabort(252); case 253: _xabort(253); case 254: _xabort(254); case 255: _xabort(255); default: _xabort(0); } } else { // Tried to abort without active transaction // Throw an exception so that user code after the abort doesn't continue running jclass excClass = (*env)->FindClass(env, "java/lang/IllegalStateException"); if (!excClass) return; (*env)->ThrowNew(env, excClass, "No active transaction to be aborted"); } }
void test_xabort(void) { // CHECK: void @llvm.x86.xabort(i8 2) _xabort(2); }
uint32_t mem_read(tid_t tid, uint32_t *addr) { version_t version; uint32_t val; objid_t objid = calc_objid(addr); struct objinfo *info = &g_objinfo[objid]; if ((g_sim_bbcnt % RTM_BATCH_N) == 0) { // Simulate basic block begin. assert(!_xtest()); int ret = _xbegin(); (void)ret; #ifdef RTM_STAT if (ret != _XBEGIN_STARTED) { fprintf(stderr, "T%d R%ld aborted %x, %d\n", g_tid, memop, ret, _XABORT_CODE(ret)); g_rtm_abort_cnt++; } #endif } int in_rtm = _xtest(); if (in_rtm) { version = info->version; // XXX It's possible the transaction commits while another write is in // fallback handler and has increased version by 1, thus we would get an // odd version here. Also refer to read tx in rtmseq. if (version & 1) { _xabort(1); } val = *addr; } else { do { version = info->version; while (unlikely(version & 1)) { cpu_relax(); version = info->version; } barrier(); val = *addr; barrier(); } while (version != info->version); } if (in_rtm && (g_sim_bbcnt % RTM_BATCH_N == RTM_BATCH_N - 1)) { // Simulate basic block end. // XXX Update: since we have checked odd version in tx region, we // will abort for parallel execution of read tx and write fallback. // So no need to check for lock here. // XXX A transaction is accessing different shared objects. Here we only // check for a single object's write lock, it's not enough. That's why // we need the odd version check in the transaction region. /* *if (info->write_lock) { * _xabort(2); *} */ _xend(); // Avoid taking log inside transaction. batch_read_log(objid, version); batch_process_log(); } else { batch_read_log(objid, version); } g_sim_bbcnt++; return val; }
void mem_write(tid_t tid, uint32_t *addr, uint32_t val) { version_t version; objid_t objid = calc_objid(addr); struct objinfo *info = &g_objinfo[objid]; if ((g_sim_bbcnt % RTM_BATCH_N) == 0) { assert(!_xtest()); int ret = _xbegin(); (void)ret; #ifdef RTM_STAT if (ret != _XBEGIN_STARTED) { fprintf(stderr, "T%d W%ld aborted %x, %d\n", g_tid, memop, ret, _XABORT_CODE(ret)); g_rtm_abort_cnt++; } #endif } int in_rtm = _xtest(); if (in_rtm) { version = info->version; // XXX To ensure exclusion of write tx and fallback. Same as in read // transaction. if (info->write_lock) { _xabort(3); } barrier(); *addr = val; barrier(); info->version += 2; // XXX The barrier is necessary, because there are reordering inside a // transaction. The reason is the same as in seqlock implementation. __sync_synchronize(); } else { spin_lock(&info->write_lock); version = info->version; barrier(); // Odd version means that there's writer trying to update value. info->version++; barrier(); *addr = val; // This barrier disallows read to happen before the write. // The explicit barrier here may also make the compiler unnecessary here. __sync_synchronize(); info->version++; spin_unlock(&info->write_lock); } if (in_rtm && (g_sim_bbcnt % RTM_BATCH_N == RTM_BATCH_N - 1)) { // XXX Update: since we have checked lock in tx region, we // will abort for parallel execution of write tx and write fallback. // So no need to check for lock here. /* *if (info->write_lock) { * _xabort(4); *} */ _xend(); // Avoid taking log inside transaction. batch_write_log(objid, version); batch_process_log(); } else { batch_write_log(objid, version); } g_sim_bbcnt++; }