mirror of
https://github.com/libffi/libffi.git
synced 2026-01-26 10:07:53 +00:00
feat(testsuite): add new threading tests to libffi test suite
This commit is contained in:
parent
074c423f86
commit
a5d465029c
163
testsuite/libffi.threads/ffitest.h
Normal file
163
testsuite/libffi.threads/ffitest.h
Normal file
@ -0,0 +1,163 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <ffi.h>
|
||||
#include "fficonfig.h"
|
||||
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
|
||||
#if defined HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#if defined HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#define MAX_ARGS 256
|
||||
|
||||
#define CHECK(x) \
|
||||
do { \
|
||||
if(!(x)){ \
|
||||
printf("Check failed:\n%s\n", #x); \
|
||||
abort(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define CHECK_FLOAT_EQ(x, y) \
|
||||
do { \
|
||||
if(fabs((x) - (y)) > FLT_EPSILON){ \
|
||||
printf("Check failed CHECK_FLOAT_EQ(%s, %s)\n", #x, #y); \
|
||||
abort(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define CHECK_DOUBLE_EQ(x, y) \
|
||||
do { \
|
||||
if(fabs((x) - (y)) > DBL_EPSILON){ \
|
||||
printf("Check failed CHECK_FLOAT_EQ(%s, %s)\n", #x, #y); \
|
||||
abort(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/* Define macros so that compilers other than gcc can run the tests. */
|
||||
#undef __UNUSED__
|
||||
#if defined(__GNUC__)
|
||||
#define __UNUSED__ __attribute__((__unused__))
|
||||
#define __STDCALL__ __attribute__((stdcall))
|
||||
#define __THISCALL__ __attribute__((thiscall))
|
||||
#define __FASTCALL__ __attribute__((fastcall))
|
||||
#define __MSABI__ __attribute__((ms_abi))
|
||||
#else
|
||||
#define __UNUSED__
|
||||
#define __STDCALL__ __stdcall
|
||||
#define __THISCALL__ __thiscall
|
||||
#define __FASTCALL__ __fastcall
|
||||
#endif
|
||||
|
||||
#ifndef ABI_NUM
|
||||
#define ABI_NUM FFI_DEFAULT_ABI
|
||||
#define ABI_ATTR
|
||||
#endif
|
||||
|
||||
/* Prefer MAP_ANON(YMOUS) to /dev/zero, since we don't need to keep a
|
||||
file open. */
|
||||
#ifdef HAVE_MMAP_ANON
|
||||
# undef HAVE_MMAP_DEV_ZERO
|
||||
|
||||
# include <sys/mman.h>
|
||||
# ifndef MAP_FAILED
|
||||
# define MAP_FAILED -1
|
||||
# endif
|
||||
# if !defined (MAP_ANONYMOUS) && defined (MAP_ANON)
|
||||
# define MAP_ANONYMOUS MAP_ANON
|
||||
# endif
|
||||
# define USING_MMAP
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MMAP_DEV_ZERO
|
||||
|
||||
# include <sys/mman.h>
|
||||
# ifndef MAP_FAILED
|
||||
# define MAP_FAILED -1
|
||||
# endif
|
||||
# define USING_MMAP
|
||||
|
||||
#endif
|
||||
|
||||
/* msvc kludge. */
|
||||
#if defined(_MSC_VER)
|
||||
#define PRIdLL "I64d"
|
||||
#define PRIuLL "I64u"
|
||||
#else
|
||||
#define PRIdLL "lld"
|
||||
#define PRIuLL "llu"
|
||||
#endif
|
||||
|
||||
/* Tru64 UNIX kludge. */
|
||||
#if defined(__alpha__) && defined(__osf__)
|
||||
/* Tru64 UNIX V4.0 doesn't support %lld/%lld, but long is 64-bit. */
|
||||
#undef PRIdLL
|
||||
#define PRIdLL "ld"
|
||||
#undef PRIuLL
|
||||
#define PRIuLL "lu"
|
||||
#define PRId8 "hd"
|
||||
#define PRIu8 "hu"
|
||||
#define PRId64 "ld"
|
||||
#define PRIu64 "lu"
|
||||
#define PRIuPTR "lu"
|
||||
#endif
|
||||
|
||||
/* PA HP-UX kludge. */
|
||||
#if defined(__hppa__) && defined(__hpux__) && !defined(PRIuPTR)
|
||||
#define PRIuPTR "lu"
|
||||
#endif
|
||||
|
||||
/* IRIX kludge. */
|
||||
#if defined(__sgi)
|
||||
/* IRIX 6.5 <inttypes.h> provides all definitions, but only for C99
|
||||
compilations. */
|
||||
#define PRId8 "hhd"
|
||||
#define PRIu8 "hhu"
|
||||
#if (_MIPS_SZLONG == 32)
|
||||
#define PRId64 "lld"
|
||||
#define PRIu64 "llu"
|
||||
#endif
|
||||
/* This doesn't match <inttypes.h>, which always has "lld" here, but the
|
||||
arguments are uint64_t, int64_t, which are unsigned long, long for
|
||||
64-bit in <sgidefs.h>. */
|
||||
#if (_MIPS_SZLONG == 64)
|
||||
#define PRId64 "ld"
|
||||
#define PRIu64 "lu"
|
||||
#endif
|
||||
/* This doesn't match <inttypes.h>, which has "u" here, but the arguments
|
||||
are uintptr_t, which is always unsigned long. */
|
||||
#define PRIuPTR "lu"
|
||||
#endif
|
||||
|
||||
/* Solaris < 10 kludge. */
|
||||
#if defined(__sun__) && defined(__svr4__) && !defined(PRIuPTR)
|
||||
#if defined(__arch64__) || defined (__x86_64__)
|
||||
#define PRIuPTR "lu"
|
||||
#else
|
||||
#define PRIuPTR "u"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* MSVC kludge. */
|
||||
#if defined _MSC_VER
|
||||
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)
|
||||
#define PRIuPTR "lu"
|
||||
#define PRIu8 "u"
|
||||
#define PRId8 "d"
|
||||
#define PRIu64 "I64u"
|
||||
#define PRId64 "I64d"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef PRIuPTR
|
||||
#define PRIuPTR "u"
|
||||
#endif
|
||||
54
testsuite/libffi.threads/threads.exp
Normal file
54
testsuite/libffi.threads/threads.exp
Normal file
@ -0,0 +1,54 @@
|
||||
# Copyright (C) 2003, 2006, 2009, 2010, 2014 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; see the file COPYING3. If not see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
dg-init
|
||||
libffi-init
|
||||
|
||||
global srcdir subdir
|
||||
|
||||
if { [string match $compiler_vendor "microsoft"] } {
|
||||
# -wd4005 macro redefinition
|
||||
# -wd4244 implicit conversion to type of smaller size
|
||||
# -wd4305 truncation to smaller type
|
||||
# -wd4477 printf %lu of uintptr_t
|
||||
# -wd4312 implicit conversion to type of greater size
|
||||
# -wd4311 pointer truncation to unsigned long
|
||||
# -EHsc C++ Exception Handling (no SEH exceptions)
|
||||
set additional_options "-wd4005 -wd4244 -wd4305 -wd4477 -wd4312 -wd4311 -EHsc";
|
||||
} else {
|
||||
set additional_options "";
|
||||
}
|
||||
|
||||
set tlist [lsort [glob -nocomplain -- $srcdir/$subdir/*.c]]
|
||||
|
||||
run-many-tests $tlist $additional_options
|
||||
|
||||
set tlist [lsort [glob -nocomplain -- $srcdir/$subdir/*.cc]]
|
||||
|
||||
# No C++ for or1k
|
||||
if { [istarget "or1k-*-*"] } {
|
||||
foreach test $tlist {
|
||||
unsupported "$test"
|
||||
}
|
||||
} else {
|
||||
run-many-tests $tlist $additional_options
|
||||
}
|
||||
|
||||
dg-finish
|
||||
|
||||
# Local Variables:
|
||||
# tcl-indent-level:4
|
||||
# End:
|
||||
66
testsuite/libffi.threads/tsan.c
Normal file
66
testsuite/libffi.threads/tsan.c
Normal file
@ -0,0 +1,66 @@
|
||||
/* { dg-do run } */
|
||||
|
||||
#include "ffitest.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define NUM_THREADS 20
|
||||
|
||||
pthread_barrier_t barrier;
|
||||
|
||||
typedef float (*callback_fn)(float, float);
|
||||
|
||||
void callback(ffi_cif *cif __UNUSED__, void *ret, void **args, void *userdata __UNUSED__) {
|
||||
float a = *(float *)args[0];
|
||||
float b = *(float *)args[1];
|
||||
*(float *)ret = a / 2 + b / 2;
|
||||
}
|
||||
|
||||
void *thread_func(void *arg) {
|
||||
pthread_barrier_wait(&barrier);
|
||||
|
||||
ffi_cif cif;
|
||||
ffi_type *args[2] = { &ffi_type_float, &ffi_type_float };
|
||||
|
||||
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_float, args) != FFI_OK) {
|
||||
fprintf(stderr, "ffi_prep_cif failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ffi_closure *closure = ffi_closure_alloc(sizeof(ffi_closure), (void **)&arg);
|
||||
|
||||
if (ffi_prep_closure_loc(closure, &cif, callback, NULL, arg) != FFI_OK) {
|
||||
fprintf(stderr, "ffi_prep_closure_loc failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
callback_fn fn = (callback_fn)arg;
|
||||
(void) fn(4.0f, 6.0f);
|
||||
|
||||
ffi_closure_free(closure);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main() {
|
||||
pthread_t threads[NUM_THREADS];
|
||||
|
||||
pthread_barrier_init(&barrier, NULL, NUM_THREADS);
|
||||
|
||||
for (int i = 0; i < NUM_THREADS; ++i) {
|
||||
if (pthread_create(&threads[i], NULL, thread_func, NULL) != 0) {
|
||||
perror("pthread_create");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUM_THREADS; ++i) {
|
||||
pthread_join(threads[i], NULL);
|
||||
}
|
||||
|
||||
pthread_barrier_destroy(&barrier);
|
||||
|
||||
printf("Completed\n");
|
||||
return 0;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user