diff options
Diffstat (limited to 'erts/emulator/test/alloc_SUITE_data/threads.c')
-rw-r--r-- | erts/emulator/test/alloc_SUITE_data/threads.c | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/erts/emulator/test/alloc_SUITE_data/threads.c b/erts/emulator/test/alloc_SUITE_data/threads.c new file mode 100644 index 0000000000..1247e5d7dd --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/threads.c @@ -0,0 +1,447 @@ +/* ``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 __WIN32__ +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> +#endif +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include "testcase_driver.h" +#include "allocator_test.h" + +#ifdef __WIN32__ +#undef HAVE_VSNPRINTF +#define HAVE_VSNPRINTF 1 +#define vsnprintf _vsnprintf +#endif + +#ifndef HAVE_VSNPRINTF +#define HAVE_VSNPRINTF 0 +#endif + +#define NO_OF_ALLOC_SEQS 6 +#define NO_OF_THREADS (18) +#define NO_OF_BLOCKS 10 +#define NO_OF_OPS_PER_BL 200 +#define SBC_THRESHOLD 8192 + +#define BLOCK_ID(TN, BN) ((TN) << 4 | (BN)) + +#define ERR_BUF_SZ 4096 +static char err_buf[ERR_BUF_SZ]; +static volatile int tc_failed; +static int dead_thread_no; +static erts_mutex tc_mutex; +static erts_cond tc_cond; + +static void exit_thread(int t_no, int do_lock) +{ + if (do_lock) + THR_MTX_LOCK(tc_mutex); + + while (dead_thread_no >= 0) + THR_COND_WAIT(tc_cond, tc_mutex); + dead_thread_no = t_no; + + THR_COND_BCAST(tc_cond); + THR_MTX_UNLOCK(tc_mutex); + THR_EXIT(NULL); +} + +static void fail(int t_no, char *frmt, ...) +{ + char buf[10]; + size_t bufsz = sizeof(buf); + va_list va; + + THR_MTX_LOCK(tc_mutex); + + va_start(va, frmt); +#if HAVE_VSNPRINTF + vsnprintf(err_buf, ERR_BUF_SZ, frmt, va); +#else + vsprintf(err_buf, frmt, va); +#endif + va_end(va); + + tc_failed = 1; + + if (erl_drv_getenv("ERL_ABORT_ON_FAILURE", buf, &bufsz) == 0 + && strcmp("true", buf) == 0) { + fprintf(stderr, "Testcase \"%s\" failed: %s\n", + testcase_name(), err_buf); + abort(); + } + + exit_thread(t_no, 0); +} + +static Allctr_t *alloc_not_ts = NULL; +static Allctr_t *alloc_ts_1 = NULL; +static Allctr_t *alloc_ts_2 = NULL; + +static void stop_allocators(void) +{ + if (alloc_not_ts) { + STOP_ALC(alloc_not_ts); + alloc_not_ts = NULL; + } + if (alloc_ts_1) { + STOP_ALC(alloc_ts_1); + alloc_ts_1 = NULL; + } + if (alloc_ts_2) { + STOP_ALC(alloc_ts_2); + alloc_ts_2 = NULL; + } +} + + +void *thread_func(void *arg); + +typedef struct { + Allctr_t *a; + int t_no; + int no_ops_per_bl; +} ThreadData; + + +char * +testcase_name(void) +{ + return "threads"; +} + +void +testcase_cleanup(TestCaseState_t *tcs) +{ + stop_allocators(); +} + +void +testcase_run(TestCaseState_t *tcs) +{ + struct { + erts_thread tid; + ThreadData arg; + } threads[NO_OF_THREADS+1] = {{0}}; + int no_threads; + int i; + char sbct_buf[10]; + char *argv_org[] = {"-tasaobf", "-tmmsbc5000", "-tmmmbc5000", "-tsbct", + &sbct_buf[0], NULL}; + char *argv[sizeof(argv_org)/sizeof(argv_org[0])]; + + if (!IS_THREADS_ENABLED) + testcase_skipped(tcs, "Threads not enabled"); + + alloc_not_ts = NULL; + alloc_ts_1 = NULL; + alloc_ts_2 = NULL; + + err_buf[0] = '\0'; + + sprintf(sbct_buf, "%d", SBC_THRESHOLD/1024); + + memcpy((void *) argv, argv_org, sizeof(argv_org)); + alloc_not_ts = START_ALC("threads_not_ts", 0, argv); + ASSERT(tcs, alloc_not_ts); + memcpy((void *) argv, argv_org, sizeof(argv_org)); + alloc_ts_1 = START_ALC("threads_ts_1", 1, argv); + ASSERT(tcs, alloc_ts_1); + memcpy((void *) argv, argv_org, sizeof(argv_org)); + alloc_ts_2 = START_ALC("threads_ts_2", 1, argv); + ASSERT(tcs, alloc_ts_2); + + ASSERT(tcs, !IS_ALLOC_THREAD_SAFE(alloc_not_ts)); + ASSERT(tcs, IS_ALLOC_THREAD_SAFE(alloc_ts_1)); + ASSERT(tcs, IS_ALLOC_THREAD_SAFE(alloc_ts_2)); + + tc_mutex = THR_MTX_CREATE(); + tc_cond = THR_COND_CREATE(); + + THR_MTX_LOCK(tc_mutex); + + dead_thread_no = -1; + no_threads = 0; + + for(i = 1; i <= NO_OF_THREADS; i++) { + char *alc; + int res; + + threads[i].arg.no_ops_per_bl = NO_OF_OPS_PER_BL; + + if (i == 1) { + alc = "threads_not_ts"; + threads[i].arg.no_ops_per_bl *= 2; + threads[i].arg.a = alloc_not_ts; + } + else if (i % 2 == 0) { + alc = "threads_ts_1"; + threads[i].arg.a = alloc_ts_1; + } + else { + alc = "threads_ts_2"; + threads[i].arg.a = alloc_ts_2; + } + threads[i].arg.t_no = i; + + threads[i].tid = THR_CREATE(thread_func, (void *) &threads[i].arg); + if (threads[i].tid) { + testcase_printf(tcs, "Successfully created thread %d " + "using %s_alloc\n", i, alc); + no_threads++; + } + else { + tc_failed = 1; + sprintf(err_buf, "Failed to create thread %d\n", i); + break; + } + + } + + while (no_threads) { + THR_COND_WAIT(tc_cond, tc_mutex); + if (dead_thread_no >= 0) { + no_threads--; + THR_JOIN(threads[dead_thread_no].tid); + testcase_printf(tcs, "Thread %d died\n", dead_thread_no); + dead_thread_no = -1; + THR_COND_BCAST(tc_cond); + } + } + + THR_MTX_UNLOCK(tc_mutex); + THR_MTX_DESTROY(tc_mutex); + THR_COND_DESTROY(tc_cond); + + stop_allocators(); + + if (tc_failed) + testcase_failed(tcs, "%s", err_buf); +} + +Ulong alloc_seq_1[] = { + 17, + SBC_THRESHOLD*2, + SBC_THRESHOLD*20, + SBC_THRESHOLD*2, + 17, + 0 +}; + +Ulong alloc_seq_2[] = { + SBC_THRESHOLD*20, + SBC_THRESHOLD*2, + 17, + SBC_THRESHOLD*2, + SBC_THRESHOLD*20, + 0 +}; + +Ulong alloc_seq_3[] = { + 1, + SBC_THRESHOLD/10, + SBC_THRESHOLD/9, + SBC_THRESHOLD/8, + SBC_THRESHOLD/7, + SBC_THRESHOLD/6, + SBC_THRESHOLD/5, + SBC_THRESHOLD/4, + SBC_THRESHOLD/3, + SBC_THRESHOLD/2, + SBC_THRESHOLD/1, + SBC_THRESHOLD*1, + SBC_THRESHOLD*2, + SBC_THRESHOLD*3, + SBC_THRESHOLD*4, + SBC_THRESHOLD*5, + SBC_THRESHOLD*6, + SBC_THRESHOLD*7, + SBC_THRESHOLD*8, + SBC_THRESHOLD*9, + SBC_THRESHOLD*10, + SBC_THRESHOLD*9, + SBC_THRESHOLD*8, + SBC_THRESHOLD*7, + SBC_THRESHOLD*6, + SBC_THRESHOLD*5, + SBC_THRESHOLD*4, + SBC_THRESHOLD*3, + SBC_THRESHOLD*2, + SBC_THRESHOLD*1, + SBC_THRESHOLD/2, + SBC_THRESHOLD/3, + SBC_THRESHOLD/4, + SBC_THRESHOLD/5, + SBC_THRESHOLD/6, + SBC_THRESHOLD/7, + SBC_THRESHOLD/8, + SBC_THRESHOLD/9, + SBC_THRESHOLD/10, + 1, + 0 +}; + +Ulong alloc_seq_4[] = { + SBC_THRESHOLD*2, + SBC_THRESHOLD*3, + SBC_THRESHOLD*7, + SBC_THRESHOLD*8, + SBC_THRESHOLD*5, + SBC_THRESHOLD*6, + SBC_THRESHOLD*1, + SBC_THRESHOLD*10, + SBC_THRESHOLD*4, + SBC_THRESHOLD*2, + 0 +}; + +Ulong alloc_seq_5[] = { + SBC_THRESHOLD/2, + SBC_THRESHOLD/3, + SBC_THRESHOLD/7, + SBC_THRESHOLD/8, + SBC_THRESHOLD/5, + SBC_THRESHOLD/6, + SBC_THRESHOLD/1, + SBC_THRESHOLD/10, + SBC_THRESHOLD/4, + SBC_THRESHOLD/2, + SBC_THRESHOLD/3, + SBC_THRESHOLD/7, + SBC_THRESHOLD/8, + SBC_THRESHOLD/5, + SBC_THRESHOLD/6, + SBC_THRESHOLD/1, + SBC_THRESHOLD/10, + SBC_THRESHOLD/4, + SBC_THRESHOLD/2, + 0 +}; + +Ulong alloc_seq_6[] = { + 1, 50, 100, 50, 23, 46, 2345, 23, 54, 2, 0 +}; + +Ulong *alloc_seqs[NO_OF_ALLOC_SEQS] = { + alloc_seq_1, + alloc_seq_2, + alloc_seq_3, + alloc_seq_4, + alloc_seq_5, + alloc_seq_6 +}; + +typedef struct { + unsigned char *p; + Ulong s; + int i; + Ulong *as; +} block; + +#define CHECK_BLOCK_DATA(T, P, S, D) \ + check_block_data(__FILE__, __LINE__, (T), (P), (S), (D)) + +static void +check_block_data(char *file, int line, int t_no, + unsigned char *p, Ulong sz, int d) +{ + Ulong i; + for (i = 0; i < sz; i++) + if (p[i] != (unsigned char) d) + fail(t_no, "%s:%d: Thread no %d found clobbered data! " + "found id=%d; expected id=%d\n", + file, line, t_no, (int) p[i], d); +} + +static void +alloc_op(int t_no, Allctr_t *a, block *bp, int id, int clean_up) +{ + if (tc_failed) + exit_thread(t_no, 1); + + if(bp->p) + CHECK_BLOCK_DATA(t_no, bp->p, bp->s, id); + + if(bp->as[bp->i] == 0 || clean_up) { + FREE(a, bp->p); + bp->p = NULL; + bp->s = 0; + bp->i = 0; /* start from the beginning again */ + return; + } + + if(!bp->p) { + bp->s = bp->as[bp->i]; + bp->p = (unsigned char *) ALLOC(a, bp->s); + if(!bp->p) + fail(t_no, "ALLOC(%lu) failed [id=%d])\n", bp->s, id); + memset((void *) bp->p, id, (size_t) bp->s); + } + else { + unsigned char *p = (unsigned char *) REALLOC(a, bp->p, bp->as[bp->i]); + if(!p) + fail(t_no, "REALLOC(0x%lx, %lu) failed [id=%d]\n", + (Ulong) bp->p, bp->as[bp->i], id); + + if(bp->s < bp->as[bp->i]) { + CHECK_BLOCK_DATA(t_no, p, bp->s, id); + memset((void *) p, id, (size_t) bp->as[bp->i]); + } + else + CHECK_BLOCK_DATA(t_no, p, bp->as[bp->i], id); + + bp->s = bp->as[bp->i]; + bp->p = p; + } + + bp->i++; +} + + +void * +thread_func(void *arg) +{ + int i, j; + ThreadData *td = ((ThreadData *) arg); + block bs[NO_OF_BLOCKS]; + + for(i = 0; i < NO_OF_BLOCKS; i++) { + bs[i].p = NULL; + bs[i].s = 0; + bs[i].i = 0; + bs[i].as = alloc_seqs[i % NO_OF_ALLOC_SEQS]; + } + + for(i = 0; i < td->no_ops_per_bl; i++) { + + for(j = 0; j < NO_OF_BLOCKS; j++) + alloc_op(td->t_no, td->a, &bs[j], BLOCK_ID(td->t_no, j), 0); + } + + for(j = 0; j < NO_OF_BLOCKS; j++) + alloc_op(td->t_no, td->a, &bs[j], BLOCK_ID(td->t_no, j), 1); + + exit_thread(td->t_no, 1); + return NULL; +} |