Exceptions in C!
This commit is contained in:
parent
e8bea8924b
commit
26179d76aa
6 changed files with 134 additions and 0 deletions
|
@ -20,3 +20,4 @@ add_subdirectory(./BinaryTree)
|
||||||
add_subdirectory(./Subprocess)
|
add_subdirectory(./Subprocess)
|
||||||
add_subdirectory(./TracingHeap)
|
add_subdirectory(./TracingHeap)
|
||||||
add_subdirectory(./Complex)
|
add_subdirectory(./Complex)
|
||||||
|
add_subdirectory(./ExceptionalScope)
|
||||||
|
|
1
src/ExceptionalScope/CMakeLists.txt
Normal file
1
src/ExceptionalScope/CMakeLists.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
add_library(ExceptionalScope STATIC ExceptionalScope.c)
|
51
src/ExceptionalScope/ExceptionalScope.c
Normal file
51
src/ExceptionalScope/ExceptionalScope.c
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#include "ExceptionalScope.h"
|
||||||
|
#include "../errorcodes.h"
|
||||||
|
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
int ExceptionalScope_Create(ExceptionalScope* self)
|
||||||
|
{
|
||||||
|
memset(self, 0, sizeof(*self));
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExceptionalScope_ActivateCleaners(ExceptionalScope* self)
|
||||||
|
{
|
||||||
|
while (self->cleaners != NULL) {
|
||||||
|
self->cleaners->action(self->cleaners->arg);
|
||||||
|
self->cleaners = self->cleaners->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExceptionalScope_Destroy(ExceptionalScope* self)
|
||||||
|
{
|
||||||
|
ExceptionalScope_ActivateCleaners(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExceptionalScope_PushCleaner(ExceptionalScope* self, ExceptionalScopeCleaner* cleaner)
|
||||||
|
{
|
||||||
|
cleaner->next = self->cleaners;
|
||||||
|
self->cleaners = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ExceptionalScope_PopCleaner(ExceptionalScope* self, ExceptionalScopeCleaner* cleaner)
|
||||||
|
{
|
||||||
|
if (self->cleaners != cleaner) return ENOTFOUND;
|
||||||
|
|
||||||
|
self->cleaners = self->cleaners->next;
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[noreturn]] void ExceptionalScope_Throw(ExceptionalScope* self, void* exception)
|
||||||
|
{
|
||||||
|
self->exception = exception;
|
||||||
|
|
||||||
|
ExceptionalScope_ActivateCleaners(self);
|
||||||
|
|
||||||
|
longjmp(self->handler, 1);
|
||||||
|
}
|
33
src/ExceptionalScope/ExceptionalScope.h
Normal file
33
src/ExceptionalScope/ExceptionalScope.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef UTILITIEC_EXCEPTIONALSCOPE_H
|
||||||
|
#define UTILITIEC_EXCEPTIONALSCOPE_H
|
||||||
|
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
#define withScopedCleaner(scope, cleaner) for (int __cleanerDone##cleaner = (ExceptionalScope_PushCleaner(scope, &cleaner), 1); __cleanerDone##cleaner--; ExceptionalScope_PopCleaner(scope, &cleaner))
|
||||||
|
#define try(scope) if (setjmp((scope)->handler) == 0)
|
||||||
|
#define catch else
|
||||||
|
|
||||||
|
typedef void (*ExceptionalScopeCleanerFunction) (void* arg);
|
||||||
|
|
||||||
|
typedef struct ExceptionalScopeCleaner_s {
|
||||||
|
ExceptionalScopeCleanerFunction action;
|
||||||
|
void* arg;
|
||||||
|
|
||||||
|
struct ExceptionalScopeCleaner_s* next;
|
||||||
|
} ExceptionalScopeCleaner;
|
||||||
|
|
||||||
|
typedef struct ExceptionalScope_s {
|
||||||
|
jmp_buf handler; // jump here when the exception is thrown
|
||||||
|
ExceptionalScopeCleaner* cleaners; // execute all these before the jumping to the handler
|
||||||
|
void* exception;
|
||||||
|
} ExceptionalScope;
|
||||||
|
|
||||||
|
int ExceptionalScope_Create(ExceptionalScope* self);
|
||||||
|
void ExceptionalScope_Destroy(ExceptionalScope* self);
|
||||||
|
|
||||||
|
void ExceptionalScope_PushCleaner(ExceptionalScope* self, ExceptionalScopeCleaner* cleaner);
|
||||||
|
int ExceptionalScope_PopCleaner(ExceptionalScope* self, ExceptionalScopeCleaner* cleaner);
|
||||||
|
|
||||||
|
[[noreturn]] void ExceptionalScope_Throw(ExceptionalScope* self, void* exception);
|
||||||
|
|
||||||
|
#endif
|
|
@ -60,4 +60,8 @@ target_link_libraries(QuadTree-test
|
||||||
rand
|
rand
|
||||||
pointers
|
pointers
|
||||||
allocator-interface
|
allocator-interface
|
||||||
|
|
||||||
|
add_executable(ExceptionalScope-test ExceptionalScope.test.c)
|
||||||
|
target_link_libraries(ExceptionalScope-test
|
||||||
|
ExceptionalScope
|
||||||
)
|
)
|
||||||
|
|
44
tests/ExceptionalScope.test.c
Normal file
44
tests/ExceptionalScope.test.c
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#include "../src/ExceptionalScope/ExceptionalScope.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define unsafe
|
||||||
|
|
||||||
|
void print(const char* s)
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
puts(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
ExceptionalScope scope;
|
||||||
|
ExceptionalScope_Create(&scope);
|
||||||
|
scope.exception = (void*) 0xCAFEBABE;
|
||||||
|
|
||||||
|
try(&scope) {
|
||||||
|
ExceptionalScopeCleaner outerCleaner = {
|
||||||
|
.next = NULL,
|
||||||
|
.arg = "Unwinding the cleaner stack #2",
|
||||||
|
.action = (ExceptionalScopeCleanerFunction) print,
|
||||||
|
};
|
||||||
|
withScopedCleaner(&scope, outerCleaner) {
|
||||||
|
ExceptionalScopeCleaner innerCleaner = {
|
||||||
|
.next = NULL,
|
||||||
|
.arg = "Unwinding the cleaner stack #1",
|
||||||
|
.action = (ExceptionalScopeCleanerFunction) print,
|
||||||
|
};
|
||||||
|
|
||||||
|
withScopedCleaner(&scope, innerCleaner) {
|
||||||
|
|
||||||
|
ExceptionalScope_Throw(&scope, (void*) 0xDEADBEEF);
|
||||||
|
puts("After the throw");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
printf("Caught an exception: %p\n", scope.exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExceptionalScope_Destroy(&scope);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue