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

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. /* -*- coding: utf-8 -*-
  2. * ----------------------------------------------------------------------
  3. * Copyright © 2013-2014, RedJack, LLC.
  4. * All rights reserved.
  5. *
  6. * Please see the COPYING file in this distribution for license details.
  7. * ----------------------------------------------------------------------
  8. */
  9. #include <stdlib.h>
  10. #include "libcork/core.h"
  11. #include "libcork/ds.h"
  12. #include "libcork/os/process.h"
  13. #include "libcork/helpers/errors.h"
  14. #if !defined(CORK_DEBUG_PROCESS)
  15. #define CORK_DEBUG_PROCESS 0
  16. #endif
  17. #if CORK_DEBUG_PROCESS
  18. #include <stdio.h>
  19. #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
  20. #else
  21. #define DEBUG(...) /* no debug messages */
  22. #endif
  23. struct cork_cleanup_entry {
  24. struct cork_dllist_item item;
  25. int priority;
  26. const char *name;
  27. cork_cleanup_function function;
  28. };
  29. static struct cork_cleanup_entry *
  30. cork_cleanup_entry_new(const char *name, int priority,
  31. cork_cleanup_function function)
  32. {
  33. struct cork_cleanup_entry *self = cork_new(struct cork_cleanup_entry);
  34. self->priority = priority;
  35. self->name = cork_strdup(name);
  36. self->function = function;
  37. return self;
  38. }
  39. static void
  40. cork_cleanup_entry_free(struct cork_cleanup_entry *self)
  41. {
  42. cork_strfree(self->name);
  43. cork_delete(struct cork_cleanup_entry, self);
  44. }
  45. static struct cork_dllist cleanup_entries = CORK_DLLIST_INIT(cleanup_entries);
  46. static bool cleanup_registered = false;
  47. static void
  48. cork_cleanup_call_one(struct cork_dllist_item *item, void *user_data)
  49. {
  50. struct cork_cleanup_entry *entry =
  51. cork_container_of(item, struct cork_cleanup_entry, item);
  52. cork_cleanup_function function = entry->function;
  53. DEBUG("Call cleanup function [%d] %s\n", entry->priority, entry->name);
  54. /* We need to free the entry before calling the entry's function, since one
  55. * of the functions that libcork registers frees the allocator instance that
  56. * we'd use to free the entry. If we called the function first, the
  57. * allocator would be freed before we could use it to free the entry. */
  58. cork_cleanup_entry_free(entry);
  59. function();
  60. }
  61. static void
  62. cork_cleanup_call_all(void)
  63. {
  64. cork_dllist_map(&cleanup_entries, cork_cleanup_call_one, NULL);
  65. }
  66. static void
  67. cork_cleanup_entry_add(struct cork_cleanup_entry *entry)
  68. {
  69. struct cork_dllist_item *curr;
  70. if (CORK_UNLIKELY(!cleanup_registered)) {
  71. atexit(cork_cleanup_call_all);
  72. cleanup_registered = true;
  73. }
  74. /* Linear search through the list of existing cleanup functions. When we
  75. * find the first existing function with a higher priority, we've found
  76. * where to insert the new function. */
  77. for (curr = cork_dllist_start(&cleanup_entries);
  78. !cork_dllist_is_end(&cleanup_entries, curr); curr = curr->next) {
  79. struct cork_cleanup_entry *existing =
  80. cork_container_of(curr, struct cork_cleanup_entry, item);
  81. if (existing->priority > entry->priority) {
  82. cork_dllist_add_before(&existing->item, &entry->item);
  83. return;
  84. }
  85. }
  86. /* If we fall through the loop, then the new function should be appended to
  87. * the end of the list. */
  88. cork_dllist_add(&cleanup_entries, &entry->item);
  89. }
  90. CORK_API void
  91. cork_cleanup_at_exit_named(const char *name, int priority,
  92. cork_cleanup_function function)
  93. {
  94. struct cork_cleanup_entry *entry =
  95. cork_cleanup_entry_new(name, priority, function);
  96. DEBUG("Register cleanup function [%d] %s\n", priority, name);
  97. cork_cleanup_entry_add(entry);
  98. }