#include <9pm/u.h>
#include <9pm/libc.h>
#include <9pm/ns.h>
#include <9pm/thread.h>
#include <9pm/threadimpl.h>

void
_threadputq(Tqueue *q, Thread *t)
{
	Thread *x;
	Thread **l;

	lock(&q->lk);
	_threaddebug(DBGQUE, "Putq 0x%lux on 0x%lux, next == 0x%lux",
		(ulong)t, (ulong)q, (ulong)t->next);
	threadassert((ulong)t->next == (ulong)~0);
	t->next = nil;
	if (q->head == nil) {
		q->head = t;
		q->tail = t;
	} else {
		x = q->tail->next;
		if(x != nil){
			_threaddebug(DBGQUE, "\tq->tail->next = 0x%lux",
				(ulong)x);
			_threaddebug(DBGQUE, "\tq=0x%lux q->tail=0x%lux q->tail->next=0x%lux",
				(ulong)q, (ulong)q->tail, (ulong)q->tail->next);
			_threaddebug(DBGQUE, "\tq=0x%lux q->head=0x%lux q->head->next=0x%lux",
				(ulong)q, (ulong)q->head, (ulong)q->head->next);
			l = &q->tail->next;
			_threaddebug(DBGQUE, "\tl=0x%lux *l=0x%lux\n",
				(ulong)l, (ulong)*l);
			_threaddebug(DBGQUE, "\tsp=0x%lux; stack is 0x%lux-0x%lux\n", (ulong)&l, (ulong)_threadgetthr()->stk, (ulong)_threadgetthr()->stk+_threadgetthr()->stksize);
			abort();
			threadassert(x == nil);
		}
		q->tail->next = t;
		q->tail = t;
	}
	unlock(&q->lk);
}

Thread *
_threadgetq(Tqueue *q)
{
	Thread *t;

	lock(&q->lk);
	if ((t = q->head)) {
		q->head = q->head->next;
		t->next = (Thread *)~0;
	}
	unlock(&q->lk);
	_threaddebug(DBGQUE, "Getq 0x%lux from 0x%lux", (ulong)t, (ulong)q);
	return t;
}

Thread *
_threadgetqbytag(Tqueue *q, ulong tag)
{
	Thread *r, *pr, *w, *pw;

	w = pr = pw = nil;
	_threaddebug(DBGQUE, "Getqbytag 0x%lux", q);
	lock(&q->lk);
	for (r = q->head; r; r = r->next) {
		if (r->tag == tag) {
			w = r;
			pw = pr;
			if (r->proc == _threadgetproc()) {
				/* Locals or blocked remotes are best */
				break;
			}
		}
		pr = r;
	}
	if (w) {
		if (pw)
			pw->next = w->next;
		else
			q->head = w->next;
		if (q->tail == w){
			q->tail = pw;
			threadassert(pw == nil || pw->next == nil);
		}
		w->next = (Thread *)~0;
	}
	unlock(&q->lk);
	_threaddebug(DBGQUE, "Getqbytag 0x%lux from 0x%lux", w, q);
	return w;
}

