You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

116 lines
3.5 KiB

/* -*- coding: utf-8 -*-
* ----------------------------------------------------------------------
* Copyright © 2013-2014, RedJack, LLC.
* All rights reserved.
*
* Please see the COPYING file in this distribution for license details.
* ----------------------------------------------------------------------
*/
#include <stdlib.h>
#include "libcork/core.h"
#include "libcork/ds.h"
#include "libcork/os/process.h"
#include "libcork/helpers/errors.h"
#if !defined(CORK_DEBUG_PROCESS)
#define CORK_DEBUG_PROCESS 0
#endif
#if CORK_DEBUG_PROCESS
#include <stdio.h>
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#else
#define DEBUG(...) /* no debug messages */
#endif
struct cork_cleanup_entry {
struct cork_dllist_item item;
int priority;
const char *name;
cork_cleanup_function function;
};
static struct cork_cleanup_entry *
cork_cleanup_entry_new(const char *name, int priority,
cork_cleanup_function function)
{
struct cork_cleanup_entry *self = cork_new(struct cork_cleanup_entry);
self->priority = priority;
self->name = cork_strdup(name);
self->function = function;
return self;
}
static void
cork_cleanup_entry_free(struct cork_cleanup_entry *self)
{
cork_strfree(self->name);
cork_delete(struct cork_cleanup_entry, self);
}
static struct cork_dllist cleanup_entries = CORK_DLLIST_INIT(cleanup_entries);
static bool cleanup_registered = false;
static void
cork_cleanup_call_one(struct cork_dllist_item *item, void *user_data)
{
struct cork_cleanup_entry *entry =
cork_container_of(item, struct cork_cleanup_entry, item);
cork_cleanup_function function = entry->function;
DEBUG("Call cleanup function [%d] %s\n", entry->priority, entry->name);
/* We need to free the entry before calling the entry's function, since one
* of the functions that libcork registers frees the allocator instance that
* we'd use to free the entry. If we called the function first, the
* allocator would be freed before we could use it to free the entry. */
cork_cleanup_entry_free(entry);
function();
}
static void
cork_cleanup_call_all(void)
{
cork_dllist_map(&cleanup_entries, cork_cleanup_call_one, NULL);
}
static void
cork_cleanup_entry_add(struct cork_cleanup_entry *entry)
{
struct cork_dllist_item *curr;
if (CORK_UNLIKELY(!cleanup_registered)) {
atexit(cork_cleanup_call_all);
cleanup_registered = true;
}
/* Linear search through the list of existing cleanup functions. When we
* find the first existing function with a higher priority, we've found
* where to insert the new function. */
for (curr = cork_dllist_start(&cleanup_entries);
!cork_dllist_is_end(&cleanup_entries, curr); curr = curr->next) {
struct cork_cleanup_entry *existing =
cork_container_of(curr, struct cork_cleanup_entry, item);
if (existing->priority > entry->priority) {
cork_dllist_add_before(&existing->item, &entry->item);
return;
}
}
/* If we fall through the loop, then the new function should be appended to
* the end of the list. */
cork_dllist_add(&cleanup_entries, &entry->item);
}
CORK_API void
cork_cleanup_at_exit_named(const char *name, int priority,
cork_cleanup_function function)
{
struct cork_cleanup_entry *entry =
cork_cleanup_entry_new(name, priority, function);
DEBUG("Register cleanup function [%d] %s\n", priority, name);
cork_cleanup_entry_add(entry);
}