pth_broadcast.vgtest \
pth_cancel_locked.stderr.exp \
pth_cancel_locked.vgtest \
+ pth_cleanup_handler.stderr.exp \
+ pth_cleanup_handler.vgtest \
pth_cond_race.stderr.exp \
pth_cond_race.vgtest \
pth_cond_race2.stderr.exp \
new_delete \
pth_broadcast \
pth_cancel_locked \
+ pth_cleanup_handler \
pth_cond_race \
pth_create_chain \
pth_detached \
monitor_example_SOURCES = monitor_example.cpp
new_delete_SOURCES = new_delete.cpp
+pth_cleanup_handler_CFLAGS = @FLAG_W_NO_EMPTY_BODY@
+
tsan_unittest_SOURCES = tsan_unittest.cpp
tsan_unittest_CXXFLAGS = $(AM_CXXFLAGS) \
-DTHREAD_WRAPPERS='"tsan_thread_wrappers_pthread.h"'
--- /dev/null
+/*
+ * Test program for verifying whether pthread cleanup handlers are invoked
+ * correctly.
+ */
+
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <stdlib.h>
+
+
+static pthread_rwlock_t rwl;
+
+
+static void cleanup_handler(void* param)
+{
+ fprintf(stderr, "Cleanup handler has been called.\n");
+ pthread_rwlock_unlock(&rwl);
+}
+
+static void* f(void *p)
+{
+ if (pthread_rwlock_rdlock(&rwl) != 0)
+ {
+ fprintf(stderr, "pthread_rwlock_rdlock()\n");
+ exit(1);
+ }
+
+ pthread_cleanup_push(cleanup_handler, NULL);
+ pthread_exit(0);
+ pthread_cleanup_pop(true);
+}
+
+
+int main()
+{
+ pthread_t pt1, pt2;
+
+ // Make sure the program exits in case a deadlock has been triggered.
+ alarm(2);
+
+ if (pthread_rwlock_init(&rwl, NULL) != 0)
+ {
+ fprintf(stderr, "pthread_rwlock_init()\n");
+ exit(1);
+ }
+ if (pthread_create(&pt1, NULL, f, NULL) != 0)
+ {
+ fprintf(stderr, "pthread_create()\n");
+ exit(1);
+ }
+ if (pthread_create(&pt2, NULL, f, NULL) != 0)
+ {
+ fprintf(stderr, "pthread_create()\n");
+ exit(1);
+ }
+
+ pthread_join(pt1, 0);
+ pthread_join(pt2, 0);
+
+ fprintf(stderr, "Test succeeded.\n");
+
+ return 0;
+}