Milán Major

netscape-revival

1 branch
Code

nspr/src/swlock.c

#ifdef SW_THREADS
#include "prlock.h"
#include "prlog.h"
#include "prmem.h"
#include "swkern.h"

/*
** XXX need per-thread list of locks thread owns so that they can get
** XXX fixed up when thread is zapped
**
** XXX this is work in progress; they aren't finished yet, and I'm not
** XXX sure we need them since monitors will suffice
*/

PR_PUBLIC_API(PRLock *) PR_NewLock(int locked)
{
    PRLock *lock;

    lock = PR_NEW(PRLock);
    if (lock) {
	PR_INIT_CLIST(&lock->waitQ);
	if (locked) {
	    lock->owner = _pr_current_thread;
	} else {
	    lock->owner = 0;
	}
    }
    return lock;
}

PR_PUBLIC_API(void) PR_InitLock(PRLock *lock, int locked)
{
    PR_ASSERT(lock->waitQ.next == 0);
    PR_INIT_CLIST(&lock->waitQ);
    if (locked) {
	lock->owner = _pr_current_thread;
    } else {
	lock->owner = 0;
    }
}

PR_PUBLIC_API(void) PR_DestroyLock(PRLock *lock)
{
    PR_ASSERT(PR_CLIST_IS_EMPTY(&lock->waitQ));
    PR_ASSERT(lock->owner == 0);
    free(lock);
}

PR_PUBLIC_API(void) PR_Lock(PRLock *lock)
{
    PRThread *me = _pr_current_thread;
    int is;

    is = _PR_IntsOff();
    for (;;) {
	if (lock->owner == 0) {
	    lock->owner = me;
	    break;
	}
	/* XXX who deals with priority inversion? */
	PR_APPEND_LINK(&me->runqLinks, &lock->waitQ);
	me->state = _PR_LOCK_WAIT;
	_PR_SwitchThread(me);
    }
    _PR_IntsOn(is, 0);
}

PR_PUBLIC_API(void) PR_Unlock(PRLock *lock)
{
    PRThread *me = _pr_current_thread;
    PRThread *best, *waiter;
    int bestPri;
    PRCList *qp;
    int needYield = 0;
    int is;

    is = _PR_IntsOff();

    PR_ASSERT(lock->owner == me);

    best = 0;
    bestPri = -1;
    lock->owner = 0;
    qp = lock->waitQ.next;
    while (qp != &lock->waitQ) {
	waiter = THREAD_PTR(qp);
	qp = waiter->runqLinks.next;
	if (waiter->flags & _PR_SUSPENDING) {
	    /*
	    ** Don't wakeup waiters that are going to be suspended once
	    ** they get the lock.
	    */
	} else if ((int)waiter->priority > bestPri) {
	    /* Found a higher priority waiter */
	    best = waiter;
	    bestPri = (int) waiter->priority;
	}
    }
    if (best) {
	/*
	** Take best waiter off of the lock's waitQ and put it onto the
	** runq.
	*/
	PR_REMOVE_AND_INIT_LINK(&best->runqLinks);
	_pr_runq_ready_mask |= (1L << bestPri);
	PR_APPEND_LINK(&best->runqLinks, &_pr_runq[bestPri]);
	needYield = bestPri > me->priority;
    }

    /* XXX who deals with undoing priority inversion? */
    _PR_IntsOn(is, needYield);
}

#endif /* SW_THREADS */