1// Copyright 2016 The Fuchsia Authors 2// Copyright (c) 2008-2014 Travis Geiselbrecht 3// 4// Use of this source code is governed by a MIT-style 5// license that can be found in the LICENSE file or at 6// https://opensource.org/licenses/MIT 7 8#pragma once 9 10#include <err.h> 11#include <kernel/thread.h> 12#include <stdbool.h> 13#include <stdint.h> 14#include <sys/types.h> 15#include <zircon/compiler.h> 16#include <zircon/types.h> 17 18__BEGIN_CDECLS 19 20#define EVENT_MAGIC (0x65766E74) // "evnt" 21 22typedef struct event { 23 int magic; 24 bool signaled; 25 uint flags; 26 wait_queue_t wait; 27} event_t; 28 29#define EVENT_FLAG_AUTOUNSIGNAL 1 30 31#define EVENT_INITIAL_VALUE(e, initial, _flags) \ 32 { \ 33 .magic = EVENT_MAGIC, \ 34 .signaled = initial, \ 35 .flags = _flags, \ 36 .wait = WAIT_QUEUE_INITIAL_VALUE((e).wait), \ 37 } 38 39// Rules for Events: 40// - Events may be signaled from interrupt context *but* the reschedule 41// parameter must be false in that case. 42// - Events may not be waited upon from interrupt context. 43// - Events without FLAG_AUTOUNSIGNAL: 44// - Wake up any waiting threads when signaled. 45// - Continue to do so (no threads will wait) until unsignaled. 46// - Events with FLAG_AUTOUNSIGNAL: 47// - If one or more threads are waiting when signaled, one thread will 48// be woken up and return. The signaled state will not be set. 49// - If no threads are waiting when signaled, the Event will remain 50// in the signaled state until a thread attempts to wait (at which 51// time it will unsignal atomicly and return immediately) or 52// event_unsignal() is called. 53 54void event_init(event_t*, bool initial, uint flags); 55void event_destroy(event_t*); 56 57// Wait until deadline 58// Interruptable arg allows it to return early with ZX_ERR_INTERNAL_INTR_KILLED if thread 59// is signaled for kill. 60zx_status_t event_wait_deadline(event_t*, zx_time_t, bool interruptable); 61 62// no deadline, non interruptable version of the above. 63static inline zx_status_t event_wait(event_t* e) { 64 return event_wait_deadline(e, ZX_TIME_INFINITE, false); 65} 66 67// Version of event_wait_deadline that ignores existing signals in 68// |signal_mask|. There is no deadline, and the caller must be interruptable. 69zx_status_t event_wait_with_mask(event_t*, uint signal_mask); 70 71int event_signal_etc(event_t*, bool reschedule, zx_status_t result); 72int event_signal(event_t*, bool reschedule); 73int event_signal_thread_locked(event_t*) TA_REQ(thread_lock); 74zx_status_t event_unsignal(event_t*); 75 76static inline bool event_initialized(const event_t* e) { 77 return e->magic == EVENT_MAGIC; 78} 79 80static inline bool event_signaled(const event_t* e) { 81 return e->signaled; 82} 83 84__END_CDECLS 85 86#ifdef __cplusplus 87 88// C++ wrapper. This should be waited on from only a single thread, but may be 89// signaled from many threads (Signal() is thread-safe). 90class Event { 91public: 92 Event(uint32_t opts = 0) { 93 event_init(&event_, false, opts); 94 } 95 ~Event() { 96 event_destroy(&event_); 97 } 98 99 Event(const Event&) = delete; 100 Event& operator=(const Event&) = delete; 101 102 // Returns: 103 // ZX_OK - signaled 104 // ZX_ERR_TIMED_OUT - time out expired 105 // ZX_ERR_INTERNAL_INTR_KILLED - thread killed 106 // Or the |status| which the caller specified in Event::Signal(status) 107 zx_status_t Wait(zx_time_t deadline) { 108 return event_wait_deadline(&event_, deadline, true); 109 } 110 111 void Signal(zx_status_t status = ZX_OK) { 112 event_signal_etc(&event_, true, status); 113 } 114 115 zx_status_t Unsignal() { 116 return event_unsignal(&event_); 117 } 118 119private: 120 event_t event_; 121}; 122 123#endif // __cplusplus 124