Beispiel #1
0
Datei: mt.c Projekt: yoanlcq/FATE
static void fe_mt_tsx_lock_x86rtm(fe_mt_tsx *tsx) {

    static const char *TAG = "fe_mt";

    /* Currently, we prevent nested transactions. 
     * FIXME Prove it is actually required. */
    if(_xtest()) 
        return;

retry:
    unsigned status = _xbegin();
    if(status == _XBEGIN_STARTED)
        return;
    if(status & _XABORT_RETRY)
        goto retry;

    fe_logv("x86 RTM transaction aborted."
              "Falling back to regular lock. Reason :\n\t");
    if(status & _XABORT_EXPLICIT)
        fe_logv(TAG, "Explicit abort. Code : %d\n", _XABORT_CODE(status)); 
    if(status & _XABORT_CONFLICT)
        fe_logv(TAG, "Memory conflict with another thread.\n");
    if(status & _XABORT_CAPACITY)
        fe_logv(TAG, "Too much memory used by the transaction.\n");
    if(status & _XABORT_DEBUG)
        fe_logv(TAG, "Debug trap.\n");
    if(status & _XABORT_NESTED)
        fe_logv(TAG, "Abort in an inner nested transaction.\n");

    fe_mt_tsx_lock_fallback(tsx);
}
Beispiel #2
0
  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();
  }
}
Beispiel #3
0
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;
}
Beispiel #4
0
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 */
	}
}
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++;
}