1/*	$OpenBSD: srp.h,v 1.15 2020/05/09 10:18:27 jca Exp $ */
2
3/*
4 * Copyright (c) 2014 Jonathan Matthew <jmatthew@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#ifndef _SYS_SRP_H_
20#define _SYS_SRP_H_
21
22#include <sys/refcnt.h>
23
24#ifndef __upunused
25#ifdef MULTIPROCESSOR
26#define __upunused
27#else
28#define __upunused __attribute__((__unused__))
29#endif
30#endif /* __upunused */
31
32struct srp {
33	void			*ref;
34};
35
36#define SRP_INITIALIZER() { NULL }
37
38struct srp_hazard {
39	struct srp		*sh_p;
40	void			*sh_v;
41};
42
43struct srp_ref {
44	struct srp_hazard	*hz;
45} __upunused;
46
47#define SRP_HAZARD_NUM 16
48
49struct srp_gc {
50	void			(*srp_gc_dtor)(void *, void *);
51	void			*srp_gc_cookie;
52	struct refcnt		srp_gc_refcnt;
53};
54
55#define SRP_GC_INITIALIZER(_d, _c) { (_d), (_c), REFCNT_INITIALIZER() }
56
57/*
58 * singly linked list built by following srps
59 */
60
61struct srpl_rc {
62	void			(*srpl_ref)(void *, void *);
63	struct srp_gc		srpl_gc;
64};
65#define srpl_cookie		srpl_gc.srp_gc_cookie
66
67#define SRPL_RC_INITIALIZER(_r, _u, _c) { _r, SRP_GC_INITIALIZER(_u, _c) }
68
69struct srpl {
70	struct srp		sl_head;
71};
72
73#define SRPL_HEAD(name, type)		struct srpl
74
75#define SRPL_ENTRY(type)						\
76struct {								\
77	struct srp		se_next;				\
78}
79
80#ifdef _KERNEL
81
82void		 srp_startup(void);
83void		 srp_gc_init(struct srp_gc *, void (*)(void *, void *), void *);
84void		*srp_swap_locked(struct srp *, void *);
85void		 srp_update_locked(struct srp_gc *, struct srp *, void *);
86void		*srp_get_locked(struct srp *);
87void		 srp_gc_finalize(struct srp_gc *);
88
89void		 srp_init(struct srp *);
90
91#ifdef MULTIPROCESSOR
92void		*srp_swap(struct srp *, void *);
93void		 srp_update(struct srp_gc *, struct srp *, void *);
94void		 srp_finalize(void *, const char *);
95void		*srp_enter(struct srp_ref *, struct srp *);
96void		*srp_follow(struct srp_ref *, struct srp *);
97void		 srp_leave(struct srp_ref *);
98#else /* MULTIPROCESSOR */
99
100static inline void *
101srp_enter(struct srp_ref *sr, struct srp *srp)
102{
103	sr->hz = NULL;
104	return srp->ref;
105}
106
107#define srp_swap(_srp, _v)		srp_swap_locked((_srp), (_v))
108#define srp_update(_gc, _srp, _v)	srp_update_locked((_gc), (_srp), (_v))
109#define srp_finalize(_v, _wchan)	((void)0)
110#define srp_follow(_sr, _srp)		srp_enter(_sr, _srp)
111#define srp_leave(_sr)			do { } while (0)
112#endif /* MULTIPROCESSOR */
113
114
115void		srpl_rc_init(struct srpl_rc *, void (*)(void *, void *),
116		    void (*)(void *, void *), void *);
117
118#define SRPL_INIT(_sl)			srp_init(&(_sl)->sl_head)
119
120#define SRPL_FIRST(_sr, _sl)		srp_enter((_sr), &(_sl)->sl_head)
121#define SRPL_NEXT(_sr, _e, _ENTRY)	srp_enter((_sr), &(_e)->_ENTRY.se_next)
122#define SRPL_FOLLOW(_sr, _e, _ENTRY)	srp_follow((_sr), &(_e)->_ENTRY.se_next)
123
124#define SRPL_FOREACH(_c, _sr, _sl, _ENTRY)				\
125	for ((_c) = SRPL_FIRST(_sr, _sl);				\
126	    (_c) != NULL; 						\
127	    (_c) = SRPL_FOLLOW(_sr, _c, _ENTRY))
128
129#define SRPL_LEAVE(_sr)			srp_leave((_sr))
130
131#define SRPL_FIRST_LOCKED(_sl)		srp_get_locked(&(_sl)->sl_head)
132#define SRPL_EMPTY_LOCKED(_sl)		(SRPL_FIRST_LOCKED(_sl) == NULL)
133
134#define SRPL_NEXT_LOCKED(_e, _ENTRY)					\
135	srp_get_locked(&(_e)->_ENTRY.se_next)
136
137#define SRPL_FOREACH_LOCKED(_c, _sl, _ENTRY)				\
138	for ((_c) = SRPL_FIRST_LOCKED(_sl);				\
139	    (_c) != NULL;						\
140	    (_c) = SRPL_NEXT_LOCKED((_c), _ENTRY))
141
142#define SRPL_FOREACH_SAFE_LOCKED(_c, _sl, _ENTRY, _tc)			\
143	for ((_c) = SRPL_FIRST_LOCKED(_sl);				\
144	    (_c) && ((_tc) = SRPL_NEXT_LOCKED(_c, _ENTRY), 1);		\
145	    (_c) = (_tc))
146
147#define SRPL_INSERT_HEAD_LOCKED(_rc, _sl, _e, _ENTRY) do {		\
148	void *head;							\
149									\
150	srp_init(&(_e)->_ENTRY.se_next);				\
151									\
152	head = SRPL_FIRST_LOCKED(_sl);					\
153	if (head != NULL) {						\
154		(_rc)->srpl_ref(&(_rc)->srpl_cookie, head);		\
155		srp_update_locked(&(_rc)->srpl_gc,			\
156		    &(_e)->_ENTRY.se_next, head);	 		\
157	}								\
158									\
159	(_rc)->srpl_ref(&(_rc)->srpl_cookie, _e);			\
160	srp_update_locked(&(_rc)->srpl_gc, &(_sl)->sl_head, (_e));	\
161} while (0)
162
163#define SRPL_INSERT_AFTER_LOCKED(_rc, _se, _e, _ENTRY) do {		\
164	void *next;							\
165									\
166	srp_init(&(_e)->_ENTRY.se_next);				\
167									\
168	next = SRPL_NEXT_LOCKED(_se, _ENTRY);				\
169	if (next != NULL) {						\
170		(_rc)->srpl_ref(&(_rc)->srpl_cookie, next);		\
171		srp_update_locked(&(_rc)->srpl_gc,			\
172		    &(_e)->_ENTRY.se_next, next);	 		\
173	}								\
174									\
175	(_rc)->srpl_ref(&(_rc)->srpl_cookie, _e);			\
176	srp_update_locked(&(_rc)->srpl_gc,				\
177	    &(_se)->_ENTRY.se_next, (_e));				\
178} while (0)
179
180#define SRPL_REMOVE_LOCKED(_rc, _sl, _e, _type, _ENTRY) do {		\
181	struct srp *ref;						\
182	struct _type *c, *n;						\
183									\
184	ref = &(_sl)->sl_head;						\
185	while ((c = srp_get_locked(ref)) != (_e))			\
186		ref = &c->_ENTRY.se_next;				\
187									\
188	n = SRPL_NEXT_LOCKED(c, _ENTRY);				\
189	if (n != NULL)							\
190		(_rc)->srpl_ref(&(_rc)->srpl_cookie, n);		\
191	srp_update_locked(&(_rc)->srpl_gc, ref, n);			\
192	srp_update_locked(&(_rc)->srpl_gc, &c->_ENTRY.se_next, NULL);	\
193} while (0)
194
195#endif /* _KERNEL */
196
197#endif /* _SYS_SRP_H_ */
198