+/* The desired minimum alignment for an allocated block of memory. */
+#define MEM_ALIGN MAX(sizeof(void *), 8)
+BUILD_ASSERT_DECL(IS_POW2(MEM_ALIGN));
+BUILD_ASSERT_DECL(CACHE_LINE_SIZE >= MEM_ALIGN);
+
+/* Allocates and returns 'size' bytes of memory in dedicated cache lines. That
+ * is, the memory block returned will not share a cache line with other data,
+ * avoiding "false sharing". (The memory returned will not be at the start of
+ * a cache line, though, so don't assume such alignment.)
+ *
+ * Use free_cacheline() to free the returned memory block. */
+void *
+xmalloc_cacheline(size_t size)
+{
+ void **payload;
+ void *base;
+
+ /* Allocate room for:
+ *
+ * - Up to CACHE_LINE_SIZE - 1 bytes before the payload, so that the
+ * start of the payload doesn't potentially share a cache line.
+ *
+ * - A payload consisting of a void *, followed by padding out to
+ * MEM_ALIGN bytes, followed by 'size' bytes of user data.
+ *
+ * - Space following the payload up to the end of the cache line, so
+ * that the end of the payload doesn't potentially share a cache line
+ * with some following block. */
+ base = xmalloc((CACHE_LINE_SIZE - 1)
+ + ROUND_UP(MEM_ALIGN + size, CACHE_LINE_SIZE));
+
+ /* Locate the payload and store a pointer to the base at the beginning. */
+ payload = (void **) ROUND_UP((uintptr_t) base, CACHE_LINE_SIZE);
+ *payload = base;
+
+ return (char *) payload + MEM_ALIGN;
+}
+
+/* Like xmalloc_cacheline() but clears the allocated memory to all zero
+ * bytes. */
+void *
+xzalloc_cacheline(size_t size)
+{
+ void *p = xmalloc_cacheline(size);
+ memset(p, 0, size);
+ return p;
+}
+
+/* Frees a memory block allocated with xmalloc_cacheline() or
+ * xzalloc_cacheline(). */
+void
+free_cacheline(void *p)
+{
+ if (p) {
+ free(*(void **) ((uintptr_t) p - MEM_ALIGN));
+ }
+}
+