fork download
  1. /**
  2.   * Delete all lines containing
  3.   * 'ALL_IN_ONE' if you split this example
  4.   * into separate files.
  5.   */
  6. #define ALL_IN_ONE 1
  7.  
  8.  
  9. /****
  10.   * pfxalloc.h
  11.   *
  12.   * Shao Miller, 2011
  13.   * It took several minutes to find
  14.   * a free *alloc. (No pun intended.)
  15.   */
  16. #ifndef PFXALLOC_H_
  17.  
  18. /* For 'offsetof' and 'size_t' */
  19. #include <stddef.h>
  20.  
  21. /*** Macros */
  22. #define PFXALLOC_H_
  23.  
  24. #ifndef alignof
  25.  
  26. /* Derived from Mr. Chris M. Thomasson */
  27. #define alignof(type) \
  28.   (offsetof(struct {char c; type t;}, t))
  29.  
  30. #ifdef __alignof_is_defined
  31. #undef __alignof_is_defined
  32. #endif /* __alignof_is_defined */
  33.  
  34. #define __alignof_is_defined 1
  35. #endif /* alignof */
  36.  
  37. /*** Functions */
  38.  
  39. /**
  40.   * Allocate memory for an object and an
  41.   * associated "prefix" object.
  42.   *
  43.   * @v pfx_size The "prefix" size.
  44.   * @v obj_alignment The object's alignment
  45.   * requirement.
  46.   * @v obj_size The object's size.
  47.   * @ret void * Points to the object,
  48.   * or is NULL for failure.
  49.   */
  50. extern void * pfxalloc(size_t, size_t, size_t);
  51.  
  52. /**
  53.   * Get an object's associated "prefix" object.
  54.   *
  55.   * @v obj The object to fetch the
  56.   * associated "prefix" for.
  57.   * @ret void * Points to the "prefix",
  58.   * or is NULL for failure.
  59.   */
  60. extern void * pfxget(void *);
  61.  
  62. #endif /* PFXALLOC_H_ */
  63.  
  64.  
  65. /**** pfxalloc.c */
  66. /* Shao Miller, 2011 */
  67.  
  68. /* For 'malloc' */
  69. #include <stdlib.h>
  70. #if !ALL_IN_ONE
  71. /* For 'size_t', 'ptrdiff_t' and 'NULL' */
  72. #include <stddef.h>
  73. /* For 'alignof' */
  74. #include "pfxalloc.h"
  75. #endif /* !ALL_IN_ONE */
  76.  
  77. /*** Constants */
  78. enum cv {
  79. cv_ptrdiff_alignment =
  80. alignof(ptrdiff_t),
  81. cv_zero = 0
  82. };
  83.  
  84. /*** Functions */
  85.  
  86. /**
  87.   * The layout looks like:
  88.   * +-----+-------------+--------+--------+
  89.   * | pfx | opt_padding | offset | |
  90.   * +- -+- -+- -+ object |
  91.   * | header | |
  92.   * +----------------------------+--------+
  93.   */
  94. void * pfxalloc(
  95. size_t pfx_size,
  96. size_t obj_alignment,
  97. size_t obj_size
  98. ) {
  99. size_t offset_at;
  100. ptrdiff_t * offset;
  101. size_t header_size;
  102. size_t total_size;
  103. unsigned char * mem;
  104. unsigned char * obj;
  105.  
  106. /* Sanity-check alignment value */
  107. if (obj_alignment & (obj_alignment - 1))
  108. return NULL;
  109.  
  110. /* Calculate the offset position */
  111. offset_at = pfx_size;
  112. offset_at += sizeof *offset;
  113. /* Check for wrap-around */
  114. if (offset_at < pfx_size)
  115. return NULL;
  116. --offset_at;
  117. offset_at /= sizeof *offset;
  118.  
  119. /* Calculate the header size */
  120. header_size = (offset_at + 1) * sizeof *offset;
  121. /* Check for wrap-around */
  122. if (header_size < pfx_size)
  123. return NULL;
  124.  
  125. /* Calculate padding */
  126. if (obj_alignment > cv_ptrdiff_alignment) {
  127. size_t new_hdr_size = header_size;
  128. new_hdr_size += obj_alignment;
  129. /* Check for wrap-around */
  130. if (new_hdr_size < header_size)
  131. return NULL;
  132. --new_hdr_size;
  133. new_hdr_size /= obj_alignment;
  134. new_hdr_size *= obj_alignment;
  135. header_size = new_hdr_size;
  136. }
  137.  
  138. /* Allocate storage */
  139. total_size = header_size + obj_size;
  140. /* Check for wrap-around */
  141. if (total_size < pfx_size || total_size < obj_size)
  142. return NULL;
  143. mem = malloc(total_size);
  144. if (!mem)
  145. return mem;
  146.  
  147. /* Point to the object */
  148. obj = mem + header_size;
  149.  
  150. /* Note the offset to the prefix */
  151. offset = (ptrdiff_t *) obj - 1;
  152. *offset = obj - mem;
  153.  
  154. return obj;
  155. }
  156.  
  157. /* Fetch an asociated prefix for an object */
  158. void * pfxget(void * obj) {
  159. ptrdiff_t * offset;
  160. unsigned char * prefix;
  161.  
  162. if (!obj)
  163. return obj;
  164.  
  165. offset = obj;
  166. --offset;
  167. prefix = obj;
  168. prefix -= *offset;
  169.  
  170. return prefix;
  171. }
  172.  
  173.  
  174. /**** ref_cnt.h */
  175. /* Shao Miller, 2011 */
  176. #ifndef REF_CNT_H_
  177.  
  178. #if !ALL_IN_ONE
  179. /* For 'size_t' */
  180. #include <stddef.h>
  181. #include "align.h"
  182. #endif /* !ALL_IN_ONE */
  183.  
  184. /*** Macros */
  185. #define REF_CNT_H_
  186.  
  187. /*** Function types */
  188. typedef void f_ref_cnt_free(void *);
  189.  
  190. /*** Functions */
  191.  
  192. /**
  193.   * Create a new, reference-counted object
  194.   *
  195.   * @v size The size of the object
  196.   * to allocate, in bytes.
  197.   * @v alignment The alignment requirement
  198.   * for the object.
  199.   * @v dealloc The de-allocation function
  200.   * to call, when refs == 0.
  201.   * @ret void * Points to the newly-
  202.   * allocated object, or is
  203.   * NULL, upon failure.
  204.   */
  205. extern void * NewRefCountedObj(
  206. size_t,
  207. size_t,
  208. f_ref_cnt_free *
  209. );
  210.  
  211. /**
  212.   * Increment the reference count for an object.
  213.   *
  214.   * @v obj The object to reference.
  215.   * @ret void * Points to the object, or is
  216.   * NULL if too many references.
  217.   */
  218. extern void * GetRef(void *);
  219.  
  220. /**
  221.   * Decrement the reference count for an object.
  222.   *
  223.   * @v obj The object to dereference.
  224.   */
  225. extern void PutRef(void *);
  226.  
  227. #endif /* REF_CNT_H_ */
  228.  
  229.  
  230. /**** ref_cnt.c */
  231. /* Shao Miller, 2011 */
  232.  
  233. #if !ALL_IN_ONE
  234. /* For 'size_t' */
  235. #include <stddef.h>
  236. #include "pfxalloc.h"
  237. #include "ref_cnt.h"
  238. #endif /* !ALL_IN_ONE */
  239.  
  240. /*** Types */
  241. struct ref_counted_obj {
  242. unsigned int ref_count;
  243. f_ref_cnt_free * dealloc;
  244. };
  245.  
  246. /*** Functions */
  247.  
  248. void * NewRefCountedObj(
  249. size_t size,
  250. size_t alignment,
  251. f_ref_cnt_free * dealloc
  252. ) {
  253. void * result;
  254. struct ref_counted_obj * ref;
  255.  
  256. /* Allocate the object */
  257. result = pfxalloc(
  258. sizeof *ref,
  259. alignment,
  260. size
  261. );
  262. if (!result)
  263. return result;
  264.  
  265. ref = pfxget(result);
  266. if (!ref) {
  267. /* Uh oh; this is unexpected! */
  268. return ref;
  269. }
  270.  
  271. /* Populate accounting info */
  272. ref->ref_count = 1;
  273. ref->dealloc = dealloc;
  274.  
  275. return result;
  276. }
  277.  
  278. void * GetRef(void * obj) {
  279. struct ref_counted_obj * ref;
  280.  
  281. ref = pfxget(obj);
  282. if (!ref)
  283. return ref;
  284.  
  285. /* Increment ref count and check for wrap-around */
  286. if (!++ref->ref_count) {
  287. --ref->ref_count;
  288. return NULL;
  289. }
  290. return obj;
  291. }
  292.  
  293. void PutRef(void * obj) {
  294. struct ref_counted_obj * ref;
  295.  
  296. ref = pfxget(obj);
  297. if (!ref)
  298. return;
  299. /* Decrement ref count and check for zero */
  300. if (!--ref->ref_count) {
  301. ref->dealloc(obj);
  302. free(ref);
  303. }
  304. return;
  305. }
  306.  
  307.  
  308. /**** Test program */
  309. /* Shao Miller, 2011 */
  310.  
  311. #include <stdio.h>
  312. #include <string.h>
  313. #if !ALL_IN_ONE
  314. #include <stdlib.h>
  315. #include "pfxalloc.h"
  316. #include "ref_cnt.h"
  317. #endif /* !ALL_IN_ONE */
  318.  
  319. /*** Types */
  320. struct foo {
  321. double bobble;
  322. size_t len;
  323. char bear[1];
  324. };
  325.  
  326. /*** Functions */
  327. f_ref_cnt_free foo_dealloc;
  328. void foo_dealloc(void * ptr) {
  329. struct foo * bar;
  330.  
  331. bar = ptr;
  332. "foo_dealloc(%p): {%f, %d, \"%s\"}\n",
  333. ptr,
  334. bar->bobble,
  335. (int)bar->len,
  336. bar->bear
  337. );
  338. return;
  339. }
  340.  
  341. int main(void) {
  342. struct foo * bar;
  343. char laughsalot[] = "Laughs-a-lot";
  344.  
  345. bar = NewRefCountedObj(
  346. sizeof *bar + sizeof laughsalot,
  347. alignof (struct foo),
  348. foo_dealloc
  349. );
  350. if (!bar) {
  351. puts("NewRefCountedObj() failed!");
  352. return EXIT_FAILURE;
  353. }
  354.  
  355. bar->bobble = 3.14159;
  356. bar->len = sizeof laughsalot;
  357. memcpy(bar->bear, laughsalot, sizeof laughsalot);
  358.  
  359. /* Test getting a reference */
  360. bar = GetRef(bar);
  361. if (!bar) {
  362. puts("GetRef() failed!");
  363. PutRef(bar);
  364. return EXIT_FAILURE;
  365. }
  366.  
  367. /* We have two references */
  368. PutRef(bar);
  369. PutRef(bar);
  370. return EXIT_SUCCESS;
  371. }
  372.  
Success #stdin #stdout 0.01s 1852KB
stdin
Standard input is empty
stdout
foo_dealloc(0x8203014): {3.141590, 13, "Laughs-a-lot"}