summaryrefslogtreecommitdiff
path: root/sysdep/unix/alloc_test.c
diff options
context:
space:
mode:
authorMaria Matejka <mq@ucw.cz>2023-05-05 09:39:13 +0200
committerMaria Matejka <mq@ucw.cz>2023-05-06 10:50:32 +0200
commita95141111c89803347c36501185a76fc73a9764a (patch)
treea96a54914cf2498d02546ed49f8e2b852680229b /sysdep/unix/alloc_test.c
parent00f30ac40bda76b289b1dc5c5aa8a5d2e4941985 (diff)
Fixed a bug in hot page global storage
The original algorithm was suffering from an ABA race condition: A: fp = page_stack B: completely allocates the same page and writes into it some data A: unsuspecting, loads (invalid) next = fp->next B: finishes working with the page and returns it back to page_stack A: compare-exchange page_stack: fp => next succeeds and writes garbage to page_stack Fixed this by using an implicit spinlock in hot page allocator.
Diffstat (limited to 'sysdep/unix/alloc_test.c')
-rw-r--r--sysdep/unix/alloc_test.c74
1 files changed, 74 insertions, 0 deletions
diff --git a/sysdep/unix/alloc_test.c b/sysdep/unix/alloc_test.c
new file mode 100644
index 00000000..202af2b2
--- /dev/null
+++ b/sysdep/unix/alloc_test.c
@@ -0,0 +1,74 @@
+/*
+ * BIRD -- Allocator Tests
+ *
+ * (c) 2023 CZ.NIC z.s.p.o.
+ * (c) 2023 Maria Matejka <mq@jmq.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+#include "test/bt-utils.h"
+#include "lib/resource.h"
+
+#include <unistd.h>
+#include <pthread.h>
+
+#define ALLOC_AND_TREE_LIMIT (1 << 14)
+
+static void *
+alloc_and_free_main(void *data UNUSED)
+{
+#define BLOCK_SIZE 32
+ void *block[BLOCK_SIZE];
+
+ for (int i=0; i<ALLOC_AND_TREE_LIMIT; i++)
+ {
+ for (int b=0; b<BLOCK_SIZE; b++)
+ {
+ block[b] = alloc_page();
+ ASSERT_DIE(PAGE_HEAD(block[b]) == block[b]);
+ memset(block[b], 0x42, page_size);
+ }
+
+ for (int b=0; b<BLOCK_SIZE; b++)
+ {
+ free_page(block[b]);
+ block[b] = alloc_page();
+ ASSERT_DIE(PAGE_HEAD(block[b]) == block[b]);
+ memset(block[b], 0x53, page_size);
+ }
+
+ for (int b=0; b<BLOCK_SIZE; b++)
+ free_page(block[b]);
+ }
+
+ return NULL;
+}
+
+static int
+t_alloc_and_free(void)
+{
+#define THR_N 16
+ pthread_t tid[THR_N];
+
+ for (int i=0; i<THR_N; i++)
+ {
+ pthread_create(&tid[i], NULL, alloc_and_free_main, NULL);
+ usleep(50 * i);
+ }
+
+ for (int i=0; i<THR_N; i++)
+ pthread_join(tid[i], NULL);
+
+ return 1;
+}
+
+int main(int argc, char **argv)
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_alloc_and_free, "Testing parallel allocations and free");
+
+ return bt_exit_value();
+}