diff --git a/tools/regression/pthread/unwind/Makefile b/tools/regression/pthread/unwind/Makefile new file mode 100644 index 000000000000..c4f9ac84d9fb --- /dev/null +++ b/tools/regression/pthread/unwind/Makefile @@ -0,0 +1,17 @@ +# $FreeBSD$ +all: main_thread_exit thread_normal_exit sem_wait_cancel \ + cond_wait_cancel cond_wait_cancel2 catch_pthread_exit + +.cpp: + c++ -o $@ $< -lpthread + +main_thread_exit: main_thread_exit.cpp +thread_normal_exit: thread_normal_exit.cpp +sem_wait_cancel: sem_wait_cancel.cpp +cond_wait_cancel: cond_wait_cancel.cpp +cond_wait_cancel2: cond_wait_cancel2.cpp +catch_pthread_exit: catch_pthread_exit.cpp + +clean: .PHONY + rm -rf main_thread_exit thread_normal_exit sem_wait_cancel \ + cond_wait_cancel cond_wait_cancel2 catch_pthread_exit diff --git a/tools/regression/pthread/unwind/Test.cpp b/tools/regression/pthread/unwind/Test.cpp new file mode 100644 index 000000000000..9322deff621e --- /dev/null +++ b/tools/regression/pthread/unwind/Test.cpp @@ -0,0 +1,37 @@ +/* $FreeBSD$ */ + +int destructed; +int destructed2; + +class Test { +public: + Test() { printf("Test::Test()\n"); } + ~Test() { printf("Test::~Test()\n"); destructed = 1; } +}; + +void +cleanup_handler(void *arg) +{ + destructed2 = 1; + printf("%s()\n", __func__); +} + +void +check_destruct(void) +{ + if (!destructed) + printf("Bug, object destructor is not called\n"); + else + printf("OK\n"); +} + +void +check_destruct2(void) +{ + if (!destructed) + printf("Bug, object destructor is not called\n"); + else if (!destructed2) + printf("Bug, cleanup handler is not called\n"); + else + printf("OK\n"); +} diff --git a/tools/regression/pthread/unwind/catch_pthread_exit.cpp b/tools/regression/pthread/unwind/catch_pthread_exit.cpp new file mode 100644 index 000000000000..15abc20d1fea --- /dev/null +++ b/tools/regression/pthread/unwind/catch_pthread_exit.cpp @@ -0,0 +1,35 @@ +/* $FreeBSD$ */ +/* try to catch thread exiting, and rethrow the exception */ + +#include +#include +#include + +int caught; + +void * +thr_routine(void *arg) +{ + try { + pthread_exit(NULL); + } catch (...) { + caught = 1; + printf("thread exiting exception caught\n"); + /* rethrow */ + throw; + } +} + +int +main() +{ + pthread_t td; + + pthread_create(&td, NULL, thr_routine, NULL); + pthread_join(td, NULL); + if (caught) + printf("OK\n"); + else + printf("failure\n"); + return (0); +} diff --git a/tools/regression/pthread/unwind/cond_wait_cancel.cpp b/tools/regression/pthread/unwind/cond_wait_cancel.cpp new file mode 100644 index 000000000000..5975e028a5ca --- /dev/null +++ b/tools/regression/pthread/unwind/cond_wait_cancel.cpp @@ -0,0 +1,39 @@ +/* $FreeBSD$ */ +/* Test stack unwinding for pthread_cond_wait function */ + +#include +#include +#include +#include + +#include "Test.cpp" + +pthread_mutex_t mtx; +pthread_cond_t cv; + +void * +thr(void *arg) +{ + Test t; + + pthread_mutex_lock(&mtx); + pthread_cond_wait(&cv, &mtx); + pthread_mutex_unlock(&mtx); + printf("Bug, thread shouldn't be here.\n"); + return (0); +} + +int +main() +{ + pthread_t td; + + pthread_mutex_init(&mtx, NULL); + pthread_cond_init(&cv, NULL); + pthread_create(&td, NULL, thr, NULL); + sleep(1); + pthread_cancel(td); + pthread_join(td, NULL); + check_destruct(); + return (0); +} diff --git a/tools/regression/pthread/unwind/cond_wait_cancel2.cpp b/tools/regression/pthread/unwind/cond_wait_cancel2.cpp new file mode 100644 index 000000000000..c781068918f1 --- /dev/null +++ b/tools/regression/pthread/unwind/cond_wait_cancel2.cpp @@ -0,0 +1,56 @@ +/* + * $FreeBSD$ + * + * Test stack unwinding for mixed pthread_cleanup_push/pop and C++ + * object, both should work together. + * + */ + +#include +#include +#include +#include + +#include "Test.cpp" + +pthread_mutex_t mtx; +pthread_cond_t cv; + +void f() +{ + Test t; + + pthread_mutex_lock(&mtx); + pthread_cond_wait(&cv, &mtx); + pthread_mutex_unlock(&mtx); + printf("Bug, thread shouldn't be here.\n"); +} + +void g() +{ + f(); +} + +void * +thr(void *arg) +{ + pthread_cleanup_push(cleanup_handler, NULL); + g(); + pthread_cleanup_pop(0); + return (0); +} + +int +main() +{ + pthread_t td; + + pthread_mutex_init(&mtx, NULL); + pthread_cond_init(&cv, NULL); + pthread_create(&td, NULL, thr, NULL); + sleep(1); + pthread_cancel(td); + pthread_join(td, NULL); + check_destruct2(); + return (0); +} diff --git a/tools/regression/pthread/unwind/main_thread_exit.cpp b/tools/regression/pthread/unwind/main_thread_exit.cpp new file mode 100644 index 000000000000..182c194b07af --- /dev/null +++ b/tools/regression/pthread/unwind/main_thread_exit.cpp @@ -0,0 +1,18 @@ +/* $FreeBSD$ */ +/* check unwinding for main thread */ + +#include +#include +#include + +#include "Test.cpp" + +int +main() +{ + Test test; + + atexit(check_destruct); + pthread_exit((void *)1); + return (0); +} diff --git a/tools/regression/pthread/unwind/sem_wait_cancel.cpp b/tools/regression/pthread/unwind/sem_wait_cancel.cpp new file mode 100644 index 000000000000..019164cb3166 --- /dev/null +++ b/tools/regression/pthread/unwind/sem_wait_cancel.cpp @@ -0,0 +1,35 @@ +/* $FreeBSD$ */ +/* Test stack unwinding for libc's sem */ + +#include +#include +#include +#include + +#include "Test.cpp" + +sem_t sem; + +void * +thr(void *arg) +{ + Test t; + + sem_wait(&sem); + printf("Bug, thread shouldn't be here.\n"); + return (0); +} + +int +main() +{ + pthread_t td; + + sem_init(&sem, 0, 0); + pthread_create(&td, NULL, thr, NULL); + sleep(1); + pthread_cancel(td); + pthread_join(td, NULL); + check_destruct(); + return (0); +} diff --git a/tools/regression/pthread/unwind/thread_normal_exit.cpp b/tools/regression/pthread/unwind/thread_normal_exit.cpp new file mode 100644 index 000000000000..faf900e572c4 --- /dev/null +++ b/tools/regression/pthread/unwind/thread_normal_exit.cpp @@ -0,0 +1,28 @@ +/* $FreeBSD$ */ +/* test stack unwinding for a new thread */ + +#include +#include +#include + +#include "Test.cpp" + +void * +thr_routine(void *arg) +{ + Test test; + + pthread_exit(NULL); + printf("Bug, thread shouldn't be here\n"); +} + +int +main() +{ + pthread_t td; + + pthread_create(&td, NULL, thr_routine, NULL); + pthread_join(td, NULL); + check_destruct(); + return (0); +}