aboutsummaryrefslogtreecommitdiff
path: root/lib/libc/include/generic-netbsd/sys/pool.h
blob: f7bd94246dd64d62b8e66f3e14a31a49562e3dd8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
/*	$NetBSD: pool.h,v 1.96 2021/12/22 16:57:28 thorpej Exp $	*/

/*-
 * Copyright (c) 1997, 1998, 1999, 2000, 2007, 2020
 *     The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Paul Kranenburg; by Jason R. Thorpe of the Numerical Aerospace
 * Simulation Facility, NASA Ames Research Center.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _SYS_POOL_H_
#define _SYS_POOL_H_

#include <sys/stdbool.h>
#include <sys/stdint.h>

struct pool_sysctl {
	char pr_wchan[16];
	uint64_t pr_flags;
	uint64_t pr_size;
	uint64_t pr_pagesize;
	uint64_t pr_itemsperpage;
	uint64_t pr_nitems;
	uint64_t pr_nout;
	uint64_t pr_hardlimit;
	uint64_t pr_npages;
	uint64_t pr_minpages;
	uint64_t pr_maxpages;

	uint64_t pr_nget;
	uint64_t pr_nfail;
	uint64_t pr_nput;
	uint64_t pr_npagealloc;
	uint64_t pr_npagefree;
	uint64_t pr_hiwat;
	uint64_t pr_nidle;

	uint64_t pr_cache_meta_size;
	uint64_t pr_cache_nfull;
	uint64_t pr_cache_npartial;
	uint64_t pr_cache_nempty;
	uint64_t pr_cache_ncontended;
	uint64_t pr_cache_nmiss_global;
	uint64_t pr_cache_nhit_global;
	uint64_t pr_cache_nmiss_pcpu;
	uint64_t pr_cache_nhit_pcpu;
};

#ifdef _KERNEL
#define __POOL_EXPOSE
#endif

#ifdef __POOL_EXPOSE
#include <sys/param.h>
#include <sys/mutex.h>
#include <sys/condvar.h>
#include <sys/queue.h>
#include <sys/time.h>
#include <sys/tree.h>
#include <sys/callback.h>

#ifdef _KERNEL_OPT
#include "opt_pool.h"
#endif

#define POOL_PADDR_INVALID	((paddr_t) -1)

struct pool;

struct pool_allocator {
	void		*(*pa_alloc)(struct pool *, int);
	void		(*pa_free)(struct pool *, void *);
	unsigned int	pa_pagesz;

	/* The following fields are for internal use only. */
	kmutex_t	pa_lock;
	TAILQ_HEAD(, pool) pa_list;	/* list of pools using this allocator */
	uint32_t	pa_refcnt;	/* number of pools using this allocator */
	int		pa_pagemask;
	int		pa_pageshift;
};

LIST_HEAD(pool_pagelist,pool_item_header);
SPLAY_HEAD(phtree, pool_item_header);

#define POOL_QUARANTINE_DEPTH	128
typedef struct {
	size_t rotor;
	intptr_t list[POOL_QUARANTINE_DEPTH];
} pool_quar_t;

struct pool {
	TAILQ_ENTRY(pool)
			pr_poollist;
	struct pool_pagelist
			pr_emptypages;	/* Empty pages */
	struct pool_pagelist
			pr_fullpages;	/* Full pages */
	struct pool_pagelist
			pr_partpages;	/* Partially-allocated pages */
	struct pool_item_header	*pr_curpage;
	struct pool	*pr_phpool;	/* Pool item header pool */
	struct pool_cache *pr_cache;	/* Cache for this pool */
	unsigned int	pr_size;	/* Size of item */
	unsigned int	pr_align;	/* Requested alignment, must be 2^n */
	unsigned int	pr_itemoffset;	/* offset of the item space */
	unsigned int	pr_minitems;	/* minimum # of free items to keep */
	unsigned int	pr_maxitems;	/* maximum # of free items to keep */
	unsigned int	pr_minpages;	/* minimum # of pages to keep */
	unsigned int	pr_maxpages;	/* maximum # of pages to keep */
	unsigned int	pr_npages;	/* # of pages allocated */
	unsigned int	pr_itemsperpage;/* # items that fit in a page */
	unsigned int	pr_poolid;	/* id of the pool */
	unsigned int	pr_nitems;	/* number of free items in pool */
	unsigned int	pr_nout;	/* # items currently allocated */
	unsigned int	pr_hardlimit;	/* hard limit to number of allocated
					   items */
	unsigned int	pr_refcnt;	/* ref count for pagedaemon, etc */
	struct pool_allocator *pr_alloc;/* back-end allocator */
	TAILQ_ENTRY(pool) pr_alloc_list;/* link on allocator's pool list */

	/* Drain hook. */
	void		(*pr_drain_hook)(void *, int);
	void		*pr_drain_hook_arg;

	const char	*pr_wchan;	/* tsleep(9) identifier */
	unsigned int	pr_flags;	/* r/w flags */
	unsigned int	pr_roflags;	/* r/o flags */
#define PR_WAITOK	0x01	/* Note: matches KM_SLEEP */
#define PR_NOWAIT	0x02	/* Note: matches KM_NOSLEEP */
#define PR_WANTED	0x04	/* waiting for free objects */
#define PR_PHINPAGE	0x40	/* page header in page */
#define PR_LIMITFAIL	0x100	/* even if waiting, fail if we hit limit */
#define PR_RECURSIVE	0x200	/* pool contains pools, for vmstat(8) */
#define PR_NOTOUCH	0x400	/* don't use free items to keep internal state*/
#define PR_NOALIGN	0x800	/* don't assume backend alignment */
#define PR_LARGECACHE	0x1000	/* use large cache groups */
#define PR_GROWING	0x2000	/* pool_grow in progress */
#define PR_GROWINGNOWAIT 0x4000	/* pool_grow in progress by PR_NOWAIT alloc */
#define PR_ZERO		0x8000	/* zero data before returning */
#define PR_USEBMAP	0x10000	/* use a bitmap to manage freed items */
#define PR_PSERIALIZE	0x20000	/* needs pserialize sync point before free */

	/*
	 * `pr_lock' protects the pool's data structures when removing
	 * items from or returning items to the pool, or when reading
	 * or updating read/write fields in the pool descriptor.
	 *
	 * We assume back-end page allocators provide their own locking
	 * scheme.  They will be called with the pool descriptor _unlocked_,
	 * since the page allocators may block.
	 */
	kmutex_t	pr_lock;
	kcondvar_t	pr_cv;
	int		pr_ipl;

	struct phtree	pr_phtree;

	int		pr_maxcolor;	/* Cache colouring */
	int		pr_curcolor;
	int		pr_phoffset;	/* unused */

	/*
	 * Warning message to be issued, and a per-time-delta rate cap,
	 * if the hard limit is reached.
	 */
	const char	*pr_hardlimit_warning;
	struct timeval	pr_hardlimit_ratecap;
	struct timeval	pr_hardlimit_warning_last;

	/*
	 * Instrumentation
	 */
	unsigned long	pr_nget;	/* # of successful requests */
	unsigned long	pr_nfail;	/* # of unsuccessful requests */
	unsigned long	pr_nput;	/* # of releases */
	unsigned long	pr_npagealloc;	/* # of pages allocated */
	unsigned long	pr_npagefree;	/* # of pages released */
	unsigned int	pr_hiwat;	/* max # of pages in pool */
	unsigned long	pr_nidle;	/* # of idle pages */

	/*
	 * Diagnostic aides.
	 */
	void		*pr_freecheck;
	void		*pr_qcache;
	bool		pr_redzone;
	size_t		pr_reqsize;
	size_t		pr_reqsize_with_redzone;
#ifdef POOL_QUARANTINE
	pool_quar_t	pr_quar;
#endif
};

/*
 * Cache group sizes, assuming 4-byte paddr_t on !_LP64.
 * All groups will be aligned to COHERENCY_UNIT.
 */
#ifdef _LP64
#define PCG_NOBJECTS_NORMAL	15	/* 256 byte group */
#define PCG_NOBJECTS_LARGE	63	/* 1024 byte group */
#else
#define PCG_NOBJECTS_NORMAL	14	/* 124 byte group */
#define PCG_NOBJECTS_LARGE	62	/* 508 byte group */
#endif

typedef struct pcgpair {
	void	*pcgo_va;		/* object virtual address */
	paddr_t	pcgo_pa;		/* object physical address */
} pcgpair_t;

/* The pool cache group. */
typedef struct pool_cache_group {
	struct pool_cache_group	*pcg_next;	/* link to next group */
	u_int			pcg_avail;	/* # available objects */
	u_int			pcg_size;	/* max number objects */
	pcgpair_t 		pcg_objects[1];	/* the objects */
} pcg_t;

/* Pool cache CPU.  Sized to 64 bytes on _LP64. */
typedef struct pool_cache_cpu {
	struct pool_cache_group	*cc_current;
	struct pool_cache_group	*cc_previous;	
	pcg_t *volatile 	*cc_pcgcache;
	uint64_t		cc_misses;
	uint64_t		cc_hits;
	uint64_t		cc_pcmisses;
	uint64_t		cc_contended;
	uint32_t		cc_nfull;
	uint32_t		cc_npart;
} pool_cache_cpu_t;

struct pool_cache {
	/* Pool layer. */
	struct pool	pc_pool;
	
	/* Cache layer. */
	TAILQ_ENTRY(pool_cache)
			pc_cachelist;	/* entry on global cache list */
	struct pool	*pc_pcgpool;	/* Pool of cache groups */
	pcg_t *volatile *pc_pcgcache;	/* list of empty cache groups */
	int		pc_pcgsize;	/* Use large cache groups? */
	int		pc_ncpu;	/* number cpus set up */
	int		(*pc_ctor)(void *, void *, int);
	void		(*pc_dtor)(void *, void *);
	void		*pc_arg;	/* for ctor/dtor */
	unsigned int	pc_refcnt;	/* ref count for pagedaemon, etc */
	unsigned int	pc_roflags;	/* r/o cache flags */
	void		*pc_cpus[MAXCPUS];

	/* Diagnostic aides. */
	void		*pc_freecheck;
	bool		pc_redzone;
	size_t		pc_reqsize;

	/* Hot items. */
	pcg_t *volatile pc_fullgroups	/* list of full cache groups */
	    __aligned(CACHE_LINE_SIZE);
	pcg_t *volatile pc_partgroups;	/* groups for reclamation */

	/* Boot cpu. */
	pool_cache_cpu_t pc_cpu0 __aligned(CACHE_LINE_SIZE);
};

#endif /* __POOL_EXPOSE */

typedef struct pool_cache *pool_cache_t;

#ifdef _KERNEL
/*
 * pool_allocator_kmem is the default that all pools get unless
 * otherwise specified.  pool_allocator_nointr is provided for
 * pools that know they will never be accessed in interrupt
 * context.
 */
extern struct pool_allocator pool_allocator_kmem;
extern struct pool_allocator pool_allocator_nointr;
extern struct pool_allocator pool_allocator_meta;

void		pool_subsystem_init(void);

void		pool_init(struct pool *, size_t, u_int, u_int,
		    int, const char *, struct pool_allocator *, int);
void		pool_destroy(struct pool *);

void		pool_set_drain_hook(struct pool *,
		    void (*)(void *, int), void *);

void		*pool_get(struct pool *, int);
void		pool_put(struct pool *, void *);
int		pool_reclaim(struct pool *);

void		pool_prime(struct pool *, int);
void		pool_setlowat(struct pool *, int);
void		pool_sethiwat(struct pool *, int);
void		pool_sethardlimit(struct pool *, int, const char *, int);
bool		pool_drain(struct pool **);
int		pool_totalpages(void);
int		pool_totalpages_locked(void);

unsigned int	pool_nget(struct pool *);
unsigned int	pool_nput(struct pool *);

/*
 * Debugging and diagnostic aides.
 */
void		pool_printit(struct pool *, const char *,
    void (*)(const char *, ...) __printflike(1, 2));
void		pool_printall(const char *, void (*)(const char *, ...)
    __printflike(1, 2));
int		pool_chk(struct pool *, const char *);

/*
 * Pool cache routines.
 */
pool_cache_t	pool_cache_init(size_t, u_int, u_int, u_int, const char *,
		    struct pool_allocator *, int, int (*)(void *, void *, int),
		    void (*)(void *, void *), void *);
void		pool_cache_bootstrap(pool_cache_t, size_t, u_int, u_int, u_int,
		    const char *, struct pool_allocator *, int,
		    int (*)(void *, void *, int), void (*)(void *, void *),
		    void *);
void		pool_cache_destroy(pool_cache_t);
void		pool_cache_bootstrap_destroy(pool_cache_t);
void		*pool_cache_get_paddr(pool_cache_t, int, paddr_t *);
void		pool_cache_put_paddr(pool_cache_t, void *, paddr_t);
void		pool_cache_destruct_object(pool_cache_t, void *);
void		pool_cache_invalidate(pool_cache_t);
bool		pool_cache_reclaim(pool_cache_t);
void		pool_cache_set_drain_hook(pool_cache_t,
		    void (*)(void *, int), void *);
void		pool_cache_setlowat(pool_cache_t, int);
void		pool_cache_sethiwat(pool_cache_t, int);
void		pool_cache_sethardlimit(pool_cache_t, int, const char *, int);
void		pool_cache_prime(pool_cache_t, int);
void		pool_cache_cpu_init(struct cpu_info *);

unsigned int	pool_cache_nget(pool_cache_t);
unsigned int	pool_cache_nput(pool_cache_t);

#define		pool_cache_get(pc, f) pool_cache_get_paddr((pc), (f), NULL)
#define		pool_cache_put(pc, o) pool_cache_put_paddr((pc), (o), \
				          POOL_PADDR_INVALID)

void		pool_whatis(uintptr_t, void (*)(const char *, ...)
    __printflike(1, 2));
#endif /* _KERNEL */

#endif /* _SYS_POOL_H_ */