Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
Aleksandr Provotorov
assignment-memory-allocator
Commits
45b6ba2a
Commit
45b6ba2a
authored
3 years ago
by
SeeMemes
Browse files
Options
Download
Email Patches
Plain Diff
v1.1
parent
9d70f919
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
182 additions
and
86 deletions
+182
-86
src/mem.c
src/mem.c
+182
-86
No files found.
src/mem.c
View file @
45b6ba2a
#include <stdarg.h>
#define _DEFAULT_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <assert.h>
#include "mem_internals.h"
#include "mem.h"
#include "util.h"
void
debug_block
(
struct
block_header
*
b
,
const
char
*
fmt
,
...
);
void
debug
(
const
char
*
fmt
,
...
);
extern
inline
block_size
size_from_capacity
(
block_capacity
cap
);
extern
inline
block_capacity
capacity_from_size
(
block_size
sz
);
void
debug
(
const
char
*
fmt
,
...);
static
bool
block_is_big_enough
(
size_t
query
,
struct
block_header
*
block
)
{
return
block
->
capacity
.
bytes
>=
query
;
}
static
size_t
pages_count
(
size_t
mem
)
{
return
mem
/
getpagesize
()
+
((
mem
%
getpagesize
())
>
0
);
}
static
size_t
round_pages
(
size_t
mem
)
{
return
getpagesize
()
*
pages_count
(
mem
)
;
}
static
void
block_init
(
void
*
restrict
addr
,
block_size
block_sz
,
void
*
restrict
next
)
{
*
((
struct
block_header
*
)
addr
)
=
(
struct
block_header
)
{
.
next
=
next
,
.
capacity
=
capacity_from_size
(
block_sz
),
.
is_free
=
true
};
}
extern
inline
block_size
size_from_capacity
(
block_capacity
cap
);
static
size_t
region_actual_size
(
size_t
query
)
{
return
size_max
(
round_pages
(
query
),
REGION_MIN_SIZE
);
}
extern
inline
block_capacity
capacity_from_size
(
block_size
sz
);
extern
inline
bool
region_is_invalid
(
const
struct
region
*
r
);
static
bool
block_is_big_enough
(
size_t
query
,
struct
block_header
*
block
)
{
return
block
->
capacity
.
bytes
>=
query
;
}
static
size_t
pages_count
(
size_t
mem
)
{
return
mem
/
getpagesize
()
+
((
mem
%
getpagesize
())
>
0
);
}
static
size_t
round_pages
(
size_t
mem
)
{
return
getpagesize
()
*
pages_count
(
mem
);
}
static
void
*
map_pages
(
void
const
*
addr
,
size_t
length
,
int
additional_flags
)
{
return
mmap
(
(
void
*
)
addr
,
length
,
PROT_READ
|
PROT_WRITE
,
MAP_PRIVATE
|
MAP_ANONYMOUS
|
additional_flags
,
0
,
0
);
static
void
block_init
(
void
*
restrict
addr
,
block_size
block_sz
,
void
*
restrict
next
)
{
*
((
struct
block_header
*
)
addr
)
=
(
struct
block_header
)
{
.
next
=
next
,
.
capacity
=
capacity_from_size
(
block_sz
),
.
is_free
=
true
};
}
/* аллоцировать регион памяти и инициализировать его блоком */
static
struct
region
alloc_region
(
void
const
*
addr
,
size_t
query
)
{
/* ??? */
}
static
size_t
region_actual_size
(
size_t
query
)
{
return
size_max
(
round_pages
(
query
),
REGION_MIN_SIZE
);
}
extern
inline
bool
region_is_invalid
(
const
struct
region
*
r
);
static
void
*
block_after
(
struct
block_header
const
*
block
)
;
void
*
heap_init
(
size_t
initial
)
{
const
struct
region
region
=
alloc_region
(
HEAP_START
,
initial
);
if
(
region_is_invalid
(
&
region
)
)
return
NULL
;
void
*
map_pages
(
void
const
*
addr
,
size_t
length
,
int
additional_flags
)
{
return
mmap
((
void
*
)
addr
,
length
,
PROT_READ
|
PROT_WRITE
,
MAP_PRIVATE
|
MAP_ANONYMOUS
|
additional_flags
,
0
,
0
);
}
return
region
.
addr
;
/* аллоцировать регион памяти и инициализировать его блоком */
static
struct
region
alloc_region
(
void
const
*
addr
,
size_t
query
)
{
struct
region
reg
;
query
=
region_actual_size
(
query
);
void
*
reg_addr
=
map_pages
(
addr
,
query
,
MAP_FIXED_NOREPLACE
);
if
(
reg_addr
==
MAP_FAILED
)
{
reg_addr
=
map_pages
(
addr
,
query
,
0
);
reg
=
(
struct
region
)
{
reg_addr
,
query
,
false
};
}
else
{
reg
=
(
struct
region
)
{
reg_addr
,
query
,
false
};
}
block_init
(
reg_addr
,
(
block_size
)
{
query
},
NULL
);
return
reg
;
}
static
void
*
block_after
(
struct
block_header
const
*
block
);
void
*
heap_init
(
size_t
initial
)
{
const
struct
region
region
=
alloc_region
(
HEAP_START
,
initial
);
if
(
region_is_invalid
(
&
region
))
return
NULL
;
return
region
.
addr
;
}
#define BLOCK_MIN_CAPACITY 24
/* --- Разделение блоков (если найденный свободный блок слишком большой )--- */
static
bool
block_splittable
(
struct
block_header
*
restrict
block
,
size_t
query
)
{
return
block
->
is_free
&&
query
+
offsetof
(
struct
block_header
,
contents
)
+
BLOCK_MIN_CAPACITY
<=
block
->
capacity
.
bytes
;
static
bool
block_splittable
(
struct
block_header
*
restrict
block
,
size_t
query
)
{
return
block
->
is_free
&&
query
+
offsetof
(
struct
block_header
,
contents
)
+
BLOCK_MIN_CAPACITY
<=
block
->
capacity
.
bytes
;
}
static
bool
split_if_too_big
(
struct
block_header
*
block
,
size_t
query
)
{
/* ??? */
static
bool
split_if_too_big
(
struct
block_header
*
block
,
size_t
query
)
{
if
(
block_splittable
(
block
,
query
))
{
void
*
new_block
=
(
void
*
)
((
uint8_t
*
)
block
+
offsetof
(
struct
block_header
,
contents
)
+
query
);
block_init
(
new_block
,
(
block_size
)
{
block
->
capacity
.
bytes
-
query
},
NULL
);
block
->
next
=
new_block
;
block
->
capacity
.
bytes
=
query
;
return
true
;
}
return
false
;
}
/* --- Слияние соседних свободных блоков --- */
static
void
*
block_after
(
struct
block_header
const
*
block
)
{
return
(
void
*
)
(
block
->
contents
+
block
->
capacity
.
bytes
);
}
static
bool
blocks_continuous
(
struct
block_header
const
*
fst
,
struct
block_header
const
*
snd
)
{
return
(
void
*
)
snd
==
block_after
(
fst
);
static
void
*
block_after
(
struct
block_header
const
*
block
)
{
return
(
void
*
)
(
block
->
contents
+
block
->
capacity
.
bytes
);
}
static
bool
mergeable
(
struct
block_header
const
*
restrict
fst
,
struct
block_header
const
*
restrict
snd
)
{
return
fst
->
is_free
&&
snd
->
is_free
&&
blocks_continuous
(
fst
,
snd
)
;
static
bool
blocks_continuous
(
struct
block_header
const
*
fst
,
struct
block_header
const
*
snd
)
{
return
(
void
*
)
snd
==
block_after
(
fst
);
}
static
bool
try_merge_with_next
(
struct
block_header
*
block
)
{
/* ??? */
static
bool
mergeable
(
struct
block_header
const
*
restrict
fst
,
struct
block_header
const
*
restrict
snd
)
{
return
fst
->
is_free
&&
snd
->
is_free
&&
blocks_continuous
(
fst
,
snd
);
}
static
bool
try_merge_with_next
(
struct
block_header
*
block
)
{
struct
block_header
*
block_next
=
block
->
next
;
if
(
block_next
!=
NULL
&&
mergeable
(
block
,
block_next
))
{
block
->
next
=
block_next
->
next
;
block
->
capacity
.
bytes
+=
size_from_capacity
(
block_next
->
capacity
).
bytes
;
return
true
;
}
return
false
;
}
/* --- ... ecли размера кучи хватает --- */
struct
block_search_result
{
enum
{
BSR_FOUND_GOOD_BLOCK
,
BSR_REACHED_END_NOT_FOUND
,
BSR_CORRUPTED
}
type
;
struct
block_header
*
block
;
struct
block_search_result
{
enum
{
BSR_FOUND_GOOD_BLOCK
,
BSR_REACHED_END_NOT_FOUND
,
BSR_CORRUPTED
}
type
;
struct
block_header
*
block
;
};
static
struct
block_search_result
find_good_or_last
(
struct
block_header
*
restrict
block
,
size_t
sz
)
{
/*??? */
static
struct
block_search_result
find_good_or_last
(
struct
block_header
*
restrict
block
,
size_t
sz
)
{
struct
block_header
*
block_current
=
block
;
struct
block_header
*
block_last
=
block
;
while
(
block_current
!=
NULL
)
{
while
(
block_current
->
is_free
&&
(
block_is_big_enough
(
sz
,
block_current
)
||
try_merge_with_next
(
block_current
)))
{
if
(
block_is_big_enough
(
sz
,
block_current
))
{
return
(
struct
block_search_result
)
{.
type
=
BSR_FOUND_GOOD_BLOCK
,
.
block
=
block_current
};
}
}
block_last
=
block_current
;
block_current
=
block_current
->
next
;
}
return
(
struct
block_search_result
)
{.
type
=
BSR_REACHED_END_NOT_FOUND
,
.
block
=
block_last
};
}
/* Попробовать выделить память в куче начиная с блока `block` не пытаясь расширить кучу
Можно переиспользовать как только кучу расширили. */
static
struct
block_search_result
try_memalloc_existing
(
size_t
query
,
struct
block_header
*
block
)
{
}
static
struct
block_header
*
grow_heap
(
struct
block_header
*
restrict
last
,
size_t
query
)
{
/* ??? */
static
struct
block_search_result
try_memalloc_existing
(
size_t
query
,
struct
block_header
*
block
)
{
struct
block_search_result
res
=
find_good_or_last
(
block
,
query
);
if
(
res
.
type
==
BSR_FOUND_GOOD_BLOCK
)
{
split_if_too_big
(
res
.
block
,
query
);
}
return
res
;
}
static
struct
block_header
*
grow_heap
(
struct
block_header
*
restrict
last
,
size_t
query
)
{
block_size
size
=
size_from_capacity
(
last
->
capacity
);
void
*
new_heap_addr
=
(
void
*
)
((
uint8_t
*
)
last
+
size
.
bytes
);
struct
region
new_region
=
alloc_region
(
new_heap_addr
,
query
);
assert
(
new_region
.
addr
!=
NULL
&&
"region creation failed"
);
block_init
(
new_region
.
addr
,
(
block_size
)
{
new_region
.
size
},
NULL
);
last
->
next
=
(
struct
block_header
*
)
new_region
.
addr
;
if
(
try_merge_with_next
(
last
))
{
return
last
;
}
else
{
return
last
->
next
;
}
}
/* Реализует основную логику malloc и возвращает заголовок выделенного блока */
static
struct
block_header
*
memalloc
(
size_t
query
,
struct
block_header
*
heap_start
)
{
/* ??? */
}
void
*
_malloc
(
size_t
query
)
{
struct
block_header
*
const
addr
=
memalloc
(
query
,
(
struct
block_header
*
)
HEAP_START
);
if
(
addr
)
return
addr
->
contents
;
else
return
NULL
;
}
static
struct
block_header
*
block_get_header
(
void
*
contents
)
{
return
(
struct
block_header
*
)
(((
uint8_t
*
)
contents
)
-
offsetof
(
struct
block_header
,
contents
));
}
void
_free
(
void
*
mem
)
{
if
(
!
mem
)
return
;
struct
block_header
*
header
=
block_get_header
(
mem
);
header
->
is_free
=
true
;
/* ??? */
}
static
struct
block_header
*
memalloc
(
size_t
query
,
struct
block_header
*
heap_start
)
{
query
=
size_max
(
query
,
BLOCK_MIN_CAPACITY
);
struct
block_search_result
res
=
try_memalloc_existing
(
query
,
heap_start
);
switch
(
res
.
type
)
{
case
BSR_REACHED_END_NOT_FOUND
:
res
.
block
=
grow_heap
(
res
.
block
,
query
);
split_if_too_big
(
res
.
block
,
query
);
break
;
case
BSR_FOUND_GOOD_BLOCK
:
break
;
case
BSR_CORRUPTED
:
err
(
"Блок повреждён"
);
return
NULL
;
}
res
.
block
->
is_free
=
false
;
return
res
.
block
;
}
void
*
_malloc
(
size_t
query
)
{
struct
block_header
*
const
addr
=
memalloc
(
query
,
(
struct
block_header
*
)
HEAP_START
);
if
(
addr
)
return
addr
->
contents
;
else
return
NULL
;
}
static
struct
block_header
*
block_get_header
(
void
*
contents
)
{
return
(
struct
block_header
*
)
(((
uint8_t
*
)
contents
)
-
offsetof
(
struct
block_header
,
contents
));
}
void
_free
(
void
*
mem
)
{
if
(
!
mem
)
return
;
struct
block_header
*
header
=
block_get_header
(
mem
);
if
(
header
->
is_free
!=
true
)
{
header
->
is_free
=
true
;
while
(
try_merge_with_next
(
header
));
}
}
\ No newline at end of file
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment