diff options
Diffstat (limited to 'erts/emulator/test/erl_drv_thread_SUITE_data')
6 files changed, 1029 insertions, 0 deletions
diff --git a/erts/emulator/test/erl_drv_thread_SUITE_data/Makefile.src b/erts/emulator/test/erl_drv_thread_SUITE_data/Makefile.src new file mode 100644 index 0000000000..216707e8a5 --- /dev/null +++ b/erts/emulator/test/erl_drv_thread_SUITE_data/Makefile.src @@ -0,0 +1,33 @@ +# ``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$ +# + +TEST_DRVS = basic@dll@ rwlock@dll@ tsd@dll@ +CC = @CC@ +LD = @LD@ +CFLAGS = @SHLIB_CFLAGS@ -I@erl_include@ @DEFS@ +SHLIB_EXTRA_LDLIBS = testcase_driver@obj@ + +all: $(TEST_DRVS) + +@SHLIB_RULES@ + +testcase_driver@obj@: testcase_driver.c testcase_driver.h +$(TEST_DRVS): testcase_driver@obj@ + + + 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); +} diff --git a/erts/emulator/test/erl_drv_thread_SUITE_data/rwlock.c b/erts/emulator/test/erl_drv_thread_SUITE_data/rwlock.c new file mode 100644 index 0000000000..064f52c16b --- /dev/null +++ b/erts/emulator/test/erl_drv_thread_SUITE_data/rwlock.c @@ -0,0 +1,214 @@ +/* ``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 17 + +struct { + int alive; + ErlDrvTid tid; +} test_thr[NO_OF_THREADS] = {0}; + + +static int die; +static int ready; +static int rlocked; +static int rwlocked; +static int do_rlock; +static int do_rwlock; +static ErlDrvMutex *mtx; +static ErlDrvCond *cnd; +static ErlDrvRWLock *rwlck; + +static void +do_sleep(unsigned secs) +{ +#ifdef __WIN32__ + Sleep((DWORD) secs*1000); +#else + sleep(secs); +#endif +} + +static void *tf(void *unused) +{ + + erl_drv_mutex_lock(mtx); + ready++; + if (ready == NO_OF_THREADS) + erl_drv_cond_broadcast(cnd); + while (!do_rlock) + erl_drv_cond_wait(cnd, mtx); + erl_drv_mutex_unlock(mtx); + + erl_drv_rwlock_rlock(rwlck); + + /* make sure everyone rlocks at the same time */ + erl_drv_mutex_lock(mtx); + rlocked++; + if (rlocked == NO_OF_THREADS) + erl_drv_cond_broadcast(cnd); + while (rlocked != NO_OF_THREADS && !die) + erl_drv_cond_wait(cnd, mtx); + erl_drv_mutex_unlock(mtx); + + erl_drv_rwlock_runlock(rwlck); + + erl_drv_mutex_lock(mtx); + while (!do_rwlock && !die) + erl_drv_cond_wait(cnd, mtx); + if (die) { + erl_drv_mutex_unlock(mtx); + return NULL; + } + erl_drv_mutex_unlock(mtx); + + erl_drv_rwlock_rwlock(rwlck); + rwlocked++; + erl_drv_rwlock_rwunlock(rwlck); + + return NULL; +} + +void +testcase_run(TestCaseState_t *tcs) +{ + int i, r; + 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"); + die = 0; + ready = 0; + rlocked = 0; + rwlocked = 0; + do_rlock = 0; + do_rwlock = 0; + + mtx = erl_drv_mutex_create("test mutex"); + cnd = erl_drv_cond_create("test cond"); + rwlck = erl_drv_rwlock_create("test rwlock"); + ASSERT(tcs, mtx && cnd && rwlck); + + testcase_printf(tcs, "Creating %d threads\n", NO_OF_THREADS); + /* Create the threads */ + for (i = 0; i < NO_OF_THREADS; i++) { + char name[100]; + sprintf(name, "thread %d", i); + r = erl_drv_thread_create(name, + &test_thr[i].tid, + tf, + NULL, + NULL); + ASSERT(tcs, r == 0); + test_thr[i].alive = 1; + } + + testcase_printf(tcs, "Testing\n"); + erl_drv_rwlock_rwlock(rwlck); + + erl_drv_mutex_lock(mtx); + while (ready != NO_OF_THREADS) + erl_drv_cond_wait(cnd, mtx); + do_rlock = 1; + erl_drv_cond_broadcast(cnd); + erl_drv_mutex_unlock(mtx); + + do_sleep(1); + + erl_drv_mutex_lock(mtx); + + ASSERT_CLNUP(tcs, + rlocked == 0, + do { + erl_drv_mutex_unlock(mtx); + erl_drv_rwlock_rwunlock(rwlck); + } while (0)); + + erl_drv_mutex_unlock(mtx); + erl_drv_rwlock_rwunlock(rwlck); + + do_sleep(2); + + erl_drv_mutex_lock(mtx); + ASSERT_CLNUP(tcs, rlocked == NO_OF_THREADS, erl_drv_mutex_unlock(mtx)); + do_rwlock = 1; + erl_drv_cond_broadcast(cnd); + erl_drv_mutex_unlock(mtx); + + testcase_printf(tcs, "Joining threads\n"); + /* Join the threads */ + for (i = 0; i < NO_OF_THREADS; i++) { + void *res; + r = erl_drv_thread_join(test_thr[i].tid, NULL); + test_thr[i].alive = 0; + ASSERT(tcs, r == 0); + } + + erl_drv_mutex_lock(mtx); + ASSERT_CLNUP(tcs, rwlocked == NO_OF_THREADS, erl_drv_mutex_unlock(mtx)); + erl_drv_mutex_unlock(mtx); + + erl_drv_mutex_destroy(mtx); + mtx = NULL; + erl_drv_cond_destroy(cnd); + cnd = NULL; + erl_drv_rwlock_destroy(rwlck); + rwlck = NULL; + + testcase_printf(tcs, "done\n"); +} + +char * +testcase_name(void) +{ + return "rwlock"; +} + +void +testcase_cleanup(TestCaseState_t *tcs) +{ + int i; + for (i = 0; i < NO_OF_THREADS; i++) { + if (test_thr[i].alive) { + erl_drv_mutex_lock(mtx); + die = 1; + erl_drv_cond_broadcast(cnd); + erl_drv_mutex_unlock(mtx); + erl_drv_thread_join(test_thr[i].tid, NULL); + } + } + + if (mtx) + erl_drv_mutex_destroy(mtx); + if (cnd) + erl_drv_cond_destroy(cnd); + if (rwlck) + erl_drv_rwlock_destroy(rwlck); +} diff --git a/erts/emulator/test/erl_drv_thread_SUITE_data/testcase_driver.c b/erts/emulator/test/erl_drv_thread_SUITE_data/testcase_driver.c new file mode 100644 index 0000000000..1e98844838 --- /dev/null +++ b/erts/emulator/test/erl_drv_thread_SUITE_data/testcase_driver.c @@ -0,0 +1,260 @@ +/* ``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" +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <setjmp.h> +#include <string.h> + +#ifdef __WIN32__ +#undef HAVE_VSNPRINTF +#define HAVE_VSNPRINTF 1 +#define vsnprintf _vsnprintf +#endif + +#ifndef HAVE_VSNPRINTF +#define HAVE_VSNPRINTF 0 +#endif + +#define COMMENT_BUF_SZ 4096 + +#define TESTCASE_FAILED 0 +#define TESTCASE_SKIPPED 1 +#define TESTCASE_SUCCEEDED 2 + +typedef struct { + TestCaseState_t visible; + ErlDrvPort port; + int result; + jmp_buf done_jmp_buf; + char *comment; + char comment_buf[COMMENT_BUF_SZ]; +} InternalTestCaseState_t; + +ErlDrvData testcase_drv_start(ErlDrvPort port, char *command); +void testcase_drv_stop(ErlDrvData drv_data); +void testcase_drv_run(ErlDrvData drv_data, char *buf, int len); + +static ErlDrvEntry testcase_drv_entry = { + NULL, + testcase_drv_start, + testcase_drv_stop, + testcase_drv_run +}; + + +DRIVER_INIT(testcase_drv) +{ + testcase_drv_entry.driver_name = testcase_name(); + return &testcase_drv_entry; +} + +ErlDrvData +testcase_drv_start(ErlDrvPort port, char *command) +{ + InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) + driver_alloc(sizeof(InternalTestCaseState_t)); + if (!itcs) { + return ERL_DRV_ERROR_GENERAL; + } + + itcs->visible.testcase_name = testcase_name(); + itcs->visible.extra = NULL; + itcs->port = port; + itcs->result = TESTCASE_FAILED; + itcs->comment = ""; + + return (ErlDrvData) itcs; +} + +void +testcase_drv_stop(ErlDrvData drv_data) +{ + testcase_cleanup((TestCaseState_t *) drv_data); + driver_free((void *) drv_data); +} + +void +testcase_drv_run(ErlDrvData drv_data, char *buf, int len) +{ + InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) drv_data; + ErlDrvTermData result_atom; + ErlDrvTermData msg[12]; + + itcs->visible.command = buf; + itcs->visible.command_len = len; + + if (setjmp(itcs->done_jmp_buf) == 0) { + testcase_run((TestCaseState_t *) itcs); + itcs->result = TESTCASE_SUCCEEDED; + } + + switch (itcs->result) { + case TESTCASE_SUCCEEDED: + result_atom = driver_mk_atom("succeeded"); + break; + case TESTCASE_SKIPPED: + result_atom = driver_mk_atom("skipped"); + break; + case TESTCASE_FAILED: + default: + result_atom = driver_mk_atom("failed"); + break; + } + + msg[0] = ERL_DRV_ATOM; + msg[1] = (ErlDrvTermData) result_atom; + + msg[2] = ERL_DRV_PORT; + msg[3] = driver_mk_port(itcs->port); + + msg[4] = ERL_DRV_ATOM; + msg[5] = driver_mk_atom(itcs->visible.testcase_name); + + msg[6] = ERL_DRV_STRING; + msg[7] = (ErlDrvTermData) itcs->comment; + msg[8] = (ErlDrvTermData) strlen(itcs->comment); + + msg[9] = ERL_DRV_TUPLE; + msg[10] = (ErlDrvTermData) 4; + + driver_output_term(itcs->port, msg, 11); +} + +int +testcase_assertion_failed(TestCaseState_t *tcs, + char *file, int line, char *assertion) +{ + testcase_failed(tcs, "%s:%d: Assertion failed: \"%s\"", + file, line, assertion); + return 0; +} + +void +testcase_printf(TestCaseState_t *tcs, char *frmt, ...) +{ + InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs; + ErlDrvTermData msg[12]; + va_list va; + va_start(va, frmt); +#if HAVE_VSNPRINTF + vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); +#else + vsprintf(itcs->comment_buf, frmt, va); +#endif + va_end(va); + + msg[0] = ERL_DRV_ATOM; + msg[1] = (ErlDrvTermData) driver_mk_atom("print"); + + msg[2] = ERL_DRV_PORT; + msg[3] = driver_mk_port(itcs->port); + + msg[4] = ERL_DRV_ATOM; + msg[5] = driver_mk_atom(itcs->visible.testcase_name); + + msg[6] = ERL_DRV_STRING; + msg[7] = (ErlDrvTermData) itcs->comment_buf; + msg[8] = (ErlDrvTermData) strlen(itcs->comment_buf); + + msg[9] = ERL_DRV_TUPLE; + msg[10] = (ErlDrvTermData) 4; + + driver_output_term(itcs->port, msg, 11); +} + + +void testcase_succeeded(TestCaseState_t *tcs, char *frmt, ...) +{ + InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs; + va_list va; + va_start(va, frmt); +#if HAVE_VSNPRINTF + vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); +#else + vsprintf(itcs->comment_buf, frmt, va); +#endif + va_end(va); + + itcs->result = TESTCASE_SUCCEEDED; + itcs->comment = itcs->comment_buf; + + longjmp(itcs->done_jmp_buf, 1); +} + +void testcase_skipped(TestCaseState_t *tcs, char *frmt, ...) +{ + InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs; + va_list va; + va_start(va, frmt); +#if HAVE_VSNPRINTF + vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); +#else + vsprintf(itcs->comment_buf, frmt, va); +#endif + va_end(va); + + itcs->result = TESTCASE_SKIPPED; + itcs->comment = itcs->comment_buf; + + longjmp(itcs->done_jmp_buf, 1); +} + +void testcase_failed(TestCaseState_t *tcs, char *frmt, ...) +{ + InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs; + char buf[10]; + size_t bufsz = sizeof(buf); + va_list va; + va_start(va, frmt); +#if HAVE_VSNPRINTF + vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); +#else + vsprintf(itcs->comment_buf, frmt, va); +#endif + va_end(va); + + itcs->result = TESTCASE_FAILED; + itcs->comment = itcs->comment_buf; + + if (erl_drv_getenv("ERL_ABORT_ON_FAILURE", buf, &bufsz) == 0 + && strcmp("true", buf) == 0) { + fprintf(stderr, "Testcase \"%s\" failed: %s\n", + itcs->visible.testcase_name, itcs->comment); + abort(); + } + + longjmp(itcs->done_jmp_buf, 1); +} + +void *testcase_alloc(size_t size) +{ + return driver_alloc(size); +} + +void *testcase_realloc(void *ptr, size_t size) +{ + return driver_realloc(ptr, size); +} + +void testcase_free(void *ptr) +{ + driver_free(ptr); +} diff --git a/erts/emulator/test/erl_drv_thread_SUITE_data/testcase_driver.h b/erts/emulator/test/erl_drv_thread_SUITE_data/testcase_driver.h new file mode 100644 index 0000000000..18d5229780 --- /dev/null +++ b/erts/emulator/test/erl_drv_thread_SUITE_data/testcase_driver.h @@ -0,0 +1,58 @@ +/* ``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$ + */ + +#ifndef TESTCASE_DRIVER_H__ +#define TESTCASE_DRIVER_H__ + +#include "erl_driver.h" +#include <stdlib.h> + +typedef struct { + char *testcase_name; + char *command; + int command_len; + void *extra; +} TestCaseState_t; + +#define ASSERT_CLNUP(TCS, B, CLN) \ +do { \ + if (!(B)) { \ + CLN; \ + testcase_assertion_failed((TCS), __FILE__, __LINE__, #B); \ + } \ +} while (0) + +#define ASSERT(TCS, B) ASSERT_CLNUP(TCS, B, (void) 0) + + +void testcase_printf(TestCaseState_t *tcs, char *frmt, ...); +void testcase_succeeded(TestCaseState_t *tcs, char *frmt, ...); +void testcase_skipped(TestCaseState_t *tcs, char *frmt, ...); +void testcase_failed(TestCaseState_t *tcs, char *frmt, ...); +int testcase_assertion_failed(TestCaseState_t *tcs, char *file, int line, + char *assertion); +void *testcase_alloc(size_t size); +void *testcase_realloc(void *ptr, size_t size); +void testcase_free(void *ptr); + + +char *testcase_name(void); +void testcase_run(TestCaseState_t *tcs); +void testcase_cleanup(TestCaseState_t *tcs); + +#endif diff --git a/erts/emulator/test/erl_drv_thread_SUITE_data/tsd.c b/erts/emulator/test/erl_drv_thread_SUITE_data/tsd.c new file mode 100644 index 0000000000..3809c915e0 --- /dev/null +++ b/erts/emulator/test/erl_drv_thread_SUITE_data/tsd.c @@ -0,0 +1,173 @@ +/* ``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" +#include <stdio.h> + +#define NO_OF_THREADS 17 +#define NO_OF_KEYS 4711 + +struct { + int alive; + ErlDrvTid tid; +} test_thr[NO_OF_THREADS] = {0}; + +struct { + int used; + ErlDrvTSDKey key; +} test_key[NO_OF_KEYS] = {0}; + +typedef struct { + int n; +} thr_arg_t; + +static void *tf(void *vta) +{ + int i; + int thr_val = (((thr_arg_t *) vta)->n << 16); + + for (i = 0; i < NO_OF_KEYS; i++) + erl_drv_tsd_set(test_key[i].key, (void *) (thr_val | i)); + + for (i = 0; i < NO_OF_KEYS; i++) + if (erl_drv_tsd_get(test_key[i].key) != ((void *) (thr_val | i))) + return (void *) 1; + + for (i = 0; i < NO_OF_KEYS; i++) + erl_drv_tsd_set(test_key[i].key, NULL); + + for (i = 0; i < NO_OF_KEYS; i++) + if (erl_drv_tsd_get(test_key[i].key) != NULL) + return (void *) 2; + + return (void *) 3; +} + +void +thr_key_clnup(void) +{ + int i; + for (i = 0; i < NO_OF_KEYS; i++) + erl_drv_tsd_set(test_key[i].key, NULL); +} + +void +testcase_run(TestCaseState_t *tcs) +{ + int i, r; + thr_arg_t ta[NO_OF_THREADS]; + ErlDrvSysInfo sinfo; + + testcase_printf(tcs, "Initializing\n"); + + driver_system_info(&sinfo, sizeof(ErlDrvSysInfo)); + + for (i = 0; i < NO_OF_KEYS; i++) { + char name[100]; + sprintf(name, "key %d", i); + r = erl_drv_tsd_key_create(name, &test_key[i].key); + ASSERT(tcs, r == 0); + test_key[i].used = 1; + } + + for (i = 0; i < NO_OF_KEYS; i++) + erl_drv_tsd_set(test_key[i].key, + (void *) (((NO_OF_THREADS+1) << 16) | i)); + + if (!sinfo.thread_support) + testcase_printf(tcs, "No thread support; testing tsd in one thread\n"); + else { + testcase_printf(tcs, "Creating %d threads\n", NO_OF_THREADS); + + /* Create the threads */ + for (i = 0; i < NO_OF_THREADS; i++) { + char name[100]; + ta[i].n = 0; + sprintf(name, "thread %d", i); + r = erl_drv_thread_create(name, + &test_thr[i].tid, + tf, + (void *) &ta[i], + NULL); + ASSERT_CLNUP(tcs, r == 0, thr_key_clnup()); + test_thr[i].alive = 1; + } + } + + testcase_printf(tcs, "Testing tsd\n"); + + for (i = 0; i < NO_OF_KEYS; i++) + ASSERT_CLNUP(tcs, + ((void *) (((NO_OF_THREADS+1) << 16) | i) + == erl_drv_tsd_get(test_key[i].key)), + thr_key_clnup()); + + testcase_printf(tcs, "Joining threads\n"); + + if (sinfo.thread_support) { + /* Join the threads */ + for (i = 0; i < NO_OF_THREADS; i++) { + void *res; + r = erl_drv_thread_join(test_thr[i].tid, &res); + test_thr[i].alive = 0; + ASSERT_CLNUP(tcs, r == 0, thr_key_clnup()); + ASSERT_CLNUP(tcs, res == ((void *) 3), thr_key_clnup()); + } + } + + thr_key_clnup(); + + for (i = 0; i < NO_OF_KEYS; i++) + ASSERT(tcs, NULL == erl_drv_tsd_get(test_key[i].key)); + + testcase_printf(tcs, "Destroying keys\n"); + + for (i = 0; i < NO_OF_KEYS; i++) + if (test_key[i].used) { + test_key[i].used = 0; + erl_drv_tsd_key_destroy(test_key[i].key); + } + + testcase_printf(tcs, "done\n"); + + if (!sinfo.thread_support) + testcase_succeeded(tcs, "No thread support; only one thread tested"); +} + +char * +testcase_name(void) +{ + return "tsd"; +} + +void +testcase_cleanup(TestCaseState_t *tcs) +{ + int i; + for (i = 0; i < NO_OF_THREADS; i++) + if (test_thr[i].alive) { + test_thr[i].alive = 0; + erl_drv_thread_join(test_thr[i].tid, NULL); + } + + for (i = 0; i < NO_OF_KEYS; i++) + if (test_key[i].used) { + test_key[i].used = 0; + erl_drv_tsd_key_destroy(test_key[i].key); + } +} |