summaryrefslogtreecommitdiff
path: root/src/include/utils/mspan.h
blob: 6c33dcf3877bc2b3a96b434a60c68daa6861421b (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
/*-------------------------------------------------------------------------
 *
 * mspan.h
 *	  Memory span management.
 *
 * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/utils/mspan.h
 *
 *-------------------------------------------------------------------------
 */

#ifndef MSPAN_H
#define MSPAN_H

#include "utils/aspace_map.h"

/*
 * Relative pointers.
 *
 * These are intended to be used when storing an address that may be
 * relative either to the base of the processes address space or some
 * dynamic shared memory segment mapped therein.
 *
 * The idea here is that you declare a relative pointer as relptr(type)
 * and then use relptr_access to dereference it and relptr_store to change
 * it.  The use of a union here is a hack, because what's stored in the
 * relptr is always a Size, never an actual pointer.  But including a pointer
 * in the union allows us to use stupid macro tricks to provide some measure
 * of type-safety.
 */
#define relptr(type)     union { type *relptr_type; Size relptr_off; }
#define relptr_access(base, rp) \
	(AssertVariableIsOfTypeMacro(base, char *), \
	 (__typeof__((rp).relptr_type)) ((rp).relptr_off == 0 ? NULL : \
		(base + (rp).relptr_off)))
#define relptr_is_null(rp) \
	((rp).relptr_off == 0)
#define relptr_store(base, rp, val) \
	(AssertVariableIsOfTypeMacro(base, char *), \
	 AssertVariableIsOfTypeMacro(val, __typeof__((rp).relptr_type)), \
	 (rp).relptr_off = ((val) == NULL ? 0 : ((char *) (val)) - (base)))

/*
 * Flags that can be associated with memory allocations.
 */
#define MSPAN_ALLOW_HUGE		0x0001		/* allow allocations > 1 GB */
#define MSPAN_SOFT_FAIL			0x0002		/* return NULL on failure */

/*
 * Large objects - and the superblocks used to satisfy smaller allocations -
 * are allocated from free lists.  Each free list except the last holds
 * available spans of one particular size; the final free list holds all
 * the remaining ones.
 */
#define MSPAN_NUM_FREE_LISTS				256

/* Forward declarations. */
struct mspan;
struct mspan_context;
struct mspan_manager;
typedef struct mspan mspan;
typedef struct mspan_context mspan_context;
typedef struct mspan_manager mspan_manager;

/*
 * One mspan_manager is needed for each allocation space.  This means that
 * we have one for our own address space, which is stored in a static variable;
 * and one for each dynamic shared memory segment in which we want to use
 * this facility, which should be stored within that segment.
 */
struct mspan_manager
{
	Size		npages;		/* # of managed pages in dsm; 0 for private */
	Size		base;		/* offset of page 0 within dsm; 0 for private */
	Size		boundary;	/* first unallocated page in dsm; 0 for private */
	Size		ncontexts;	/* # of outstanding contexts */
	Size		nsyschunks;	/* # of chunks allocated from OS */
	relptr(mspan) span_of_spans;	/* superblock for span descriptors */
	relptr(mspan_context) freecontext;	/* allocatable context object */
	aspace_map	page_map;	/* map pages to mspans */
	relptr(mspan) freelist[MSPAN_NUM_FREE_LISTS]; /* spans for freespace */
};

/* Manager for backend-private address space. */
extern mspan_manager private_mspan_manager;

/* Initialization a manager in private or dynamic shared memory. */
extern void mspan_initialize_private_manager(mspan_manager *);
extern mspan_manager *mspan_initialize_dsm_manager(dsm_segment *,
							 void *, Size nbytes);

/* Create or destroy a memory context. */
extern mspan_context *mspan_context_create(dsm_segment *, mspan_manager *);
extern void mspan_context_destroy(dsm_segment *, mspan_context *);

/* Allocate or free memory. */
extern void *mspan_alloc(dsm_segment *, mspan_context *, Size size, int flags);
extern void *mspan_free(dsm_segment *, void *);

#endif