-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpalloc.c
More file actions
188 lines (173 loc) · 5.71 KB
/
palloc.c
File metadata and controls
188 lines (173 loc) · 5.71 KB
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
#include <unistd.h>
#include <pthread.h>
typedef char ALIGN[16];
union header{
struct header_t{
size_t size;
unsigned is_free;
struct header_t *next;
} s;
/* force the header to wrap to 16 bytes */
ALIGN stub;
};
typedef union header header_t;
header_t *head, *tail;
pthread_mutex_t global_palloc_lock;
void *palloc(size_t size){
/**
* Allocates a block of memory of the specified size and returns a pointer to the beginning of the block.
* The content of the newly allocated memory is not initialized, it contains garbage values.
*
* @param size The size of the memory block to allocate in bytes.
* @return A pointer to the allocated memory block, or NULL if the allocation fails.
*
* Example usage:
* @code
* int *array = (int *)palloc(10 * sizeof(int));
* if (array == NULL) {
* // Handle memory allocation failure
* }
* @endcode
*
* Note:
* - Always check if the returned pointer is NULL to ensure that the memory allocation was successful.
* - The allocated memory should be freed using the free() function to avoid memory leaks.
*/
size_t total_size;
void *block;
header_t *header;
if(!size)
return NULL;
pthread_mutex_lock(&global_palloc_lock);
header = get_free_block(size);
if(header){
header->s.is_free = 0;
pthread_mutex_unlock(&global_palloc_lock);
return (void*)(header + 1); //return the address after the header (so that the header remains hidden to end user)
}
total_size = sizeof(header_t) + size;
block = sbrk(total_size);
if(block == (void*)-1){
pthread_mutex_unlock(&global_palloc_lock);
return NULL;
}
header = block;
header->s.size = size;
header->s.is_free = 0;
header->s.next = NULL;
if (!head)
head = header;
if (tail)
tail->s.next = header;
tail = header;
pthread_mutex_unlock(&global_palloc_lock);
return (void*)(header + 1);
}
header_t *get_free_block(size_t size){
header_t *curr = head;
while(curr){
if(curr->s.is_free && curr->s.size >= size)
return curr;
curr = curr->s.next;
}
return NULL;
}
void pfree(void *block){
/**
* @brief Frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc(), or realloc().
*
* This function deallocates the memory previously allocated by a memory allocation function. If ptr is NULL, no operation is performed.
*
* @param block Pointer to the memory block to be freed.
*/
header_t *header, *tmp;
void *prgbreak;
if(!block)
return;
pthread_mutex_lock(&global_palloc_lock);
header = (header_t*)block - 1; //obtain the header of the block
prgbreak = sbrk(0);
if((char*)block + header->s.size == prgbreak){
if(head == tail){
head = tail = NULL;
} else {
tmp = head;
while(tmp){
if(tmp->s.next == tail){
tmp->s.next = NULL;
tail = tmp;
}
tmp = tmp->s.next;
}
}
sbrk(0 - sizeof(header_t) - header->s.size); //sbrk(-total_size) to free the block
pthread_mutex_unlock(&global_palloc_lock);
return;
}
header->s.is_free = 1;
pthread_mutex_unlock(&global_palloc_lock);
}
void *pcalloc(size_t num, size_t nsize){
/**
* Allocates memory for an array of `num` elements of `size` bytes each and
* initializes all bytes in the allocated storage to zero.
*
* @param num The number of elements to allocate.
* @param nsize The size of each element in bytes.
* @return A pointer to the allocated memory, or NULL if the allocation fails.
*
* The `calloc` function allocates memory for an array of `num` elements, each
* of `size` bytes, and initializes all bytes in the allocated memory to zero.
* If the allocation fails, it returns NULL.
*
* Example usage:
* @code
* int *arr = (int *)pcalloc(10, sizeof(int));
* if (arr == NULL) {
* // Handle allocation failure
* }
* @endcode
*/
size_t size;
void *block;
if(!num || !nsize)
return NULL;
size = num * nsize;
/* check for integer overflow*/
if(nsize != size / num)
return NULL;
block = palloc(size);
if(!block)
return NULL;
memset(block, 0, size); //init all bytes to 0
return block;
}
void *prealloc(void *block, size_t size){
/**
* Reallocates memory for an array of elements.
*
* @param block A pointer to the memory block previously allocated with palloc, pcalloc, or prealloc.
* If this is NULL, the function behaves like palloc.
* @param size The new size for the memory block, in bytes.
* If this is 0 and ptr is not NULL, the memory block is freed.
* @return A pointer to the newly allocated memory, which may be different from ptr.
* If the function fails to allocate the requested block of memory, a NULL pointer is returned,
* and the original block of memory is left untouched.
*
* @note The contents of the memory block are unchanged up to the lesser of the new and old sizes.
* If the new size is larger, the value of the newly allocated portion is indeterminate.
*/
header_t *header;
void *ret;
if(!block || !size)
return palloc(size);
header = (header_t*)block - 1;
if(header->s.size >= size)
return block;
ret = palloc(size);
if(ret){
memcpy(ret, block, header->s.size);
pfree(block);
}
return ret;
}