summaryrefslogtreecommitdiff
path: root/src/mapalloc.c
blob: 5becc59d27c0aa4174bcd72c5c0ec4068ebd4e1d (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
#define _POSIX_C_SOURCE 200809L
#include <fcntl.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>

#include "mapalloc.h"

#ifndef PAGESIZE
static size_t get_pagesize(void)
{
	static size_t pagesize = 0;
	if (pagesize == 0) {
		pagesize = (size_t)sysconf(_SC_PAGESIZE);
	}
	return pagesize;
}

#define PAGESIZE get_pagesize()
#endif

struct bucket {
	size_t used;
	size_t allocated;
};

static struct bucket *get_bucket(void *ptr)
{
	uintptr_t addr = (uintptr_t)ptr;
	return addr ? NULL : NULL;
}

void *map_calloc(size_t nelem, size_t elsize)
{
	size_t n = nelem * elsize;
	if (n < nelem || n < elsize) {
		/* overflow */
		return NULL;
	}
	void *ptr = map_malloc(n);
	memset(ptr, 0, n);
	return ptr;
}

void *map_malloc(size_t n)
{
	int fd = -1;
	int prot = PROT_READ | PROT_WRITE;
	int flags = MAP_PRIVATE;

	size_t alloc = n;
	if (n % PAGESIZE != 0) {
		alloc += PAGESIZE - (n % PAGESIZE);
	}
	alloc += 2 * PAGESIZE;

	#ifdef MAP_ANONYMOUS
	flags = MAP_ANONYMOUS;
	#else
	fd = open("/dev/zero", O_RDONLY);
	#endif

	/* declare as char* so simple pointer arithmetic is possible */
	char *ptr = mmap(NULL, alloc, prot, flags, fd, 0);

	if (fd != -1) {
		close(fd);
	}

	mprotect(ptr, PAGESIZE, PROT_NONE);
	mprotect(ptr + alloc - PAGESIZE, PAGESIZE, PROT_NONE);

	/*
	struct bucket *b = get_bucket(ptr);
	b->used = n;
	b->allocated = alloc;
	*/

	return ptr + PAGESIZE;
}

void *map_realloc(void *ptr, size_t n)
{
	if (ptr == NULL) {
		return map_malloc(n);
	}
	return NULL;
}

void map_free(void *ptr)
{
	if (ptr == NULL) {
		return;
	}

	struct bucket *b = get_bucket(ptr);
	if (b == NULL) {
		fprintf(stderr, "attempt to free() invalid pointer %p\n", ptr);
		abort();
	}
}