blob: b881ac4b5b74bd934a1e100671f500d48b8b2677 [file] [edit]
// Copyright 2025 The Fuchsia Authors
//
// 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_OBJECT_INCLUDE_OBJECT_COUNTER_DISPATCHER_H_
#define ZIRCON_KERNEL_OBJECT_INCLUDE_OBJECT_COUNTER_DISPATCHER_H_
#include <zircon/rights.h>
#include <zircon/types.h>
#include <ktl/atomic.h>
#include <object/dispatcher.h>
#include <object/handle.h>
class CounterDispatcher
: public SoloDispatcher<CounterDispatcher, ZX_DEFAULT_COUNTER_RIGHTS, ZX_COUNTER_SIGNALED> {
public:
~CounterDispatcher() override;
// Creates a CounterDispatcher.
static zx_status_t Create(KernelHandle<CounterDispatcher>* handle, zx_rights_t* rights);
zx_obj_type_t get_type() const final { return ZX_OBJ_TYPE_COUNTER; }
// Returns the counter's value.
//
// Synchronizes-with |SetValue| or |Add|.
int64_t Value() const {
Guard<CriticalMutex> guard{get_lock()};
return value_;
}
// Sets the counter's value, asserting/deasserting signals as appropriate.
//
// Synchronizes-with |Value| or |Add|.
void SetValue(int64_t new_value) {
Guard<CriticalMutex> guard{get_lock()};
SetValueLocked(new_value);
}
// Adds |amount| to this counter.
//
// Synchronizes-with |SetValue| or |Value|.
//
// Returns an error if the value would underflow/overflow.
zx_status_t Add(int64_t amount) {
Guard<CriticalMutex> guard{get_lock()};
const int64_t before = value_;
int64_t after;
if (add_overflow(before, amount, &after)) {
return ZX_ERR_OUT_OF_RANGE;
}
SetValueLocked(after);
return ZX_OK;
}
private:
CounterDispatcher();
// Returns true iff |old_value| is non-positive and |new_value| is positive.
static bool NewlyPositive(int64_t old_value, int64_t new_value) {
return (old_value <= 0 && new_value > 0);
}
// Returns true iff |old_value| is positive and |new_value| is non-positive.
static bool NewlyNonPositive(int64_t old_value, int64_t new_value) {
return (old_value > 0 && new_value <= 0);
}
void SetValueLocked(int64_t new_value) TA_REQ(get_lock()) {
const int64_t old_value = value_;
value_ = new_value;
if (NewlyPositive(old_value, new_value)) {
UpdateStateLocked(ZX_COUNTER_NON_POSITIVE, ZX_COUNTER_POSITIVE);
} else if (NewlyNonPositive(old_value, new_value)) {
UpdateStateLocked(ZX_COUNTER_POSITIVE, ZX_COUNTER_NON_POSITIVE);
}
}
int64_t value_ TA_GUARDED(get_lock()){};
};
#endif // ZIRCON_KERNEL_OBJECT_INCLUDE_OBJECT_COUNTER_DISPATCHER_H_