blob: 2b25e5884b8854a28fc4128756436bd6310fa921 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
// Copyright (c) 2008-2014 Travis Geiselbrecht
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#pragma once
#include <arch/defines.h>
#include <arch/ops.h>
#include <arch/thread.h>
#include <kernel/spinlock.h>
#include <list.h>
#include <sys/types.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
__BEGIN_CDECLS
extern spin_lock_t thread_lock;
// wait queue stuff
#define WAIT_QUEUE_MAGIC (0x77616974) // 'wait'
typedef struct wait_queue {
int magic;
int count;
struct list_node heads;
} wait_queue_t;
#define WAIT_QUEUE_INITIAL_VALUE(q) \
{ \
.magic = WAIT_QUEUE_MAGIC, \
.count = 0, \
.heads = LIST_INITIAL_VALUE((q).heads), \
}
// wait queue primitive
// NOTE: must be inside critical section when using these
void wait_queue_init(wait_queue_t* wait);
void wait_queue_destroy(wait_queue_t*);
// block on a wait queue.
// return status is whatever the caller of wait_queue_wake_*() specifies.
// a deadline other than ZX_TIME_INFINITE will abort at the specified time
// and return ZX_ERR_TIMED_OUT. a deadline in the past will immediately return.
zx_status_t wait_queue_block(wait_queue_t*, zx_time_t deadline) TA_REQ(thread_lock);
// block on a wait queue, ignoring existing signals in |signal_mask|.
// return status is whatever the caller of wait_queue_wake_*() specifies.
// a deadline other than ZX_TIME_INFINITE will abort at the specified time
// and return ZX_ERR_TIMED_OUT. a deadline in the past will immediately return.
zx_status_t wait_queue_block_with_mask(wait_queue_t*, zx_time_t deadline,
uint signal_mask) TA_REQ(thread_lock);
// returns the highest priority of all the blocked threads on this wait queue.
// returns -1 if no threads are blocked.
int wait_queue_blocked_priority(wait_queue_t*) TA_REQ(thread_lock);
// returns the current highest priority blocked thread on this wait queue, or
// null if no threads are blocked.
struct thread* wait_queue_peek(wait_queue_t*) TA_REQ(thread_lock);
// release one or more threads from the wait queue.
// reschedule = should the system reschedule if any is released.
// wait_queue_error = what wait_queue_block() should return for the blocking thread.
int wait_queue_wake_one(wait_queue_t*, bool reschedule,
zx_status_t wait_queue_error) TA_REQ(thread_lock);
int wait_queue_wake_all(wait_queue_t*, bool reschedule,
zx_status_t wait_queue_error) TA_REQ(thread_lock);
struct thread* wait_queue_dequeue_one(wait_queue_t* wait,
zx_status_t wait_queue_error) TA_REQ(thread_lock);
// is the wait queue currently empty
bool wait_queue_is_empty(wait_queue_t*) TA_REQ(thread_lock);
// remove a specific thread out of a wait queue it's blocked on
zx_status_t wait_queue_unblock_thread(struct thread* t,
zx_status_t wait_queue_error) TA_REQ(thread_lock);
// a thread's priority has changed, potentially modify the wait queue it's in
void wait_queue_priority_changed(struct thread* t,
int old_prio) TA_REQ(thread_lock);
// validate that the queue of a given wait queue is valid
void wait_queue_validate_queue(wait_queue_t* wait) TA_REQ(thread_lock);
__END_CDECLS
#ifdef __cplusplus
class WaitQueue {
public:
WaitQueue() {}
~WaitQueue() { wait_queue_destroy(&wq_); }
WaitQueue(WaitQueue&) = delete;
WaitQueue(WaitQueue&&) = delete;
WaitQueue& operator=(WaitQueue&) = delete;
WaitQueue& operator=(WaitQueue&&) = delete;
zx_status_t Block(zx_time_t deadline) TA_REQ(thread_lock) {
return wait_queue_block(&wq_, deadline);
}
struct thread* Peek() TA_REQ(thread_lock) {
return wait_queue_peek(&wq_);
}
int WakeOne(bool reschedule, zx_status_t wait_queue_error) TA_REQ(thread_lock) {
return wait_queue_wake_one(&wq_, reschedule, wait_queue_error);
}
bool IsEmpty() TA_REQ(thread_lock) { return wait_queue_is_empty(&wq_); }
static zx_status_t UnblockThread(struct thread* t, zx_status_t wait_queue_error)
TA_REQ(thread_lock) {
return wait_queue_unblock_thread(t, wait_queue_error);
}
private:
wait_queue_t wq_ = WAIT_QUEUE_INITIAL_VALUE(wq_);
};
#endif // __cplusplus