diff options
Diffstat (limited to 'erts/emulator/test/erl_drv_thread_SUITE_data/basic.c')
-rw-r--r-- | erts/emulator/test/erl_drv_thread_SUITE_data/basic.c | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/erts/emulator/test/erl_drv_thread_SUITE_data/basic.c b/erts/emulator/test/erl_drv_thread_SUITE_data/basic.c new file mode 100644 index 0000000000..fca2c1dbea --- /dev/null +++ b/erts/emulator/test/erl_drv_thread_SUITE_data/basic.c @@ -0,0 +1,291 @@ +/* ``The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved via the world wide web at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Initial Developer of the Original Code is Ericsson Utvecklings AB. + * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings + * AB. All Rights Reserved.'' + * + * $Id$ + */ + +#include "testcase_driver.h" + +#ifdef __WIN32__ +#include <windows.h> +#else +#include <unistd.h> +#endif +#include <errno.h> + +#define NO_OF_THREADS 2 + +static int die; +static int cw_passed; +static int res_tf0; +static int res_tf1; +static ErlDrvMutex *mtx; +static ErlDrvCond *cnd; +static int need_join[NO_OF_THREADS]; +static ErlDrvTid tid[NO_OF_THREADS]; +static ErlDrvThreadOpts *topts; + +typedef struct { + int n; +} thr_arg_t; + +static void +do_sleep(unsigned secs) +{ +#ifdef __WIN32__ + Sleep((DWORD) secs*1000); +#else + sleep(secs); +#endif +} + +static void *tf0(void *vta) +{ + if (((thr_arg_t *) vta)->n == 0) { + + erl_drv_mutex_lock(mtx); + + erl_drv_cond_wait(cnd, mtx); + + if (die) { + erl_drv_mutex_unlock(mtx); + return NULL; + } + + cw_passed++; + + erl_drv_cond_wait(cnd, mtx); + + if (die) { + erl_drv_mutex_unlock(mtx); + return NULL; + } + + cw_passed++; + + erl_drv_mutex_unlock(mtx); + if (erl_drv_equal_tids(erl_drv_thread_self(), tid[0])) + res_tf0 = 0; + } + + return (void *) &res_tf0; +} + + +static void *tf1(void *vta) +{ + + if (((thr_arg_t *) vta)->n == 1) { + + erl_drv_mutex_lock(mtx); + + erl_drv_cond_wait(cnd, mtx); + + if (die) { + erl_drv_mutex_unlock(mtx); + return NULL; + } + + cw_passed++; + + erl_drv_cond_wait(cnd, mtx); + + if (die) { + erl_drv_mutex_unlock(mtx); + return NULL; + } + + cw_passed++; + + erl_drv_mutex_unlock(mtx); + + if (erl_drv_equal_tids(erl_drv_thread_self(), tid[1])) + res_tf1 = 1; + + erl_drv_thread_exit((void *) &res_tf1); + + res_tf1 = 4711; + } + return NULL; +} + +void +testcase_run(TestCaseState_t *tcs) +{ + int i, r; + void *tres[2]; + thr_arg_t ta[2]; + ErlDrvTid my_tid; + ErlDrvSysInfo sinfo; + + driver_system_info(&sinfo, sizeof(ErlDrvSysInfo)); + if (!sinfo.thread_support) + testcase_skipped(tcs, "No thread support; nothing to test"); + + testcase_printf(tcs, "Initializing\n"); + + cw_passed = 0; + die = 0; + my_tid = erl_drv_thread_self(); + + for (i = 0; i < NO_OF_THREADS; i++) + need_join[i] = 0; + + res_tf0 = 17; + res_tf1 = 17; + + mtx = NULL; + cnd = NULL; + /* Create mutex and cond */ + mtx = erl_drv_mutex_create("mutex"); + ASSERT(tcs, mtx); + cnd = erl_drv_cond_create("cond"); + ASSERT(tcs, cnd); + topts = erl_drv_thread_opts_create("thread opts"); + ASSERT(tcs, topts); + topts->suggested_stack_size = 0; /* As small as possible */ + + testcase_printf(tcs, "Creating threads 0 & 1\n"); + + /* Create the threads */ + ta[0].n = 0; + r = erl_drv_thread_create("thread 0", &tid[0], tf0, (void *) &ta[0], topts); + ASSERT(tcs, r == 0); + need_join[0] = 1; + + ta[1].n = 1; + r = erl_drv_thread_create("thread 1", &tid[1], tf1, (void *) &ta[1], NULL); + ASSERT(tcs, r == 0); + need_join[1] = 1; + + testcase_printf(tcs, "Testing tids\n"); + + ASSERT(tcs, !erl_drv_equal_tids(tid[0], my_tid)); + ASSERT(tcs, !erl_drv_equal_tids(tid[1], my_tid)); + ASSERT(tcs, !erl_drv_equal_tids(tid[0], tid[1])); + ASSERT(tcs, erl_drv_equal_tids(my_tid, erl_drv_thread_self())); + + testcase_printf(tcs, "Testing mutex/cond\n"); + + /* Make sure the threads waits on cond wait */ + do_sleep(1); + + erl_drv_mutex_lock(mtx); + + ASSERT_CLNUP(tcs, cw_passed == 0, erl_drv_mutex_unlock(mtx)); + + /* Let one thread pass one cond wait */ + erl_drv_cond_signal(cnd); + + erl_drv_mutex_unlock(mtx); + + do_sleep(1); + + erl_drv_mutex_lock(mtx); + + ASSERT_CLNUP(tcs, cw_passed == 1, erl_drv_mutex_unlock(mtx)); + + + /* Let both threads pass one cond wait */ + erl_drv_cond_broadcast(cnd); + + erl_drv_mutex_unlock(mtx); + + do_sleep(1); + + erl_drv_mutex_lock(mtx); + + ASSERT_CLNUP(tcs, cw_passed == 3, erl_drv_mutex_unlock(mtx)); + + + /* Let the thread that only have passed one cond wait pass the other one */ + erl_drv_cond_signal(cnd); + + erl_drv_mutex_unlock(mtx); + + do_sleep(1); + + erl_drv_mutex_lock(mtx); + + ASSERT_CLNUP(tcs, cw_passed == 4, erl_drv_mutex_unlock(mtx)); + + + testcase_printf(tcs, "Testing join\n"); + + /* Both threads should have passed both cond waits and exited; + join them and check returned values */ + + erl_drv_thread_join(tid[0], &tres[0]); + ASSERT_CLNUP(tcs, r == 0, erl_drv_mutex_unlock(mtx)); + need_join[0] = 0; + + ASSERT_CLNUP(tcs, tres[0] == &res_tf0, erl_drv_mutex_unlock(mtx)); + ASSERT_CLNUP(tcs, res_tf0 == 0, erl_drv_mutex_unlock(mtx)); + + r = erl_drv_thread_join(tid[1], &tres[1]); + ASSERT_CLNUP(tcs, r == 0, erl_drv_mutex_unlock(mtx)); + need_join[1] = 0; + + ASSERT_CLNUP(tcs, tres[1] == &res_tf1, erl_drv_mutex_unlock(mtx)); + ASSERT_CLNUP(tcs, res_tf1 == 1, erl_drv_mutex_unlock(mtx)); + + /* Test signaling when noone waits */ + + erl_drv_cond_signal(cnd); + + /* Test broadcasting when noone waits */ + + erl_drv_cond_broadcast(cnd); + + erl_drv_mutex_unlock(mtx); + + erl_drv_mutex_destroy(mtx); + mtx = NULL; + + erl_drv_cond_destroy(cnd); + cnd = NULL; + + erl_drv_thread_opts_destroy(topts); + topts = NULL; + + testcase_printf(tcs, "done\n"); +} + +char * +testcase_name(void) +{ + return "basic"; +} + +void +testcase_cleanup(TestCaseState_t *tcs) +{ + int i; + for (i = 0; i < NO_OF_THREADS; i++) { + if (need_join[i]) { + erl_drv_mutex_lock(mtx); + die = 1; + erl_drv_cond_broadcast(cnd); + erl_drv_mutex_unlock(mtx); + erl_drv_thread_join(tid[i], NULL); + } + } + if (mtx) + erl_drv_mutex_destroy(mtx); + if (cnd) + erl_drv_cond_destroy(cnd); + if (topts) + erl_drv_thread_opts_destroy(topts); +} |