Skip to content

Instantly share code, notes, and snippets.

@blackball
Last active August 16, 2019 08:47
Show Gist options
  • Save blackball/e731b075314cb2775f870b70e0fe5875 to your computer and use it in GitHub Desktop.
Save blackball/e731b075314cb2775f870b70e0fe5875 to your computer and use it in GitHub Desktop.
/// For modules that we care about the memory safety, we should never allow user
/// to have a way to access the memory directly. In this case, handle will be a
/// more useful tool. But in order to use handle safely, some tricks required.
/// Here I try to make an example of using handle to design simple API.
/// NOTE: for now we assume all codes will only be ran in single-thread, MT
// could be enabled easily though.
#include <stdio.h>
#include <stdlib.h>
struct object
{
int uid, gid;
};
int object_isvalid(const struct object obj);
// allocate an object
struct object object_create();
// deallocate an object
void object_destroy(const struct object obj);
// use the allocated object
void object_use(const struct object obj);
/// the implementation
enum objectimplstatus
{
objectimplstatus_free = 0,
objectimplstatus_inuse,
};
struct objectimpl
{
int status;
int gid; // generation id used to avoid use-after-free issue
int val;
};
#define OBJECT_INVALID_ID 0
#define OBJECT_MAX_NUM 32
static struct
{
struct objectimpl impls[OBJECT_MAX_NUM+1]; // the valid slot is from 1 to MAX_NUM
} sg_system;
// here we are relying on the *static* to initialize system,
// we could make impls to be dynamic, Implement the dynamic version
// in C is little bit lengthy, but C++ RAII feature could
// make it easier.
static struct objectimpl*
system_get(const struct object obj)
{
return &(sg_system.impls[obj.uid]);
}
static inline int
system_size()
{
return OBJECT_MAX_NUM;
}
static inline int
system_isvalid(const struct object obj)
{
return obj.uid > 0 && obj.uid <= system_size() && (sg_system.impls[obj.uid].gid == obj.gid);
}
static struct object
system_allocate()
{
struct object obj;
int i = OBJECT_MAX_NUM;
for (; i > 0; --i) {
if (sg_system.impls[i].status == objectimplstatus_free) {
break;
}
}
sg_system.impls[i].status = objectimplstatus_inuse;
obj.uid = i;
obj.gid = sg_system.impls[i].gid;
return obj;
}
static void
system_deallocate(const struct object obj)
{
if (system_isvalid(obj)) {
sg_system.impls[obj.uid].status = objectimplstatus_free;
sg_system.impls[obj.uid].gid++;
}
else {
puts("Try to deallocate an invalid object!");
}
}
/// Below is the external API implementation
int
object_isvalid(const struct object obj)
{
return system_isvalid(obj);
}
struct object
object_create()
{
return system_allocate();
}
void
object_destroy(const struct object obj)
{
system_deallocate(obj);
}
void
object_use(const struct object obj)
{
if (object_isvalid(obj)) {
struct objectimpl *pimp = system_get(obj);
pimp->val += 3;
printf("%d\n", pimp->val);
}
}
int main()
{
struct object obj = object_create();
object_use(obj);
object_use(obj);
object_destroy(obj);
object_destroy(obj);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment