src/sys/sys/clockintr.h

145 lines
4.7 KiB
C

/* $OpenBSD: clockintr.h,v 1.29 2024/02/25 19:15:50 cheloha Exp $ */
/*
* Copyright (c) 2020-2024 Scott Cheloha <cheloha@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _SYS_CLOCKINTR_H_
#define _SYS_CLOCKINTR_H_
#include <sys/stdint.h>
struct clockintr_stat {
uint64_t cs_dispatched; /* total time in dispatch (ns) */
uint64_t cs_early; /* number of early dispatch calls */
uint64_t cs_earliness; /* total earliness (ns) */
uint64_t cs_lateness; /* total lateness (ns) */
uint64_t cs_prompt; /* number of prompt dispatch calls */
uint64_t cs_run; /* number of events dispatched */
uint64_t cs_spurious; /* number of spurious dispatch calls */
};
#ifdef _KERNEL
#include <sys/mutex.h>
#include <sys/queue.h>
struct clockqueue;
struct clockrequest;
struct cpu_info;
/*
* Platform API
*/
struct intrclock {
void *ic_cookie;
void (*ic_rearm)(void *, uint64_t);
void (*ic_trigger)(void *);
};
/*
* Schedulable clock interrupt callback.
*
* Struct member protections:
*
* I Immutable after initialization.
* m Parent queue mutex (cl_queue->cq_mtx).
*/
struct clockintr {
uint64_t cl_expiration; /* [m] dispatch time */
TAILQ_ENTRY(clockintr) cl_alink; /* [m] cq_all glue */
TAILQ_ENTRY(clockintr) cl_plink; /* [m] cq_pend glue */
void *cl_arg; /* [I] argument */
void (*cl_func)(struct clockrequest *, void*, void*); /* [I] callback */
struct clockqueue *cl_queue; /* [I] parent queue */
uint32_t cl_flags; /* [m] CLST_* flags */
};
#define CLST_PENDING 0x00000001 /* scheduled to run */
/*
* Interface for callback rescheduling requests.
*
* Struct member protections:
*
* I Immutable after initialization.
* o Owned by a single CPU.
*/
struct clockrequest {
uint64_t cr_expiration; /* [o] copy of dispatch time */
struct clockqueue *cr_queue; /* [I] enclosing queue */
uint32_t cr_flags; /* [o] CR_* flags */
};
#define CR_RESCHEDULE 0x00000001 /* reschedule upon return */
/*
* Per-CPU clock interrupt state.
*
* Struct member protections:
*
* a Modified atomically.
* I Immutable after initialization.
* m Per-queue mutex (cq_mtx).
* o Owned by a single CPU.
*/
struct clockqueue {
struct clockrequest cq_request; /* [o] callback request object */
struct mutex cq_mtx; /* [a] per-queue mutex */
uint64_t cq_uptime; /* [o] cached uptime */
TAILQ_HEAD(, clockintr) cq_all; /* [m] established clockintr list */
TAILQ_HEAD(, clockintr) cq_pend;/* [m] pending clockintr list */
struct clockintr *cq_running; /* [m] running clockintr */
struct clockintr cq_hardclock; /* [o] hardclock handle */
struct intrclock cq_intrclock; /* [I] local interrupt clock */
struct clockintr_stat cq_stat; /* [o] dispatch statistics */
volatile uint32_t cq_gen; /* [o] cq_stat update generation */
volatile uint32_t cq_dispatch; /* [o] dispatch is running */
uint32_t cq_flags; /* [m] CQ_* flags; see below */
};
#define CQ_INIT 0x00000001 /* clockintr_cpu_init() done */
#define CQ_INTRCLOCK 0x00000002 /* intrclock installed */
#define CQ_IGNORE_REQUEST 0x00000004 /* ignore callback requests */
#define CQ_NEED_WAKEUP 0x00000008 /* caller at barrier */
#define CQ_STATE_MASK 0x0000000f
void clockintr_cpu_init(const struct intrclock *);
int clockintr_dispatch(void *);
void clockintr_trigger(void);
/*
* Kernel API
*/
#define CL_BARRIER 0x00000001 /* block if callback is running */
#define CL_FLAG_MASK 0x00000001
uint64_t clockintr_advance(struct clockintr *, uint64_t);
void clockintr_bind(struct clockintr *, struct cpu_info *,
void (*)(struct clockrequest *, void *, void *), void *);
void clockintr_cancel(struct clockintr *);
void clockintr_schedule(struct clockintr *, uint64_t);
void clockintr_stagger(struct clockintr *, uint64_t, uint32_t, uint32_t);
void clockintr_unbind(struct clockintr *, uint32_t);
uint64_t clockrequest_advance(struct clockrequest *, uint64_t);
uint64_t clockrequest_advance_random(struct clockrequest *, uint64_t, uint32_t);
void clockqueue_init(struct clockqueue *);
int sysctl_clockintr(int *, u_int, void *, size_t *, void *, size_t);
#endif /* _KERNEL */
#endif /* !_SYS_CLOCKINTR_H_ */