blob: 3dc1e849fcba0287eeb7936a4cd9fa8c168040d2 [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
#ifndef ZIRCON_KERNEL_INCLUDE_KERNEL_EVENT_H_
#define ZIRCON_KERNEL_INCLUDE_KERNEL_EVENT_H_
#include <err.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
#include <fbl/canary.h>
#include <kernel/thread.h>
#include <kernel/timer.h>
// Rules for Events and AutounsignalEvents:
// - Events may be signaled from interrupt context *but* the reschedule
// parameter must be false in that case.
// - Events may not be waited upon from interrupt context.
// - Standard Events:
// - Wake up any waiting threads when signaled.
// - Continue to do so (no threads will wait) until unsignaled.
// - Stores a single result value when first signaled. This result is
// returned to waiters and cleared when unsignaled.
// - AutounsignalEvents:
// - If one or more threads are waiting when signaled, one thread will
// be woken up and return. The signaled state will not be set.
// - If no threads are waiting when signaled, the AutounsignalEvent will remain
// in the signaled state until a thread attempts to wait (at which
// time it will unsignal atomicly and return immediately) or
// AutounsignalEvent::Unsignal() is called.
// - Stores a single result value when signaled until a thread is woken.
class Event {
public:
constexpr explicit Event(bool initial = false) : Event(initial, Flags(0)) {}
~Event();
Event(const Event&) = delete;
Event& operator=(const Event&) = delete;
// Event::Wait() and other Wait functions will return ZX_OK if already signaled, even if deadline
// has passed. They will return ZX_ERR_TIMED_OUT after the deadline passes if the event has not
// been signaled.
// Returns:
// ZX_OK - signaled
// ZX_ERR_TIMED_OUT - time out expired
// ZX_ERR_INTERNAL_INTR_KILLED - thread killed
// ZX_ERR_INTERNAL_INTR_RETRY - thread is suspended
// Or the |status| which the caller specified in Event::Signal(status)
zx_status_t Wait(const Deadline& deadline) { return WaitWorker(deadline, true, 0); }
// Same as Wait() but waits forever and gives a mask of signals to ignore.
// The caller must be interruptable.
zx_status_t WaitWithMask(uint signal_mask) {
return WaitWorker(Deadline::infinite(), true, signal_mask);
}
// no deadline, non interruptable version of the above.
zx_status_t Wait() { return WaitWorker(Deadline::infinite(), false, 0); }
// Wait until deadline
// Interruptable arg allows it to return early with ZX_ERR_INTERNAL_INTR_KILLED if thread
// is signaled for kill or with ZX_ERR_INTERNAL_INTR_RETRY if the thread is suspended.
zx_status_t WaitDeadline(zx_time_t deadline, bool interruptable) {
return WaitWorker(Deadline::no_slack(deadline), interruptable, 0);
}
// All Signal variations return the number of threads woken.
int Signal(zx_status_t status = ZX_OK) { return SignalEtc(true, status); }
int SignalThreadLocked() TA_REQ(thread_lock);
int SignalNoResched() { return SignalEtc(false); }
int SignalEtc(bool reschedule, zx_status_t wait_result = ZX_OK);
zx_status_t Unsignal() TA_EXCL(thread_lock);
protected:
enum Flags : uint32_t {
AUTOUNSIGNAL = 1,
};
// Only our AutounsignalEvent subclass can also access this, to keep the flags private.
constexpr Event(bool initial, Flags flags)
: magic_(kMagic), result_(initial ? ZX_OK : INT_MAX), flags_(flags) {}
private:
zx_status_t WaitWorker(const Deadline& deadline, bool interruptable, uint signal_mask);
int SignalInternal(bool reschedule, zx_status_t wait_result) TA_REQ(thread_lock);
static constexpr uint32_t kMagic = fbl::magic("evnt");
uint32_t magic_;
static constexpr zx_status_t kNotSignalled = INT_MAX;
zx_status_t result_;
Flags flags_;
WaitQueue wait_;
};
class AutounsignalEvent : public Event {
public:
constexpr explicit AutounsignalEvent(bool initial = false)
: Event(initial, Flags::AUTOUNSIGNAL) {}
};
#endif // ZIRCON_KERNEL_INCLUDE_KERNEL_EVENT_H_