Commit 08d8e9e8 authored by ymelnyk21's avatar ymelnyk21
Browse files

starting

parents
This diff is collapsed.
CC = gcc
#SPECIAL_FLAGS = -ggdb -Wall -DDEBUG_ALLOC
SPECIAL_FLAGS = -ggdb -Wall
CFLAGS = -std=gnu99 $(SPECIAL_FLAGS)
all: libpb libbf memtest
libpb: pb-alloc.o safeio.o
$(CC) $(CFLAGS) -fPIC -shared -o libpb.so pb-alloc.o safeio.o
pb-alloc.o: pb-alloc.c safeio.h
$(CC) $(CFLAGS) -c pb-alloc.c
libbf: bf-alloc.o safeio.o
$(CC) $(CFLAGS) -fPIC -shared -o libbf.so bf-alloc.o safeio.o
bf-alloc.o: bf-alloc.c safeio.h
$(CC) $(CFLAGS) -c bf-alloc.c
libsf: sf-alloc.o safeio.o
$(CC) $(CFLAGS) -fPIC -shared -o libsf.so sf-alloc.o safeio.o
memtest: memtest.c
$(CC) $(CFLAGS) -o memtest memtest.c
safeio.o: safeio.c safeio.h
$(CC) $(CFLAGS) -c safeio.c
docs:
doxygen
clean:
rm -rf *.o *.so memtest
https://sfkaplan.people.amherst.edu/courses/2021/fall/COSC-171/assignments/project-3/Doxyfile
https://sfkaplan.people.amherst.edu/courses/2021/fall/COSC-171/assignments/project-3/Makefile
https://sfkaplan.people.amherst.edu/courses/2021/fall/COSC-171/assignments/project-3/memtest.c
https://sfkaplan.people.amherst.edu/courses/2021/fall/COSC-171/assignments/project-3/pb-alloc.c
https://sfkaplan.people.amherst.edu/courses/2021/fall/COSC-171/assignments/project-3/safeio.c
https://sfkaplan.people.amherst.edu/courses/2021/fall/COSC-171/assignments/project-3/safeio.h
#include <stdlib.h>
#include <stdio.h>
int main (int argc, char **argv){
char* x = malloc(24);
char* y = malloc(19);
char* z = malloc(32);
printf("x = %p\n", x);
printf("y = %p\n", y);
printf("z = %p\n", z);
}
// ==============================================================================
/**
* pb-alloc.c
*
* A _pointer-bumping_ heap allocator. This allocator *does not re-use* freed
* blocks. It uses _pointer bumping_ to expand the heap with each allocation.
**/
// ==============================================================================
// ==============================================================================
// INCLUDES
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include "safeio.h"
// ==============================================================================
// ==============================================================================
// MACRO CONSTANTS AND FUNCTIONS
/** The system's page size. */
#define PAGE_SIZE sysconf(_SC_PAGESIZE)
/**
* Macros to easily calculate the number of bytes for larger scales (e.g., kilo,
* mega, gigabytes).
*/
#define KB(size) ((size_t)size * 1024)
#define MB(size) (KB(size) * 1024)
#define GB(size) (MB(size) * 1024)
/** The virtual address space reserved for the heap. */
#define HEAP_SIZE GB(2)
// ==============================================================================
// ==============================================================================
// TYPES AND STRUCTURES
/** A header for each block's metadata. */
typedef struct header {
/** The size of the useful portion of the block, in bytes. */
size_t size;
} header_s;
// ==============================================================================
// ==============================================================================
// GLOBALS
/** The address of the next available byte in the heap region. */
static intptr_t free_addr = 0;
/** The beginning of the heap. */
static intptr_t start_addr = 0;
/** The end of the heap. */
static intptr_t end_addr = 0;
// ==============================================================================
// ==============================================================================
/**
* The initialization method. If this is the first use of the heap, initialize it.
*/
void init () {
// Only do anything if there is no heap region (i.e., first time called).
if (start_addr == 0) {
DEBUG("Trying to initialize");
// Allocate virtual address space in which the heap will reside. Make it
// un-shared and not backed by any file (_anonymous_ space). A failure to
// map this space is fatal.
void* heap = mmap(NULL,
HEAP_SIZE,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1,
0);
if (heap == MAP_FAILED) {
ERROR("Could not mmap() heap region");
}
// Hold onto the boundaries of the heap as a whole.
start_addr = (intptr_t)heap;
end_addr = start_addr + HEAP_SIZE;
free_addr = start_addr;
// DEBUG: Emit a message to indicate that this allocator is being called.
DEBUG("bp-alloc initialized");
}
} // init ()
// ==============================================================================
// ==============================================================================
/**
* Allocate and return `size` bytes of heap space. Expand into the heap region
* via _pointer bumping_.
*
* \param size The number of bytes to allocate.
* \return A pointer to the allocated block, if successful; `NULL` if
* unsuccessful.
*/
void* malloc (size_t size) {
init();
if (size == 0) {
return NULL;
}
size_t total_size = size + sizeof(header_s);
header_s* header_ptr = (header_s*)free_addr;
void* block_ptr = (void*)(free_addr + sizeof(header_s));
intptr_t new_free_addr = free_addr + total_size;
if (new_free_addr > end_addr) {
return NULL;
} else {
free_addr = new_free_addr;
}
header_ptr->size = size;
return block_ptr;
} // malloc()
// ==============================================================================
// ==============================================================================
/**
* Deallocate a given block on the heap. Add the given block (if any) to the
* free list.
*
* \param ptr A pointer to the block to be deallocated.
*/
void free (void* ptr) {
DEBUG("free(): ", (intptr_t)ptr);
} // free()
// ==============================================================================
// ==============================================================================
/**
* Allocate a block of `nmemb * size` bytes on the heap, zeroing its contents.
*
* \param nmemb The number of elements in the new block.
* \param size The size, in bytes, of each of the `nmemb` elements.
* \return A pointer to the newly allocated and zeroed block, if successful;
* `NULL` if unsuccessful.
*/
void* calloc (size_t nmemb, size_t size) {
// Allocate a block of the requested size.
size_t block_size = nmemb * size;
void* block_ptr = malloc(block_size);
// If the allocation succeeded, clear the entire block.
if (block_ptr != NULL) {
memset(block_ptr, 0, block_size);
}
return block_ptr;
} // calloc ()
// ==============================================================================
// ==============================================================================
/**
* Update the given block at `ptr` to take on the given `size`. Here, if `size`
* fits within the given block, then the block is returned unchanged. If the
* `size` is an increase for the block, then a new and larger block is
* allocated, and the data from the old block is copied, the old block freed,
* and the new block returned.
*
* \param ptr The block to be assigned a new size.
* \param size The new size that the block should assume.
* \return A pointer to the resultant block, which may be `ptr` itself, or
* may be a newly allocated block.
*/
void* realloc (void* ptr, size_t size) {
if (ptr == NULL) {
return malloc(size);
}
if (size == 0) {
free(ptr);
return NULL;
}
header_s* old_header = (header_s*)((intptr_t)ptr - sizeof(header_s));
size_t old_size = old_header->size;
if (size <= old_size) {
return ptr;
}
void* new_ptr = malloc(size);
if (new_ptr != NULL) {
memcpy(new_ptr, ptr, old_size);
free(ptr);
}
return new_ptr;
} // realloc()
// ==============================================================================
#if defined (ALLOC_MAIN)
// ==============================================================================
/**
* The entry point if this code is compiled as a standalone program for testing
* purposes.
*/
int main () {
// Allocate a few blocks, then free them.
void* x = malloc(16);
void* y = malloc(64);
void* z = malloc(32);
free(z);
free(y);
free(x);
return 0;
} // main()
// ==============================================================================
#endif
// ==============================================================================
/**
* safeio.c
*
* Safe I/O (well, just O) functions that do not rely on heap allocation.
**/
// ==============================================================================
// ==============================================================================
// INCLUDES
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include "safeio.h"
// ==============================================================================
// ==============================================================================
// MACRO CONSTANTS AND FUNCTIONS
#define BITS_PER_BYTE 8
#define BITS_PER_NYBBLE 4
#define BYTE_MASK 0xff
#define NYBBLE_MASK 0xf
#define BYTES_PER_WORD sizeof(intptr_t)
#define BITS_PER_WORD (BYTES_PER_WORD * BITS_PER_BYTE)
#define NYBBLES_PER_WORD (BITS_PER_WORD / BITS_PER_NYBBLE)
/** The maximum length of debugging/error messages. */
#define MAX_MESSAGE_LENGTH 256
#define TAB_STRING "\t"
#define TAB_LENGTH 1
#define NEWLINE_STRING "\n"
#define NEWLINE_LENGTH 1
#define OUTPUT_FD STDERR_FILENO
// ==============================================================================
// ==============================================================================
void
int_to_hex (char* buffer, uint64_t value) {
static char hex_digits[] = { '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
char* current = buffer;
bool non_zero = false;
for (int i = NYBBLES_PER_WORD - 1; i >= 0; i = i - 1) {
unsigned int nybble = (value >> (i * BITS_PER_NYBBLE)) & NYBBLE_MASK;
if (non_zero || nybble != 0) {
non_zero = true;
*current++ = hex_digits[nybble];
}
}
if (!non_zero) {
*current++ = hex_digits[0];
}
*current = '\0';
} // int_to_hex ()
// ==============================================================================
// ==============================================================================
/**
* Print a message.
*
* \param prefix The string to emit as a prefix.
* \param msg The string to emit as a message.
* \param argc Count of the variadic arguments.
* \param argp The variadic arguments of integers to be appended to the output.
*/
void
emit (const char* prefix, const char* msg, int argc, va_list argp) {
// Emit the prefix and message.
write(OUTPUT_FD, prefix, strnlen(prefix, MAX_MESSAGE_LENGTH));
write(OUTPUT_FD, msg, strnlen(msg, MAX_MESSAGE_LENGTH));
// Emit each given integer with a tab prefix.
for (int i = 0; i < argc; ++i) {
uint64_t value = va_arg(argp, uint64_t);
char buffer[MAX_MESSAGE_LENGTH];
int_to_hex(buffer, value);
write(OUTPUT_FD, TAB_STRING, TAB_LENGTH);
write(OUTPUT_FD, buffer, strnlen(buffer, MAX_MESSAGE_LENGTH));
}
// Emit a newline and flush the output.
write(OUTPUT_FD, NEWLINE_STRING, NEWLINE_LENGTH);
fsync(OUTPUT_FD);
}
// ==============================================================================
// ==============================================================================
/**
* Print an debugging message.
*
* \param msg The string to emit as a message to `stderr`. Cannot be longer
* than 256 characters.
* \param argc Count of the variadic arguments.
* \param ... The variadic arguments (0 or more) of integers to be appended to
* the output.
*/
void
safe_debug (const char* msg, int argc, ...) {
// Emit the debugging message.
va_list argp;
va_start(argp, argc);
emit("DEBUG: ", msg, argc, argp);
va_end(argp);
} // safe_debug ()
// ==============================================================================
// ==============================================================================
/**
* Print an error message and abort the process. **Does not return**
*
* \param msg The string to emit as a message to `stderr`. Cannot be longer
* than 256 characters.
* \param argc Count of the variadic arguments.
* \param ... The variadic arguments (0 or more) of integers to be appended to
* the output.
*/
void
safe_error (const char* msg, int argc, ...) {
// Emit the error message.
va_list argp;
va_start(argp, argc);
emit("ERROR: ", msg, argc, argp);
va_end(argp);
// And exit with an error code.
exit(1);
} // safe_error ()
// ==============================================================================
// ==============================================================================
/**
* safeio.h
*
* Safe I/O (well, just O) functions that do not rely on heap allocation.
**/
// ==============================================================================
// ==============================================================================
// Avoid multiple inclusion.
#if !defined (_SAFEIO_H)
#define _SAFEIO_H
// ==============================================================================
// ==============================================================================
// MACROS
#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
/** Emit an error message. */
#define ERROR(msg,...) safe_error(msg, NUMARGS(__VA_ARGS__), ##__VA_ARGS__)
/** Emit a debugging message (or, if disabled, remove such output). */
#if defined (DEBUG_ALLOC)
#define DEBUG(msg,...) safe_debug(msg, NUMARGS(__VA_ARGS__), ##__VA_ARGS__)
#else
#define DEBUG(msg,...)
#endif /* DEBUG_ALLOC */
// ==============================================================================
// ==============================================================================
/**
* Print an debugging message.
*
* \param msg The string to emit as a message to `stderr`. Cannot be longer
* than 256 characters.
* \param argc Count of the variadic arguments.
* \param ... The variadic arguments (0 or more) of integers to be appended to
* the output.
*/
void safe_debug (const char* msg, int argc, ...);
/**
* Print an error message and abort the process. **Does not return**
*
* \param msg The string to emit as a message to `stderr`. Cannot be longer
* than 256 characters.
* \param argc Count of the variadic arguments.
* \param ... The variadic arguments (0 or more) of integers to be appended to
* the output.
*/
void safe_error (const char* msg, int argc, ...);
// ==============================================================================
// ==============================================================================
#endif // _SAEFIO_H
// ==============================================================================
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment