1/* @title: Fixed Size Allocation */
2#pragma once
3#include <compiler.h>
4#include <mem/alloc.h>
5#include <mem/page.h>
6#include <smp/perdomain.h>
7#include <structures/list.h>
8#include <sync/spinlock.h>
9
10/* Number of fully-empty freelist backing pages to keep cached per local tree
11 * before reclaiming on free
12 *
13 * Provides hysteresis so a workload that oscillates across a page boundary
14 * does not pmm_alloc/pmm_free on every transition */
15#define FIXED_SIZE_KEEP_EMPTY_PAGES 1
16
17/* The idea here:
18 *
19 * memory is laid out as
20 *
21 * [ data ] [ potential empty ] [ fixed_size_node ]
22 *
23 * essentially, the objects have their own alignment, so each
24 * of these "full nodes" comes with the data first, then the
25 * empty zone. the fixed size node trails to link it all up
26 */
27struct fixed_size_node {
28 struct list_head list_node;
29};
30static_assert(offsetof(struct fixed_size_node, list_node) == 0);
31
32struct fixed_size_page_hdr {
33 ssize_t domain; /* -1 means it isn't perdomain */
34 size_t free_count;
35 size_t total;
36 struct list_head page_list;
37};
38
39struct fixed_size_range_attributes {
40 size_t obj_size;
41 size_t obj_align;
42 void (*init_obj)(void *);
43 void (*deinit_obj)(void *);
44 bool bootstrap_mode : 1;
45};
46
47struct fixed_size_range {
48 struct fixed_size_range_attributes attrs;
49 struct spinlock lock;
50 struct list_head freelist;
51 struct list_head fl_pages;
52 size_t empty_pages;
53 size_t full_node_size; /* node size + object size */
54 struct fixed_size_range **perdomain_fsrs;
55 ssize_t domain;
56};
57
58static_assert(sizeof(struct fixed_size_range) < PAGE_SIZE);
59
60void *fixed_size_alloc(struct fixed_size_range *fsr);
61void fixed_size_free(struct fixed_size_range *fsr, void *obj);
62void fixed_size_reclaim_freelist_pages(struct fixed_size_range *fsr);
63struct fixed_size_range *
64fixed_size_range_create(struct fixed_size_range_attributes *attrs);
65void fixed_size_range_init(struct fixed_size_range *fsr,
66 struct fixed_size_range_attributes *attrs);
67
68#define FIXED_SIZE_RANGE_PERDOMAIN_DECLARE(name, ...) \
69 static void __##name##_fsr_init(struct fixed_size_range *__fsr, \
70 size_t __domain) { \
71 (void) __domain; \
72 static struct fixed_size_range **__perdomain_fsrs_##name = NULL; \
73 if (!__perdomain_fsrs_##name) \
74 __perdomain_fsrs_##name = kmalloc( \
75 sizeof(struct fixed_size_range *) * global.domain_count); \
76 \
77 struct fixed_size_range_attributes __attrs = {__VA_ARGS__}; \
78 fixed_size_range_init(__fsr, &__attrs); \
79 __perdomain_fsrs_##name[__domain] = __fsr; \
80 __fsr->perdomain_fsrs = __perdomain_fsrs_##name; \
81 __fsr->domain = __domain; \
82 } \
83 PERDOMAIN_DECLARE(__##name##_fsr, struct fixed_size_range, \
84 __##name##_fsr_init)
85
86#define FSR_PERDOMAIN_THIS(name) PERDOMAIN_PTR(__##name##_fsr)
87#define FSR_PERDOMAIN_ALLOC(name) fixed_size_alloc(FSR_PERDOMAIN_THIS(name))
88#define FSR_PERDOMAIN_FREE(name, obj) \
89 fixed_size_free(FSR_PERDOMAIN_THIS(name), (obj))
90