static inline void
process_all_work(struct workqueue_worker *worker)
{
	struct work_struct *work;
	bool didcan;

	while (STAILQ_FIRST(&worker->ws_list_head)) {
		work = STAILQ_FIRST(&worker->ws_list_head);
		STAILQ_REMOVE_HEAD(&worker->ws_list_head, ws_entries);
		work->on_queue = false;

		/* A work shouldn't be executed concurrently on a single cpu */
		if (work->running)
			continue;

		/* Do not run canceled works */
		if (work->canceled) {
			/* XXX: should we allow canceled works to be reenabled ? */
			work->canceled = false;
			continue;
		}

		work->running = true;
		lockmgr(&worker->worker_lock, LK_RELEASE);
		work->func(work);
		lwkt_yield();
		lockmgr(&worker->worker_lock, LK_EXCLUSIVE);
		if (work->on_queue == false)
			work->worker = NULL;
		didcan = work->canceled;
		cpu_sfence();
		work->running = false;
		if (didcan == true)
			wakeup(work);
	}
}
static void
wq_worker_thread(void *arg)
{
	struct workqueue_worker *worker = arg;

	lockmgr(&worker->worker_lock, LK_EXCLUSIVE);
	while (1) {
		process_all_work(worker);
		lksleep(worker, &worker->worker_lock, 0, "wqidle", 0);
	}
	lockmgr(&worker->worker_lock, LK_RELEASE);
}
int
queue_work(struct workqueue_struct *wq, struct work_struct *work)
{
	struct workqueue_worker *worker;
	int ret = false;

	/* XXX: should we block instead ? */
	if (wq->is_draining)
		return false;

	if (wq->num_workers > 1)
		worker = &(*wq->workers)[mycpuid];
	else
		worker = &(*wq->workers)[0];

	lockmgr(&worker->worker_lock, LK_EXCLUSIVE);
	work->canceled = false;
	if (work->on_queue == false || work->running == false) {
		if (work->on_queue == false) {
			STAILQ_INSERT_TAIL(&worker->ws_list_head, work,
					   ws_entries);
			work->on_queue = true;
			work->worker = worker;
			wakeup_one(worker);
		}
		ret = true;
	}
	lockmgr(&worker->worker_lock, LK_RELEASE);

	return ret;
}
static inline void
_delayed_work_fn(void *arg)
{
	struct delayed_work *dw = arg;

	queue_work(system_wq, &dw->work);
}
int
queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *work,
    unsigned long delay)
{
	int pending = work->work.on_queue; // XXX: running too ?
	if (delay != 0) {
		callout_reset(&work->timer, delay, _delayed_work_fn, work);
	} else {
		_delayed_work_fn((void *)work);
	}

	return (!pending);
}
static inline bool
_cancel_work(struct work_struct *work, bool sync_wait)
{
	struct workqueue_worker *worker;
	bool ret;

	ret = false;

	for (;;) {
		if (work->on_queue) {
			worker = work->worker;
			if (worker == NULL)
				continue;
			lockmgr(&worker->worker_lock, LK_EXCLUSIVE);
			if (worker != work->worker || work->on_queue == false) {
				lockmgr(&worker->worker_lock, LK_RELEASE);
				continue;
			}
			STAILQ_REMOVE(&worker->ws_list_head, work,
				      work_struct, ws_entries);
			work->on_queue = false;
			ret = true;
			lockmgr(&worker->worker_lock, LK_RELEASE);
		}
		if (work->running == false)
			break;

		worker = work->worker;
		if (worker == NULL)
			continue;
		lockmgr(&worker->worker_lock, LK_EXCLUSIVE);
		if (worker != work->worker || work->running == false) {
			lockmgr(&worker->worker_lock, LK_RELEASE);
			continue;
		}
		work->canceled = true;
		ret = true;
		if (sync_wait == false) {
			lockmgr(&worker->worker_lock, LK_RELEASE);
			break;
		}
		/* XXX this races */
		lksleep(work, &worker->worker_lock, 0, "wqcan", 1);
		lockmgr(&worker->worker_lock, LK_RELEASE);
		/* retest */
	}

	return ret;
}
bool
cancel_work_sync(struct work_struct *work)
{
	return _cancel_work(work, true);
}

/* Return false if work wasn't pending
 * Return true if work was pending and canceled */
bool
cancel_delayed_work(struct delayed_work *dwork)
{
	struct work_struct *work = &dwork->work;

	work->canceled = true;
	callout_cancel(&dwork->timer);

	return _cancel_work(work, false);
}

bool
cancel_delayed_work_sync(struct delayed_work *dwork)
{
	struct work_struct *work = &dwork->work;

	work->canceled = true;
	callout_cancel(&dwork->timer);

	return _cancel_work(work, true);
}
