示例#1
0
文件: lock_sema.c 项目: kostyll/gccpy
void
runtime_lock(Lock *l)
{
    M *m;
    uintptr v;
    uint32 i, spin;

    m = runtime_m();
    if(m->locks++ < 0)
        runtime_throw("runtime_lock: lock count");

    // Speculative grab for lock.
    if(runtime_casp((void**)&l->key, nil, (void*)LOCKED))
        return;

    if(m->waitsema == 0)
        m->waitsema = runtime_semacreate();

    // On uniprocessor's, no point spinning.
    // On multiprocessors, spin for ACTIVE_SPIN attempts.
    spin = 0;
    if(runtime_ncpu > 1)
        spin = ACTIVE_SPIN;

    for(i=0;; i++) {
        v = (uintptr)runtime_atomicloadp((void**)&l->key);
        if((v&LOCKED) == 0) {
unlocked:
            if(runtime_casp((void**)&l->key, (void*)v, (void*)(v|LOCKED)))
                return;
            i = 0;
        }
        if(i<spin)
            runtime_procyield(ACTIVE_SPIN_CNT);
        else if(i<spin+PASSIVE_SPIN)
            runtime_osyield();
        else {
            // Someone else has it.
            // l->waitm points to a linked list of M's waiting
            // for this lock, chained through m->nextwaitm.
            // Queue this M.
            for(;;) {
                m->nextwaitm = (void*)(v&~LOCKED);
                if(runtime_casp((void**)&l->key, (void*)v, (void*)((uintptr)m|LOCKED)))
                    break;
                v = (uintptr)runtime_atomicloadp((void**)&l->key);
                if((v&LOCKED) == 0)
                    goto unlocked;
            }
            if(v&LOCKED) {
                // Queued.  Wait.
                runtime_semasleep(-1);
                i = 0;
            }
        }
    }
}
示例#2
0
文件: lock_futex.c 项目: vkargov/gcc
// Possible lock states are MUTEX_UNLOCKED, MUTEX_LOCKED and MUTEX_SLEEPING.
// MUTEX_SLEEPING means that there is presumably at least one sleeping thread.
// Note that there can be spinning threads during all states - they do not
// affect mutex's state.
void
runtime_lock(Lock *l)
{
	uint32 i, v, wait, spin;

	if(runtime_m()->locks++ < 0)
		runtime_throw("runtime_lock: lock count");

	// Speculative grab for lock.
	v = runtime_xchg(&l->key, MUTEX_LOCKED);
	if(v == MUTEX_UNLOCKED)
		return;

	// wait is either MUTEX_LOCKED or MUTEX_SLEEPING
	// depending on whether there is a thread sleeping
	// on this mutex.  If we ever change l->key from
	// MUTEX_SLEEPING to some other value, we must be
	// careful to change it back to MUTEX_SLEEPING before
	// returning, to ensure that the sleeping thread gets
	// its wakeup call.
	wait = v;

	// On uniprocessor's, no point spinning.
	// On multiprocessors, spin for ACTIVE_SPIN attempts.
	spin = 0;
	if(runtime_ncpu > 1)
		spin = ACTIVE_SPIN;

	for(;;) {
		// Try for lock, spinning.
		for(i = 0; i < spin; i++) {
			while(l->key == MUTEX_UNLOCKED)
				if(runtime_cas(&l->key, MUTEX_UNLOCKED, wait))
					return;
			runtime_procyield(ACTIVE_SPIN_CNT);
		}

		// Try for lock, rescheduling.
		for(i=0; i < PASSIVE_SPIN; i++) {
			while(l->key == MUTEX_UNLOCKED)
				if(runtime_cas(&l->key, MUTEX_UNLOCKED, wait))
					return;
			runtime_osyield();
		}

		// Sleep.
		v = runtime_xchg(&l->key, MUTEX_SLEEPING);
		if(v == MUTEX_UNLOCKED)
			return;
		wait = MUTEX_SLEEPING;
		runtime_futexsleep(&l->key, MUTEX_SLEEPING, -1);
	}
}